这是使用EXISTS的正确方法吗?

时间:2012-02-28 01:53:40

标签: sql exists min

我已经为我周四的考试做了一些SQL,如果我正确使用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()是否有意义?

先感谢大家!

5 个答案:

答案 0 :(得分:2)

当您使用exists时,它仅验证为过滤器返回的数据(连接和位置)。通常,您将看到来自....的选择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)

答案 1 :(得分: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语句只关心它是否返回任何行。

答案 2 :(得分: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)

正如Justin所提到的,不使用子查询的返回值,因此SELECT 1EXISTS/NOT EXISTS的约定。

答案 3 :(得分: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

答案 4 :(得分: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