为什么这两个带有“ EXISTS”的查询的行为会有所不同?

时间:2019-05-07 06:03:18

标签: sql sql-server tsql sql-server-2012 exists

有两个表。 Customers,其中custid作为PK,Orders,其中custid作为FK。

Customers表具有列custidcompanyname

Orders表具有列custidorderidorderdate

我想退回在2007年而不是'2008'年订购的客户。我要在最终结果中返回custidcompanyname

我有query1,它通过总共7个不同的custid获取正确的结果 我有query2,可以让我获得更多不同的行,即最终结果中有86行

query1

SELECT custid, companyname
FROM customers c
WHER EXISTS
 (SELECT custid
  FROM orders o
  WHERE YEAR(orderdate) = '2007'AND o.custid = c.custid)
AND NOT EXISTS
 (SELECT custid
  FROM orders o
  WHERE YEAR(orderdate) = '2008'AND o.custid=c.custid)

query2

SELECT DISTINCT custid, companyname
FROM customers c
WHERE EXISTS
 (SELECT custid
  FROM orders o
  WHERE YEAR(orderdate) = '2007'
        AND YEAR(orderdate) <> '2008'
        AND o.custid=c.custid)

我不了解query2的问题以及为什么它无法给出正确的结果?

4 个答案:

答案 0 :(得分:2)

正确的查询是第一个

如user2722968所述,使用: WHERE YEAR(orderdate) = '2007' AND YEAR(orderdate) <> '2008' 每行工作。因此,如果一个监护人在2007年和2008年都同时拥有一个orderid, 前面提到的WHERE确实会返回2007行,就像确实有YEAR(orderdate) = '2007' AND YEAR(orderdate) <> '2008'一样。

相反,(NOT) EXISTS中的不同代码不是对行而是对结果集执行操作(semijoi)。这就是您所需要的。

一个建议:如果可以避免使用函数,这是一个很好的性能习惯,因为当您将函数应用于字段时,如果有一个索引,则不能使用它来加快计算速度。因此,最好使用YEAR(orderdate)= 2007,而不是:

orderdate>='20070101' and orderdate<'20080101'

考虑到这一点,查询变为:

SELECT custid, companyname
FROM customers c
WHERE EXISTS
 (SELECT custid
  FROM orders o
  WHERE orderdate>='20070101' and orderdate<'20080101' AND o.custid = c.custid)
AND NOT EXISTS
 (SELECT custid
  FROM orders o
  WHERE orderdate>='20080101' and orderdate<'20090101' AND o.custid=c.custid)

答案 1 :(得分:1)

  

这两个带有“ EXISTS”的查询为什么表现不同?

因为:

  • 如果在2007年有订单,而在2008年没有(不同)订单,则第一个查询将返回客户。
  • 但是第二个查询将返回一个客户,如果该客户在2007年有订单,但同一订单不在2008年(并且由于该订单已经在2007年,那么它不在2008年,因此条件{{1} }是多余的。

看起来第一个查询更有意义。

答案 2 :(得分:1)

好吧,让我们有一个拥有一个客户(客户1)的customers表和下面的orders

custid   orderid  orderdate
---------------------------
  1         1       1.1.2007
  1         2       1.1.2008       

您的第二个查询为客户解释子查询

SELECT custid
FROM orders o
WHERE YEAR(orderdate) = 2007 AND YEAR(orderdate) <> 2008 AND o.custid = 1

,它返回第一行。因此,exists对于客户的评估为true,因为存在一行带有year(orderdate) = 2007 and year(orderdate) <> 2008的行(第一行)。但是,这并不意味着与2008年不存在不同的行!

很显然,第一个查询不返回任何结果,因为客户1不满足not exists谓词。如果我们用关系代数表达第一个查询,那么它对应于两个集合之间的差,但是,第二个查询只是带有条件的普通联接。

答案 3 :(得分:1)

有一种更简单的方法可以使用EXCEPT

解决此问题
select c.custid, c.companyname
from Customers c
join
Orders o
on o.custid=c.custid
where orderdate>='20070101' and orderdate<'20080101'
except
select c.custid, c.companyname
from [TSQL2012].Sales.Customers c
join
[TSQL2012].Sales.Orders o
on o.custid=c.custid
where orderdate>='20080101' and orderdate<'20090101'