【问题标题】: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

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

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

【问题讨论】:

    标签: mysql sql select inner-join cartesian-product


    【解决方案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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-13
        • 1970-01-01
        • 2015-06-25
        • 2012-07-19
        • 2019-01-20
        • 2017-03-24
        相关资源
        最近更新 更多