2012-02-28 121 views
1

我一直在为星期四的考试做一些SQL,并且怀疑我是否正确使用了EXISTS语句。这是使用EXISTS的正确方法吗?

所以,在这里我有2个表

Machines    Maintenance 
    ============   ============== 
PK ID_Machine   PK ID_Machine FK 
    Name    PK ID_Task  FK 
    Date_bought    Date 

这样一个数据库,他们要我写查询说“显示所有这一切并没有收到任何维护在2011年的最古老的机器数据”

我做了如下的方式:

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT MA.* 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)     
AND EXISTS (SELECT MIN(M2.DATE_BOUGHT) 
       FROM MACHINE M2 
       WHERE M2.ID_MACHINE = M.ID_MACHINE) 

这是做这个查询的正确道路?在EXISTS语句中使用SELECT MIN()是否有意义?

在此先感谢大家!

+0

嗯....当您尝试运行该查询会发生什么? – 2012-02-28 01:55:20

+0

那么,问题是我实际上没有在任何DBMS中创建此DB。这只是教科书中的练习,我正在用一张纸来解决它。不幸的是,教科书没有答案,所以这就是为什么我问:) – nachoargentina 2012-02-28 02:00:30

+0

一开始,你需要一个'AND' *而不是*第二个'WHERE'。另外,绝对不要在'EXISTS'中使用'SELECT MIN()' - 这是没有意义的。 – Bohemian 2012-02-28 02:17:53

回答

2

当您使用exists时,它仅验证过滤器(连接和位置)返回的一段数据。通常情况下,您会看到存在查询,其中select 1来自....这是因为实际返回值未被使用。

这是一个新颖的想法,我必须亲自测试一下。但是,正如我上面所述,大部分回报数据都被忽略。它只关心连接和过滤器匹配的位置,并不关心MIN,即使它看起来本身就是一个过滤器。它更像是一个聚合,所以底层数据看起来依然存在。第一个存在是有效的,但下一个部分确实需要工作。我已经更新了下面的内容,我会做什么。

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT 1 
       FROM MAINTENANCE MA 
       WHERE MA.ID_MACHINE = M.ID_MACHINE 
       AND YEAR(MA.DATE) = 2011)     
    AND M.ID_MACHINE = (SELECT TOP 1 M2.ID_MACHINE 
      FROM MACHINE M2 
      WHERE M2.ID_MACHINE = M.ID_MACHINE 
      ORDER BY M2.DATE_BOUGHT) 
+0

正确,那么在我的情况下,与EXISTS条件我试图选择最古老的机器......这就是为什么我在子查询的SELECT语句中包含一个MIN()。我认为通过这样做,EXISTS语句将会消除所有其他机器,但其中有MIN(Date_bought)的机器。是这样吗?还是我以错误的方式解决这个问题? – nachoargentina 2012-02-28 02:18:47

+0

更新我的回复,但简短的回答是,你确实是在错误地解决这个问题。这是一个新颖的主意,虽然:) – 2012-02-28 02:23:27

+0

对不起,忽略我的最后一条评论,我没有阅读你的评论,直到最后,只是第一段。那么,你认为它可能以这种方式工作?我认为是这样,因为正如你所说,MIN()在理论上将作为一个过滤器。只要有机会,我会尝试在实际的数据库中进行测试。 – nachoargentina 2012-02-28 02:24:35

0

我认为这将是一个更好的方法去解决它。

SELECT TOP 1 MIN(A.Date_bought), A.ID_Machine, A.Name 
FROM Machines A 
JOIN Maintenance B on A.ID_Machine = B.ID_Machine 
WHERE DATEPART(year, B.Date) != '2011' 
GROUP BY A.Date_bought, A.ID_Machine, A.Name 
+0

-1:OP询问他/她的查询是否有效,而不是重写它。 – 2012-02-28 02:06:43

+1

我认为这会失败,因为'MIN'是聚集的,你没有'GROUP BY' – Yuval 2012-02-28 02:07:14

+0

