根据我放置过滤条件的位置,查询中的过滤条件会得到不同的结果。我的问题是:
鉴于简化的方案:
--Table: Parent Columns: ID, Name, Description
--Table: Child Columns: ID, ParentID, Name, Description
--Query 1
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description
FROM Parent p
LEFT OUTER JOIN Child c ON (p.ID = c.ParentID)
WHERE c.ID IS NULL OR c.Description = 'FilterCondition'
--Query 2
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description
FROM Parent p
LEFT OUTER JOIN Child c
ON (p.ID = c.ParentID AND c.Description = 'FilterCondition')
我认为查询会返回相同的结果集,当他们没有时,我感到很惊讶。我正在使用MS SQL2005并且在实际查询中,查询1返回~700行,查询2返回~1100行,我无法检测返回行和排除哪些行的模式。查询1中仍有许多行,子行包含数据和NULL数据。我更喜欢查询2的样式(我认为它更优),但我认为查询会返回相同的结果。
修改/概述:
这里提供了一些很棒的答案。我很难选择给谁答案。我决定选择mdma,因为它是第一个答案,也是最清晰的答案之一。根据提供的答案,这是我的总结:
可能的结果:
查询结果:
由于左连接,查询2始终返回父级。在查询1中,WHERE子句在左连接之后执行,因此不包括子项中没有子项匹配过滤器的父项(案例B1)。
注意:在B1的情况下仅返回父信息,在B2的情况下,仅返回与过滤器匹配的父/子信息。
HLGEM提供了一个很好的链接:
http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN
答案 0 :(得分:10)
是的,存在巨大差异。在LEFT JOIN的ON子句中放置过滤器时,在结果连接到外部表之前,将应用过滤器。在WHERE子句中应用过滤器时,它会在应用LEFT JOIN之后发生。
简而言之,第一个查询将排除存在子行但子描述不等于过滤条件的行,而第二个查询将始终返回父行的行。
答案 1 :(得分:9)
第一个查询将返回父项没有子项或某些子项与过滤条件匹配的情况。具体而言,父项具有一个子项但与过滤条件不匹配的情况将被省略。
第二个查询将为所有父项返回一行。如果过滤条件不匹配,则将为所有c列返回NULL。这就是为什么在查询2中获得更多行的原因 - 具有与过滤条件不匹配的子项的父项将输出NULL子值,在第一个查询中它们将被过滤掉。
答案 2 :(得分:3)
将条件放在where子句中会将其转换为内部联接(除非您使用的地方id为null,这使得记录不在表中) 请参阅此内容以获得更全面的解释:
http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN
答案 3 :(得分:2)
对于此记录集:
parent
id
1
child
id parent filter
1 1 OtherCondition
2 1 OtherCondition
,第一个查询将返回0
个记录,而第二个查询将返回1
个记录:
WITH parent (id) AS
(
SELECT 1
),
child (id, parent, condition) AS
(
SELECT 1, 1, 'OtherCondition'
UNION ALL
SELECT 2, 1, 'OtherCondition'
)
SELECT *
FROM parent
LEFT JOIN
child
ON child.parent = parent.id
/* The children are found, so no fake NULL records returned */
1 1 1 OtherCondition
1 2 1 OtherCondition
现在添加WHERE
子句:
WITH parent (id) AS
(
SELECT 1
),
child (id, parent, condition) AS
(
SELECT 1, 1, 'OtherCondition'
UNION ALL
SELECT 2, 1, 'OtherCondition'
)
SELECT *
FROM parent
LEFT JOIN
child
ON child.parent = parent.id
WHERE child.id IS NULL OR child.condition = 'FilterCondition'
WHERE
子句过滤上一步返回的记录,没有记录符合条件。
虽然这个:
WITH parent (id) AS
(
SELECT 1
),
child (id, parent, condition) AS
(
SELECT 1, 1, 'OtherCondition'
UNION ALL
SELECT 2, 1, 'OtherCondition'
)
SELECT *
FROM parent
LEFT JOIN
child
ON child.parent = parent.id
AND child.condition = 'FilterCondition'
1 NULL NULL NULL
返回一条假记录。
答案 4 :(得分:1)
只有description != 'FilterCondition'
子项的父项不会出现在查询1中,因为在连接行后会评估WHERE子句。
答案 5 :(得分:1)
第一个查询返回的行数较少,因为它只返回没有子节点的行,或者具有与过滤条件匹配的子节点。
WHERE子句排除其余的(那些DO有孩子但与过滤条件不匹配的子句。)
第二个查询显示上述所有三个条件。
答案 6 :(得分:0)
我注意到可以使结果发生变化的几个差异。在第一个查询中,您有LEFT OUTER JOIN Child c ON (p.ID = c.ParentID)
,然后在第二个查询中有LEFT OUTER JOIN Child c
ON (p.ID = c.ParentID AND c.Description = 'FilterCondition')
,这使得第二个查询返回所有父项孩子满足你的条件,因为第一个条件也将返回没有孩子的父母。另请参阅连接条件的优先级和条件。