【问题标题】:Unexpected result of Cross join交叉连接的意外结果
【发布时间】:2017-07-26 11:18:46
【问题描述】:

这些是我的 tblEmp 表和 tblDept 表(我使用的是 MS-SQL Server 2012),当我尝试在这两个表上使用交叉联接时,它会给出我是没想到的结果,就是想知道这个cross join为什么会出现这样的结果,谢谢。

ID  Name  Gender    Salary  Dept_id
1   abc   male      2004    1
2   Tom   female    5004    2
3   Sara  female    29404   2
4   Jim    male     8604    3
5   Lisan   male    2078    1
6   Brad    male    9804    3
7   Diana   female  2095    2
8   Henry   male    28204   2
9   Mark    male    20821   1
10  Miley   female  9456    1
11  Richie  male    8604    NULL
12  Lisan   female  20776   NULL

tblDept

ID  Dept_Name         Location
1   IT                Mumbai
2   HR                Delhi
3   Accounts          London
4   OtherDepartment   NewYork

这是交叉连接查询,它是输出

select Name, Gender, Salary, Dept_Name
from tblEmp 
CROSS JOIN tblDept 
where tblEmp.Dept_id is NULL

输出

Name    Gender  Salary  Dept_Name
Richie  male    8604    IT
Richie  male    8604    HR
Richie  male    8604    Accounts
Richie  male    8604    OtherDepartment
Lisan   female  20776   IT
Lisan   female  20776   HR
Lisan   female  20776   Accounts
Lisan   female  20776   OtherDepartment

我的预期是这样的

    Name    Gender  Salary  Dept_Name
    Richie  male    8604    NULL
    Richie  male    8604    NULL
    Richie  male    8604    NULL
    Richie  male    8604    NULL
    Lisan   female  20776   NULL
    Lisan   female  20776   NULL
    Lisan   female  20776   NULL
    Lisan   female  20776   NULL

【问题讨论】:

  • 跳过 WHERE 子句。你得到了什么?如果重新引入 WHERE 子句,当前结果是否有意义?
  • 你的期望是错误的。 cross join 与表之间的行不匹配。我猜你只需要考虑这个并尝试其他cross joins,以完全理解为什么结果是正确的。
  • @jarlh 跳过 where 子句会获取非空记录
  • 是的,还要将 tblEmp.Dept_id 添加到选择列表中!
  • 给你!明白了....谢谢

标签: sql sql-server cross-join


【解决方案1】:

CROSS JOIN 将为您提供第一个表的每一行与第二个表的每一行的连接(笛卡尔积),除非您使用 where 子句添加一个条件来连接两个表(在这种情况下,它的行为类似于内部连接)

下面是交叉连接的快速演示:

DECLARE @A table 
(
    A1 int identity(1,1),
    A2 int
)

DECLARE @B table 
(
    B1 int identity(1,1),
    B2 int
)

INSERT INTO @A VALUES (1), (2),  (NULL)

INSERT INTO @B VALUES (4), (5), (6)

SELECT *
FROM @A
CROSS JOIN @B

结果:

A1          A2          B1          B2
----------- ----------- ----------- -----------
1           1           1           4
2           2           1           4
3           NULL        1           4
1           1           2           5
2           2           2           5
3           NULL        2           5
1           1           3           6
2           2           3           6
3           NULL        3           6

如您所见,对于表@A 中的每条记录,您连接表@B 中的每条记录

SELECT *
FROM @A
CROSS JOIN @B
WHERE A2 IS NULL

结果:

A1          A2          B1          B2
----------- ----------- ----------- -----------
3           NULL        1           4
3           NULL        2           5
3           NULL        3           6

如您所见,对于表@A 中A2 为空的每条记录,您连接表@B 的每条记录。