谢谢你,错过了GROUP BY :)另外,对于杰克,他还问是否是正确的方式来做到这一点,我不知道我不认为这是事实,所以我提供了另一种解决方案。当我在这里只有8位代表时,无需投票。天啊。大声笑 – stringpoet 2012-02-28 02:08:40

1

引述SQL-92 standard

8.8

 Function 

    Specify a test for a non-empty set. 

    Format 

    <exists predicate> ::= EXISTS <table subquery> 


    Syntax Rules 

     None. 

    Access Rules 


     None. 

    General Rules 

    1) Let T be the result of the <table subquery>. 

    2) If the cardinality of T is greater than 0, then the result of 
     the <exists predicate> is true; otherwise, the result of the 
     <exists predicate> is false. 

    Leveling Rules 

    1) The following restrictions apply for Intermediate SQL: 

      None. 

    2) The following restrictions apply for Entry SQL in addition to 
     any Intermediate SQL restrictions: 

      None. 

所以,不,也有在子查询(只知道它是有效的)的语法,并没有硬性规定。 exists声明仅仅关心它是否返回任何行。

+0

好吧,在这种情况下,EXISTS语句将返回M2表中的一个特定行的真。由于该表对我的查询中的主表有一个外部引用,这是否意味着通过这样做,它将排除我的主表中的所有行,但具有MIN(Date_bought)值的行除外?因为这基本上是我瞄准 – nachoargentina 2012-02-28 02:09:46

+0

不是,它不会从任何表中删除任何行。它既不是'delete'也不是'truncate'语句。 – 2012-02-28 02:49:28

1

思考的EXISTSNOT EXISTS你可以钉到您查询的WHERE子句的布尔条件。它们用于检查其他数据条件是否与您正在查看的数据相关。

SELECT M.ID_MACHINE, M.NAME, M.DATE_BOUGHT 
FROM MACHINES M 

-- DO NOT want a machine with a maintenance year of 2011 
WHERE NOT EXISTS (SELECT 1 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)  

-- DO want there to be a matching ID in the Machine table    
WHERE EXISTS (SELECT 1 
       FROM MACHINE M2 
       WHERE M2.ID_MACHINE = M.ID_MACHINE) 

贾斯汀提到的,子查询的返回值都没有用,所以SELECT 1EXISTS/NOT EXISTS的惯例。

+0

但是,正如我刚刚编辑我的文章,MIN类型的行为本身就像一个过滤器......所以我不知道是否有MIN会工作或不......。从来没有尝试过,理论上它可以工作。我更新了我对此的回应。我可能会加载一些虚拟数据来看:) – 2012-02-28 02:19:48

+0

测试它,它失败。我正在重新更新我的答案:) – 2012-02-28 02:22:17

+0

@JustinPihony好的,tx用于为我测试!很高兴知道那是不正确的。我喜欢它的男人。 – nachoargentina 2012-02-28 02:27:08

1

您的第一次使用EXISTS似乎是正确的,但第二个似乎是关闭。您想检查机器是否最旧,但是您要检查机器是否存在相同的MACHINE_ID(使用MINEXISTS函数的结果没有影响)。

我不是数据库管理员,但考虑到子查询在某些实现中可能代价很高,而在其他实现中,它们可能会在放入EXISTS函数时进行优化。所以当你真的需要代码运行时,应该考虑stringpoet的代码......虽然我说你需要GROUP BY所有其他字段。

另请注意,您不应使用关键字WHERE两次,但请将您的条件加入AND/OR

这里是我的修正,你和stringpoet代码:

SELECT M.ID_MACHINE, M.NAME, MIN(M.DATE_BOUGHT) 
FROM MACHINES M 
WHERE NOT EXISTS (SELECT MA.* 
        FROM MAINTENANCE MA 
        WHERE MA.ID_MACHINE = M.ID_MACHINE 
        AND YEAR(MA.DATE) = 2011)     
GROUP BY M.ID_MACHINE, M.NAME 
+0

好的,太棒了,这让事情变得更加清晰! tx Yuval,我将使用你的代码,而不是用EXIST的代码作为我的答案 – nachoargentina 2012-02-28 02:37:23

相关问题