为什么在 WHERE 或 LEFT JOIN 中放置条件时 "zero" 结果是否出现 COUNT?
Why does "zero" results in COUNT appear or not when placing the condition in WHERE or LEFT JOIN?
我已阅读placing conditions in WHERE or in JOIN does not matter。但是,我 运行 得到一个听起来有点可疑的结果:结果因我放置条件的位置而异。谁能给我解释一下它的底层逻辑?
我有两个虚拟表 topic 和 issues。一个问题有一个标题和与主题的 1-n 关系,因此每个问题都与一个主题相关。然后,该问题有一个可以跨主题重复的标题。它的结构很糟糕,但我无法更改它:/
所有这些都是in SQL Fiddle。
<topic> <issues>
id | name id | topic_id | title
------------ ---------------------
1 | art 1 | 1 | final
2 | music 2 | 1 | semi final
3 | sport 3 | 2 | final
4 | 2 | draft
现在我想 select 一个主题在问题列表中出现的次数,当有 none 时得到 0
。在 How to include “zero” / “0” results in COUNT aggregate?:
的帮助下,使用 LEFT JOIN
可以做到
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
GROUP BY t.id;
这个returns预期的结果:
name | count
--------------
art | 2
music | 2
sport | 0
现在我想知道给定标题在多个主题中出现了多少次。例如,每个主题出现多少次 "final"?这就是问题出现的地方:
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
AND i.title = "final" -- in the LEFT JOIN!
GROUP BY t.id;
Returns:
name | count
--------------
art | 1
music | 1
sport | 0 -- yeah, sport - 0 is here
鉴于
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
WHERE
i.title = "final" -- in the WHERE!
GROUP BY t.id;
Returns
name | count
--------------
art | 1
music | 1 -- where is sport - 0?
尝试在 LEFT JOIN 上移动 where 条件,因为如果在 where 条件中使用左联接 table 的列,这将表现得像 INNER JOIN,并且 returns 仅匹配记录
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id AND i.title = "final"
GROUP BY t.id;
WHERE
i.title = "final"
还排除了 i.title is NULL
的行。因此,当 LEFT JOIN 在 i
table 中没有相应的值时,WHERE 将排除行。
WHERE
i.title = "final" or i.title is null
离开行
如评论中所述,您的最终查询确实是内部联接,如果左侧 table 中没有匹配项,则左侧联接计数 returns 0,但是当您使用它成为一个内部联接,只有 returns 两个 table 都匹配的结果。
/*Joins on the key values provided, if there is no value that
corresponds on the left table counts returns 0 */
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
group by t.id;
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
and i.title = "final"
group by t.id;
/*Joins on the key values provided, if there is no value that corresponds on the left
table then count returns 0 and then filter by the title
*/
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
where i.title = "final"
group by t.id;
/*Solution*/
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
where (i.title = "final" || i.title is null)
group by t.id;
"placing conditions in WHERE or in JOIN does not matter" 是不正确的。如果 FROM 在顶层只有内部 JOIN(INNER JOIN ON、JOIN ON、CROSS JOIN),那么您可以在其内部 JOIN 和 WHERE 之间移动条件。但是对于 OUTER JOIN 就不一样了。请参阅 CROSS JOIN vs INNER JOIN in SQL Server 2008 re inner joins and Conditions in LEFT JOIN (OUTER JOIN) vs INNER JOIN 重新将外部和内部连接在一起。
一个 OUTER JOIN ON returns what INNER JOIN ON returns 加上可能通过用 NULL 扩展输入行形成的更多行。如果您稍后通过 WHERE 条件删除这些额外的行,那么您可以只使用 INNER JOIN ON(带有或)而不使用 WHERE 条件,或者只使用带有 WHERE 条件的 CROSS JOIN。
CROSS JOIN 对其参数表进行交叉连接,(INNER) JOIN ON 进行 CROSS JOIN,然后删除不满足 ON 条件的行,外部 JOIN ON 进行 INNER JOIN ON,然后根据 LEFT/RIGHT/FULL 添加某些由 NULL 扩展行组成的未满足 ON 条件的行。然后在所有连接 WHERE 删除不满足其条件的行之后。然后 SELECT 删除、添加和重命名列。
我已阅读placing conditions in WHERE or in JOIN does not matter。但是,我 运行 得到一个听起来有点可疑的结果:结果因我放置条件的位置而异。谁能给我解释一下它的底层逻辑?
我有两个虚拟表 topic 和 issues。一个问题有一个标题和与主题的 1-n 关系,因此每个问题都与一个主题相关。然后,该问题有一个可以跨主题重复的标题。它的结构很糟糕,但我无法更改它:/
所有这些都是in SQL Fiddle。
<topic> <issues>
id | name id | topic_id | title
------------ ---------------------
1 | art 1 | 1 | final
2 | music 2 | 1 | semi final
3 | sport 3 | 2 | final
4 | 2 | draft
现在我想 select 一个主题在问题列表中出现的次数,当有 none 时得到 0
。在 How to include “zero” / “0” results in COUNT aggregate?:
LEFT JOIN
可以做到
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
GROUP BY t.id;
这个returns预期的结果:
name | count
--------------
art | 2
music | 2
sport | 0
现在我想知道给定标题在多个主题中出现了多少次。例如,每个主题出现多少次 "final"?这就是问题出现的地方:
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
AND i.title = "final" -- in the LEFT JOIN!
GROUP BY t.id;
Returns:
name | count
--------------
art | 1
music | 1
sport | 0 -- yeah, sport - 0 is here
鉴于
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id
WHERE
i.title = "final" -- in the WHERE!
GROUP BY t.id;
Returns
name | count
--------------
art | 1
music | 1 -- where is sport - 0?
尝试在 LEFT JOIN 上移动 where 条件,因为如果在 where 条件中使用左联接 table 的列,这将表现得像 INNER JOIN,并且 returns 仅匹配记录
SELECT
t.name, count(i.title)
FROM
topic as t
LEFT JOIN issues as i
ON t.id = i.topic_id AND i.title = "final"
GROUP BY t.id;
WHERE
i.title = "final"
还排除了 i.title is NULL
的行。因此,当 LEFT JOIN 在 i
table 中没有相应的值时,WHERE 将排除行。
WHERE
i.title = "final" or i.title is null
离开行
如评论中所述,您的最终查询确实是内部联接,如果左侧 table 中没有匹配项,则左侧联接计数 returns 0,但是当您使用它成为一个内部联接,只有 returns 两个 table 都匹配的结果。
/*Joins on the key values provided, if there is no value that
corresponds on the left table counts returns 0 */
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
group by t.id;
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
and i.title = "final"
group by t.id;
/*Joins on the key values provided, if there is no value that corresponds on the left
table then count returns 0 and then filter by the title
*/
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
where i.title = "final"
group by t.id;
/*Solution*/
select t.name, count(i.title)
from topic as t
left join issues as i on t.id = i.topic_id
where (i.title = "final" || i.title is null)
group by t.id;
"placing conditions in WHERE or in JOIN does not matter" 是不正确的。如果 FROM 在顶层只有内部 JOIN(INNER JOIN ON、JOIN ON、CROSS JOIN),那么您可以在其内部 JOIN 和 WHERE 之间移动条件。但是对于 OUTER JOIN 就不一样了。请参阅 CROSS JOIN vs INNER JOIN in SQL Server 2008 re inner joins and Conditions in LEFT JOIN (OUTER JOIN) vs INNER JOIN 重新将外部和内部连接在一起。
一个 OUTER JOIN ON returns what INNER JOIN ON returns 加上可能通过用 NULL 扩展输入行形成的更多行。如果您稍后通过 WHERE 条件删除这些额外的行,那么您可以只使用 INNER JOIN ON(带有或)而不使用 WHERE 条件,或者只使用带有 WHERE 条件的 CROSS JOIN。
CROSS JOIN 对其参数表进行交叉连接,(INNER) JOIN ON 进行 CROSS JOIN,然后删除不满足 ON 条件的行,外部 JOIN ON 进行 INNER JOIN ON,然后根据 LEFT/RIGHT/FULL 添加某些由 NULL 扩展行组成的未满足 ON 条件的行。然后在所有连接 WHERE 删除不满足其条件的行之后。然后 SELECT 删除、添加和重命名列。