常量值如何影响 Join 的 ON 子句?

Posted

技术标签:

【中文标题】常量值如何影响 Join 的 ON 子句?【英文标题】:How do constant values effect the ON clause of Joins? 【发布时间】:2010-12-04 19:40:07 【问题描述】:

我最近发现 LEFT JOIN 的 ON 子句可能包含 (1 = 1) 之类的值。

这让我很沮丧,因为它打破了我对连接功能的看法。

我遇到过以下情况的更详细版本:

SELECT DISTINCT Person.ID, ...
FROM Person LEFT JOIN Manager 
ON (Manager.ID = Person.ID OR Manager.ID = -1))
WHERE (...)

这是完全合法的。如果有的话,“Manager.ID = -1”会完成什么?这对 Join 有何影响?

【问题讨论】:

我带着同样的问题来到这个页面。您提到使用常量的 ON 表达式是“完全合法的”。你是怎么确定的?你是说它是“合法的”(由规范批准)还是只是在给定的实现中工作 【参考方案1】:

除非 Manager 表中有一行 id 等于 -1,否则它什么都不做。如果有这样一行,那么该行将始终连接到 person 表中的每一行。因此,对于每个 Person 行,您可能会在查询输出中获得两个 ros,一个带有 manager.id = 到人员的 id,另一个带有 Manager.ID = -1 行

【讨论】:

比我想象的要简单。谢谢。【参考方案2】:

如果人员表是:

id  name

1   Person One
2   Person Two
3   Person Three
4   Person Four
5   Person Five

如果经理表是

id  name
-1  Admin
2   Manager One
3   Manager Two

如果查询是:

SELECT DISTINCT *
FROM Person LEFT JOIN Manager 
ON (Manager.id = Person.id OR Manager.id = -1)

那么结果是:

Person One  -1  Admin
Person Two  -1  Admin
Person Two  2   Manager One
Person Three    -1  Admin
Person Three    3   Manager Two
Person Four -1  Admin
Person Five -1  Admin

这里所有人员行都与 -1 Admin (在经理表上)联接,如果经理表中存在相同的 id,则会发生另一个联接。

【讨论】:

缺少“第四个人”浪费了我 5 分钟 :)【参考方案3】:

您还将看到用于进一步过滤记录的 AND 子句。这在处理外连接时非常重要,因为将这些过滤操作添加到 where 子句会将连接从左连接变为内连接(除非它类似于 where t.idfield is null)。

下面我将展示它是如何工作的,以及为什么将过滤子句放在正确的位置很重要。

创建表 #test ( test1id int, test varchar (10)) 创建表 #test2 ( test2id int, test1id int, test2 varchar (10))

insert into #test (test1id, test)
select 1, 'Judy'
union all
select 2, 'Sam'
union all 
select 3, 'Nathan'

insert into #test2 (test2id, test1id, test2)
select 1,1,'hello'
union all 
select 2,1,'goodbye'
union all 
select 3,2,'hello'

select * from #test t
left join #test2 t2 on t.test1id = t2.test1id
where test2 = 'goodbye'
--result set
--test1id   test    test2id test1id test2
--1 Judy    2   1   goodbye

select * from #test t
left join #test2 t2 on t.test1id = t2.test1id
and test2 = 'goodbye'
--result set 
--test1id   test    test2id test1id test2
--1 Judy    2   1   goodbye
--2 Sam NULL    NULL    NULL
--3 Nathan  NULL    NULL    NULL

您可以使用 where some field is null (假设您选择一个永远不会为 null 的字段)来获取第一个表中的记录,但不能像这样获取第二个表中的记录:

select * from #test t
left join #test2 t2 on t.test1id = t2.test1id
where test2id is null
--result set 
--test1id   test    test2id test1id test2
--3 Nathan  NULL    NULL    NULL

【讨论】:

以上是关于常量值如何影响 Join 的 ON 子句?的主要内容,如果未能解决你的问题,请参考以下文章

JOIN 和 ON 子句(NULL 值)

如何在 LEFT JOIN ON 子句中使用子选择?

使用静态/常量 ON 子句时出现奇怪的 MERGE 行为

2015.1.8 Left join 左连接

在 JOIN 的 ON 子句中使用别名

JOIN 的 ON 子句中引用的表的顺序是不是重要?