为什么这两个 'EXISTS' 的查询表现不同?

Why do these two queries with 'EXISTS' behave differently?

有两个table。 Customerscustid 作为主键,Orderscustid 作为主键。

Customers table 有列 custidcompanyname

Orders table 有列 custidorderidorderdate

我想 return 在 2007 年而不是在“2008 年”下订单的客户。我想returncustidcompanyname在最后的结果。

我有 query1 总共有 7 个不同的 custid 来获取正确的结果 我有 query2,它给了我更多不同的行,即最终结果中的 86 行

查询1

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)

查询2

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 的问题以及为什么它不能给出正确的结果?

正确的查询是第一个

如 user2722968 所述,使用: WHERE YEAR(orderdate) = '2007' AND YEAR(orderdate) <> '2008' 作品 per-row。所以,如果一个 custid 在 2007 年和 2008 年都有一个 orderid, 前面提到的 WHERE 确实 return 2007 行,因为它确实 YEAR(orderdate) = '2007' AND YEAR(orderdate) <> '2008'.

相反,(NOT) EXISTS 中的不同代码不是对行执行操作 (semijoi),而是对 result-sets。这就是你需要的。

一个建议:如果可以避免的话,最好不要使用函数,因为当你对一个字段应用函数时,如果它上面有索引,它就不能用来加速计算。因此,最好使用:

而不是 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)

Why do these two queries with 'EXISTS' behave differently?

因为:

  • 如果客户在 2007 年有订单并且在 2008 年没有(不同的)订单,则第一个查询将 return 客户。
  • 但是第二个查询将 return 一个客户,如果它在 2007 年有订单但同一个订单不在 2008 年(并且由于订单已经在 2007 年,那么它不在 2008 年,所以条件 <> 2008 是多余的)。

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

好的,让我们有一个客户(客户 1)和以下 orders table

customers table
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

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

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

有一种更简单的方法可以解决这个问题 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'