postgresql Why Exists和not exists在SQL中返回不同的结果

xienkqul  于 2023-03-01  发布在  PostgreSQL
关注(0)|答案(1)|浏览(150)

我一直在练习SQL基本查询,但我坚持在一个任务。我的意思是-我知道如何做,但当我尝试应用反向逻辑,似乎有些错误,我不明白是什么使其他查询产生错误的结果。所以任务如下:“列出购买了自行车但未购买 Helm 的客户。”因此,通过“不存在”解决此问题非常简单:

SELECT DISTINCT(o.customerid) 
FROM salesordersexample.order_details od
JOIN salesordersexample.products p ON od.productnumber = p.productnumber
JOIN salesordersexample.categories c ON c.categoryid = p.categoryid
JOIN salesordersexample.orders o ON od.ordernumber = o.ordernumber 
WHERE NOT EXISTS
(
    SELECT DISTINCT(o2.customerid) 
    FROM salesordersexample.order_details od2
    JOIN salesordersexample.products p2 ON od2.productnumber = p2.productnumber
    JOIN salesordersexample.categories c2 ON c2.categoryid = p2.categoryid
    JOIN salesordersexample.orders o2 ON od2.ordernumber = o2.ordernumber 
    WHERE p2.productname LIKE '%Helmet%' AND o.customerid = o2.customerid
) 
AND p.productname ILIKE '%bike%';

但是当我想使用EXISTS时,我认为在子查询中将LIKE转换为NOT LIKE就足够了,我的逻辑强烈地引导我实现这个想法。我试图理解正在发生的事情,但我没有任何线索。无法正常工作查询:

SELECT DISTINCT(o.customerid) 
FROM salesordersexample.order_details od
JOIN salesordersexample.products p ON od.productnumber = p.productnumber
JOIN salesordersexample.categories c ON c.categoryid = p.categoryid
JOIN salesordersexample.orders o ON od.ordernumber = o.ordernumber 
WHERE EXISTS
(
    SELECT DISTINCT(o2.customerid) 
    FROM salesordersexample.order_details od2
    JOIN salesordersexample.products p2 ON od2.productnumber = p2.productnumber
    JOIN salesordersexample.categories c2 ON c2.categoryid = p2.categoryid
    JOIN salesordersexample.orders o2 ON od2.ordernumber = o2.ordernumber 
    WHERE p2.productname NOT LIKE '%Helmet%' AND o.customerid = o2.customerid
) 
AND p.productname ILIKE '%bike%';

第一个查询返回了正确的结果- 2行,而第二个查询是错误的,返回了27行。我深信问题是微不足道的,但我不明白为什么结果是错误的。

bq3bfh9z

bq3bfh9z1#

这两个子查询在逻辑上并不等效。
在第一个查询中,not exists子查询确保客户没有购买 Helm -这正是您想要的。
在第二个查询中,exists检查他们是否至少购买了不是 Helm 的东西--不管他们是否购买了 Helm 。但是,由于查询的其余部分确保他们确实已经购买了自行车,因此子查询总是查找匹配的行简单地说,exists条件不过滤任何行,查询只返回所有购买自行车的客户。
注:

  • (not) exists检查是否有匹配的行,因此select distinct是多余的:select 1就足够了,数据库可能会在幕后为您进行优化,但是显式是更好的做法,可以使查询更容易执行
  • 我们可以用group by来描述逻辑,用having子句来过滤,这样就不需要在子查询中重复连接

相关问题