我已经为我周四的考试做了一些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()是否有意义?
先感谢大家!
答案 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)
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)
将EXISTS
和NOT 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 1
是EXISTS/NOT EXISTS
的约定。
答案 3 :(得分:1)
您第一次使用EXISTS
似乎是正确的,但第二次似乎是关闭的。您想要检查机器是否最旧,但是您要检查机器是否存在相同的MACHINE_ID
(使用MIN
对EXISTS
的结果没有影响功能)。
我不是数据库管理员,但考虑到子查询在某些实现中可能代价高昂,而在其他实现中,可能会在置于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