以下SQL代码之间有什么区别:
select count(*)
from A
left join B
on a.id = b.id
where a.status = 2 and
b.id is NULL
和
select count(*)
from A
left join B
on a.id = b.id
and a.status =2
where b.id is NULL
?我读到这个:Semantic difference between join queries但我仍然不知道哪个更好用
我花了过去一小时阅读本文并把握所有答案的附加价值,但我理解代码示例和“从未遇到过这样”最好的
答案 0 :(得分:10)
如何使用LEFT连接是关键,一个将过滤掉结果,另一个只是使LEFT连接失败,保留来自JOIN左侧的数据。
(1)在a.id = b.id上左连接B. 其中a.status = 2
忽略其他过滤器,这表示对表B进行LEFT JOIN,因此,“尝试使用条件a.id=b.id
”加入表B.“
如果你不能匹配,请将记录保存在左表(即A)。在此之后,在剩余记录上,FILTER out(即REMOVE)记录与a.status=2
不匹配
(2)左连接B. on a.id = b.id 和a.status = 2
忽略其他过滤器,这表示在两个条件下对表B进行LEFT JOIN,因此,“尝试在两个条件a.id = b.id and a.status =2
”上加入表B.如果两个条件都没有得到B的记录(即使一个与B无关),请保留A的记录。
答案 1 :(得分:5)
区别在于逻辑评估条件,这反过来会影响结果集。
在您的示例(重新格式化)中,您有:
示例1
SELECT COUNT(*)
FROM A LEFT JOIN B ON a.id = b.id
WHERE a.status = 2 AND b.id is NULL
示例2
SELECT COUNT(*)
FROM A LEFT JOIN B ON a.id = b.id AND a.status = 2
WHERE b.id is NULL
在第一种情况下,应用LEFT JOIN并生成结果集;然后使用WHERE子句中的两个条件对其进行过滤。
在第二种情况下,LEFT JOIN由a.status
上的过滤条件组成,在某些情况下可能会改变LEFT JOIN的结果集。然后使用主WHERE子句过滤此结果集。
示例2基本上等同于:
示例2A
SELECT COUNT(*)
FROM (SELECT * FROM A WHERE a.status = 2) AS A
LEFT JOIN B ON a.id = b.id
WHERE b.id is NULL
有些问题(但可能不是这个问题),差异可能很重要。
让我们尝试创建一些简单的样本数据:
Table A Table B
id status id
4 2 1
5 3
示例1将具有中间结果集:
a.id a.status b.id
4 2 null
5 3 null
和WHERE子句删除了第二行。
示例2将具有中间结果集:
a.id a.status b.id
4 2 null
在这个例子中,最终结果是一样的,而且我还没有能够提出不一样的数据。
如果移动的查询条件位于外连接表上并且比简单相等更复杂,则可以看到效果。
答案 2 :(得分:5)
重写没有LEFT JOIN / IS NULL
的2个查询,因此很明显他们可以在某些情况下返回不同的数据集:
---Query 1
SELECT COUNT(*)
FROM a
WHERE a.status = 2
AND NOT EXISTS
( SELECT *
FROM b
WHERE a.id = b.id
)
和
---Query 2
SELECT COUNT(*)
FROM a
WHERE NOT ( a.status = 2
AND EXISTS
( SELECT *
FROM b
WHERE a.id = b.id
)
)
--- or:
---Query 2
SELECT COUNT(*)
FROM a
WHERE a.status <> 2
OR NOT EXISTS
( SELECT *
FROM b
WHERE a.id = b.id
)
答案 3 :(得分:1)
也许这更容易理解:
SELECT id
FROM A
WHERE status = 2
EXCEPT
SELECT id
FROM B;
在不太可能的情况下,您只对结果的基数感兴趣:
SELECT COUNT(*)
FROM ( SELECT id
FROM A
WHERE status = 2
EXCEPT
SELECT id
FROM B ) AS DT1;