使用对结果值具有“乘数”作用的单列对多个表进行内部联接

时间:2018-12-14 16:50:44

标签: mysql sql

试图在4个表(项目,任务,支出和捐款)上运行简单的内部联接查询。这些连接似乎在某个地方纠结在一起。例如SUM(tasks.budget_amount)的总和应为3,211,385.21,但是我的总值为49,659,564.60

SELECT projects.id, projects.name, SUM(tasks.budget_amount) as budget, SUM(spendings.amount_spent) AS spending, SUM(donations.donation_amount) AS donation 
    FROM (((projects
    INNER JOIN tasks on tasks.project_id=projects.id)
    INNER JOIN spendings on spendings.task_id=tasks.id)
    INNER JOIN donations on donations.task_id=tasks.id)
    GROUP BY projects.id

有没有办法防止这种情况?

1 个答案:

答案 0 :(得分:1)

从SELECT列表(SUM)中删除聚合表达式,然后删除GROUP BY,返回每个表的主键/唯一标识符,以查看正在发生的情况。

我们将看到的是半笛卡尔乘积(或叉乘积),一个表中的多行与另一表中的多行匹配。 SQL规范将返回所有匹配项。


避免这种情况的一种方法是通过预先汇总结果然后进行联接来避免叉积。

例如:

SELECT p.id
     , p.name
     , IFNULL(b.budget,0)    AS budget
     , IFNULL(s.spending,0)  AS spending
     , IFNULL(d.donation,0)  AS donation 
  FROM projects p
  LEFT
  JOIN ( SELECT bt.project_id
              , SUM(bt.budget_amount) AS budget
           FROM tasks bt
         GROUP BY bt.project_id 
       ) b
    ON b.project_id = p.id
  LEFT
  JOIN ( SELECT st.project_id
              , SUM(ss.amount_spent) AS spending
           FROM tasks st
           JOIN spendings ss
             ON ss.task_id = st.id
          GROUP BY st.project_id
       ) s
    ON s.project_id = p.id
  LEFT
  JOIN ( SELECT dt.project_id
              , SUM(dd.donation_amount) AS donation
           FROM tasks dt
           JOIN donations dd
             ON dd.task_id = dt.id
          GROUP BY dt.project_id
       ) d
    ON d.project_id = p.id

请注意,每个内联视图dsb均保证返回唯一值project_id