剖析连接

Bij*_*ose 3 sql-server t-sql

最近我在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)

我做了几种破解方法,都是徒劳的。我想我错过了一些我的发现如下

  1. 首先,他将四列命名为每个级别 1,2,3 等
  2. 每次他离开时加入同一张桌子4次,每次使用不同的别名
  3. 通过在每个连接上给出条件,表被更改到下一个级别
  4. 指定经理的 where 条件

我未能理解的部分是他所做的连接,即使我知道使用左连接,我们将获得左表的列,如果没有找到匹配,则在右侧的列将是 NULL。所以我正在寻找一些可视化在这里发生的连接或对这个特定场景的深度连接的一些理解。如果问题不适合这里,我将删除它。我在我发布的问题中也问了同样的问题,但没有回复,这就是我提出新问题的原因

And*_*y M 6

先试试这个没有连接的查询:

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未引用任何内容的行。换句话说,这仅返回最顶层的经理。对于您的特定示例,它的工作方式如下:

在 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代表level12forlevel23for 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 原始查询中的其他两列level4level5,将返回 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)

如果克里斯关于大多数情况下四个连接应该足够的假设不适用于您的特定情况(当然,我不是指您问题中的简单示例),您可以使用相同的模式进行更多自连接。