【讨论】:

    【解决方案2】:

    结果是正确的,cross join 将为您提供基于两个表的所有组合:tblEmptblDept

    并且由于您使用Dept_Name 作为组合,没有 where 子句,它将为您提供两个表之间可能的所有组合:

    Name    Gender  Salary  Dept_Name
    abc   male      2004    IT
    abc   male      2004    HR
    abc   male      2004    Accounts
    abc   male      2004    OtherDepartment
    Tom   female    5004    IT
    Tom   female    5004    HR
    Tom   female    5004    Accounts
    Tom   female    5004    OtherDepartment
    
    ... and so on
    
    Richie  male    8604    IT
    Richie  male    8604    HR
    Richie  male    8604    Accounts
    Richie  male    8604    OtherDepartment
    Lisan   female  20776   IT
    Lisan   female  20776   HR
    Lisan   female  20776   Accounts
    Lisan   female  20776   OtherDepartment
    

    也就是说,通过交叉连接,您实际上会得到 12(来自 tblEmp)x 4(来自 tblDept)= 48 行

    那么你的 where 子句只会带走除RichieLisan 之外的所有人,因为他们两个是唯一拥有Dept_id = NULL 的人

    Name    Gender  Salary  Dept_Name
    Richie  male    8604    IT
    Richie  male    8604    HR
    Richie  male    8604    Accounts
    Richie  male    8604    OtherDepartment
    Lisan   female  20776   IT
    Lisan   female  20776   HR
    Lisan   female  20776   Accounts
    Lisan   female  20776   OtherDepartment
    

    如果你也查询Dept_id列,

    select Name, Gender, Salary, Dept_id, Dept_Name
    from tblEmp 
    CROSS JOIN tblDept 
    where tblEmp.Dept_id is NULL
    

    结果会更清楚,因为你实际上只得到Dept_id = NULL的员工:

    Name    Gender  Salary  Dept_id Dept_Name
    Richie  male    8604    NULL    IT
    Richie  male    8604    NULL    HR
    Richie  male    8604    NULL    Accounts
    Richie  male    8604    NULL    OtherDepartment
    Lisan   female  20776   NULL    IT
    Lisan   female  20776   NULL    HR
    Lisan   female  20776   NULL    Accounts
    Lisan   female  20776   NULL    OtherDepartment
    

    您的 Dept_Name 列来自 4 个 tblDept 条目,而不是来自 tblEmp 条目。

    【讨论】:

    • @Deepesh 嗨,太好了。 :) 是的,我试图提出一个解释来澄清这一点
    • @lan 真的很感谢你的努力......它帮助我更清楚地理解加入
    【解决方案3】:

    如果您需要显示所有员工及其部门,您可以使用 LEFT JOIN:

    SELECT Name, Gender, Salary, Dept_Name
    FROM 
        tblEmp AS E
        LEFT JOIN
        tblDept AS D
            ON E.Dept_id = D.ID
    

    结果:

    Name    Gender  Salary  Dept_Name 
    abc     male    2004    IT 
    Tom     female  5004    HR 
    Sara    female  29404   HR 
    Jim     male    8604    Accounts 
    Lisan   male    2078    IT 
    Brad    male    9804    Accounts 
    Diana   female  2095    HR 
    Henry   male    28204   HR 
    Mark    male    20821   IT 
    Miley   female  9456    IT 
    Richie  male    8604    NULL 
    Lisan   female  20776   NULL
    

    如果您需要显示所有员工和所有部门,您可以使用 FULL JOIN:

    SELECT Name, Gender, Salary, Dept_Name
    FROM 
        tblEmp AS E
        FULL JOIN
        tblDept AS D
            ON E.Dept_id = D.ID
    

    结果:

    Name    Gender  Salary  Dept_Name
    abc     male    2004    IT
    Tom     female  5004    HR
    Sara    female  29404   HR
    Jim     male    8604    Accounts
    Lisan   male    2078    IT
    Brad    male    9804    Accounts
    Diana   female  2095    HR
    Henry   male    28204   HR
    Mark    male    20821   IT
    Miley   female  9456    IT
    Richie  male    8604    NULL
    Lisan   female  20776   NULL
    NULL    NULL    NULL    OtherDepartment
    

    【讨论】:

      【解决方案4】:

      如果您确实希望每个部门的每个部门都有一个空行,例如具有空 dept_id 的人

      Name    Gender  Salary  Dept_Name
      Richie  male    8604    NULL
      Richie  male    8604    NULL
      Richie  male    8604    NULL
      Richie  male    8604    NULL
      Lisan   female  20776   NULL
      Lisan   female  20776   NULL
      Lisan   female  20776   NULL
      Lisan   female  20776   NULL
      

      你可以执行这个...

      select Name, Gender, Salary, NULL AS Dept_Name
      from tblEmp 
      CROSS JOIN tblDept 
      where tblEmp.Dept_id is NULL
      

      【讨论】:

        猜你喜欢
        • 2018-09-16
        • 1970-01-01
        • 1970-01-01
        • 2014-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-11
        • 2021-08-30
        相关资源
        最近更新 更多