使用多个内部联接时,与使用单个内部联接时相比,我得到不同的结果

Posted

技术标签:

【中文标题】使用多个内部联接时,与使用单个内部联接时相比,我得到不同的结果【英文标题】:When using multiple inner joins I get different results compared to when I use a single inner join 【发布时间】:2021-12-28 18:12:35 【问题描述】:

我无法理解为什么我的两个 SQL 查询输出的高级管理人员计数结果不同,而我预计它们是相同的。

SELECT COMPANY.Company_Code, COMPANY.Founder, COUNT(SENIOR_MANAGER.Senior_Manager_Code)
FROM COMPANY INNER JOIN SENIOR_MANAGER
ON SENIOR_MANAGER.COMPANY_CODE = COMPANY.COMPANY_CODE
GROUP BY COMPANY.COMPANY_CODE, COMPANY.FOUNDER;

此 SQL 查询试图找出不同公司有多少高级管理人员,结果如下:

C1 Angela 5 
C10 Earl 2 
C100 Aaron 4 
C11 Robert 1 
C12 Amy 6 

但是,当我在另一个使用两个内部联接的查询中使用相同的条件时,我会得到另一组结果。这是我的查询:

SELECT COMPANY.COMPANY_CODE, COMPANY.FOUNDER, COUNT(LEAD_MANAGER.LEAD_MANAGER_CODE), 
COUNT(SENIOR_MANAGER.SENIOR_MANAGER_CODE)
FROM COMPANY INNER JOIN LEAD_MANAGER
ON COMPANY.COMPANY_CODE = LEAD_MANAGER.COMPANY_CODE
INNER JOIN SENIOR_MANAGER
ON SENIOR_MANAGER.COMPANY_CODE = COMPANY.COMPANY_CODE
GROUP BY COMPANY.COMPANY_CODE, COMPANY.FOUNDER;

结果如下:

C1 Angela 10 10 
C10 Earl 2 2 
C100 Aaron 8 8 
C11 Robert 1 1 
C12 Amy 12 12

第四列是高级经理的人数,由于某种原因与第三列的值相同,但与我显示的第一个查询的值不同。有人可以解释为什么结果不同吗?我怀疑这可能是因为我错误地使用了内部连接?

我期望的结果是第四列显示第一个查询中的值。

【问题讨论】:

【参考方案1】:

由于双连接查询的计数反映了单连接查询的倍数,因此您将先前不同的配对与新连接重复计算。

具体来说,在第一个查询中,COMPANYSENIOR_MANAGER 表可以有一对多的关系,一个不同的公司可以有多个高级经理。

但是,在第二个查询中,当包含与 COMPANY 具有更多不同配对的 LEAD_MANAGER 表时,您针对 COMPANYLEAD_MANAGER 的每个对应配对重复 SENIOR_MANAGER 多次。


作为重复计数的解决方案,考虑加入聚合子查询(或CTEs):

SELECT agg_s.COMPANY_CODE,
       agg_s.FOUNDER,
       agg_s.SENIOR_MANAGER_COUNT.
       agg_l.LEAD_MANAGER_COUNT
FROM
  (SELECT c.COMPANY_CODE, 
          c.FOUNDER, 
          COUNT(s.SENIOR_MANAGER_CODE) AS SENIOR_MANAGER_COUNT
   FROM COMPANY c
   INNER JOIN SENIOR_MANAGER s
      ON s.COMPANY_CODE = c.COMPANY_CODE
   GROUP BY c.COMPANY_CODE,
            c.FOUNDER
  ) AS agg_s
INNER JOIN
  (SELECT c.COMPANY_CODE, 
          c.FOUNDER, 
          COUNT(l.LEAD_MANAGER_CODE) AS LEAD_MANAGER_COUNT
   FROM COMPANY c
   INNER JOIN LEAD_MANAGER l
      ON c.COMPANY_CODE = l.COMPANY_CODE
   GROUP BY c.COMPANY_CODE,
            c.FOUNDER
  ) AS agg_l

ON  agg_s.COMPANY_CODE = agg_l.COMPANY_CODE
AND agg_s.FOUNDER = agg_l.FOUNDER

更好的是,考虑更改表设计以进行适当的规范化,其中您维护一个单个MANAGER 表,其中TYPE 指示列用于SENIORLEAD。然后运行带有条件聚合的单个查询:

SELECT c.COMPANY_CODE, 
       c.FOUNDER, 
       COUNT(CASE WHEN m.TYPE = 'SENIOR' THEN 1 ELSE NULL END) AS SENIOR_MANAGER_COUNT,
       COUNT(CASE WHEN m.TYPE = 'LEAD' THEN 1 ELSE NULL END) AS LEAD_MANAGER_COUNT
FROM COMPANY c
INNER JOIN MANAGER m
   ON c.COMPANY_CODE = m.COMPANY_CODE
GROUP BY c.COMPANY_CODE,
         c.FOUNDER;

【讨论】:

【参考方案2】:

您的问题缺少有关数据的信息(这可能是您收到反对票的原因),但答案似乎相当清楚。

每次连接新表时,结果集中的每一行都会乘以该行在新表中匹配连接条件的次数。

所以您的结果显示 C1、C100 和 C12 中的每一个都有两个 LEAD_MANAGER。

【讨论】:

以上是关于使用多个内部联接时,与使用单个内部联接时相比,我得到不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

使用具有多个条件的内部联接

使用内部联接更新多个表中的列

如何使用多个 And 条件,其中我使用内部联接组合了三个表

内部联接与内部联接(SELECT . FROM)

查找内部联接的最大值 - SQL

如何使用内部联接创建触发器