最近我在dba.stackexchange 中问了一个问题,这个问题是关于 sql 中的数据层次结构的,一个叫chris allen 的人回答了这个问题,我真的很喜欢它,但是当我试图理解这个查询时,我更加困惑了。
这是查询:
Res_id Res_name Man_id
1 sam 3
2 Biju 4
3 adrian Null
4 Helen 3
5 Micah 4
select
level1.res_name as level1,
level2.res_name as level2,
level3.res_name as level3,
level4.res_name as level4,
level5.res_name as level5
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
left join resource as level3 on level2.res_id=level3.man_id
left join resource as level4 on level3.res_id=level4.man_id
left join resource as level5 on level4.res_id=level5.man_id
where isnull(level1.man_id,0)=0
Run Code Online (Sandbox Code Playgroud)
我做了几种破解方法,都是徒劳的。我想我错过了一些我的发现如下
我未能理解的部分是他所做的连接,即使我知道使用左连接,我们将获得左表的列,如果没有找到匹配,则在右侧的列将是 NULL。所以我正在寻找一些可视化在这里发生的连接或对这个特定场景的深度连接的一些理解。如果问题不适合这里,我将删除它。我在我发布的问题中也问了同样的问题,但没有回复,这就是我提出新问题的原因
先试试这个没有连接的查询:
select
level1.res_name as level1
from resource as level1
where isnull(level1.man_id,0)=0
Run Code Online (Sandbox Code Playgroud)
这将返回man_id
未引用任何内容的行。换句话说,这仅返回最顶层的经理。对于您的特定示例,它的工作方式如下:
FROM 子句返回整个表:
level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
1 sam 3
2 Biju 4
3 adrian NULL
4 Helen 3
5 Micah 4
Run Code Online (Sandbox Code Playgroud)WHERE 子句只留下一行:
level1.Res_id level1.Res_name level1.Man_id
------------- --------------- -------------
3 adrian NULL
Run Code Online (Sandbox Code Playgroud)最后,SELECT 只取一列:
level1
------
adrian
Run Code Online (Sandbox Code Playgroud)在 Chris 的查询中添加一个自联接,
select
level1.res_name as level1,
level2.res_name as level2
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
where isnull(level1.man_id,0)=0
Run Code Online (Sandbox Code Playgroud)
给你每一位高层管理者的直接下属。更具体地说,联接产生以下行集:
level1.Res_id level1.Res_name level1.Man_id level2.Res_id level2.Res_name level2.Man_id
------------- --------------- ------------- ------------- --------------- -------------
1 sam 3 NULL NULL NULL
2 Biju 4 NULL NULL NULL
3 adrian NULL 1 sam 3
3 adrian NULL 4 Helen 3
4 Helen 3 2 Biju 4
4 Helen 3 2 Biju 4
5 Micah 4 NULL NULL NULL
Run Code Online (Sandbox Code Playgroud)
WHERE 子句将其过滤为:
level1.Res_id level1.Res_name level1.Man_id level2.Res_id level2.Res_name level2.Man_id
------------- --------------- ------------- ------------- --------------- -------------
3 adrian NULL 1 sam 3
3 adrian NULL 4 Helen 3
Run Code Online (Sandbox Code Playgroud)
最后 SELECT 子句只返回名称:
level1 level2
------ ------
adrian sam
adrian Helen
Run Code Online (Sandbox Code Playgroud)
以同样的方式,再添加一个连接,如下所示:
select
level1.res_name as level1,
level2.res_name as level2,
level3.res_name as level3
from resource as level1
left join resource as level2 on level1.res_id=level2.man_id
left join resource as level3 on level2.res_id=level3.man_id
where isnull(level1.man_id,0)=0
Run Code Online (Sandbox Code Playgroud)
带来下一个级别的下属:
这是将表的第三个实例连接到第一个连接的结果的结果:
1.Res_id 1.Res_name 1.Man_id 2.Res_id 2.Res_name 2.Man_id 3.Res_id 3.Res_name 3.Man_id
-------- ---------- -------- -------- ---------- -------- -------- ---------- --------
1 sam 3 NULL NULL NULL NULL NULL NULL
2 Biju 4 NULL NULL NULL NULL NULL NULL
3 adrian NULL 1 sam 3 NULL NULL NULL
3 adrian NULL 4 Helen 3 2 Biju 4
3 adrian NULL 4 Helen 3 5 Micah 4
4 Helen 3 2 Biju 4 NULL NULL NULL
4 Helen 3 5 Micah 4 NULL NULL NULL
5 Micah 4 NULL NULL NULL NULL NULL NULL
Run Code Online (Sandbox Code Playgroud)
(为方便起见,我缩短了表别名:1
代表level1
、2
forlevel2
和3
for level3
)
这是 WHERE 过滤器之后剩下的:
1.Res_id 1.Res_name 1.Man_id 2.Res_id 2.Res_name 2.Man_id 3.Res_id 3.Res_name 3.Man_id
-------- ---------- -------- -------- ---------- -------- -------- ---------- --------
3 adrian NULL 1 sam 3 NULL NULL NULL
3 adrian NULL 4 Helen 3 2 Biju 4
3 adrian NULL 4 Helen 3 5 Micah 4
Run Code Online (Sandbox Code Playgroud)这就是 SELECT 从上面提取的内容并返回给您:
level1 level2 level3
------ ------ ------
adrian sam NULL
adrian Helen Biju
adrian Helen Micah
Run Code Online (Sandbox Code Playgroud)其余的连接也是如此。但是,在您的示例中,不会有更多行,因为表中的层次结构不会超过两个级别。因此,Chris 原始查询中的其他两列level4
和level5
,将返回 NULL:
level1 level2 level3 level4 level5
------ ------ ------ ------ ------
adrian sam NULL NULL NULL
adrian Helen Biju NULL NULL
adrian Helen Micah NULL NULL
Run Code Online (Sandbox Code Playgroud)
如果克里斯关于大多数情况下四个连接应该足够的假设不适用于您的特定情况(当然,我不是指您问题中的简单示例),您可以使用相同的模式进行更多自连接。