使用LEFT join避免在三个表中使用笛卡尔积

时间:2014-02-04 07:22:05

标签: mysql join

我有以下3个表: -

  1. 客户(customer_id,姓名)
  2. achived(achived_id,customer_id,achie)
  3. target(target_id,customer_id,target)
  4. 在编写以下查询时,由于笛卡尔积,我输出错误: -

    SELECT C.name customer, SUM(A.achieved) achived, SUM(T.target) target
    FROM customers C
    LEFT JOIN achieved A
    ON C.customer_id = A.customer_id
    LEFT JOIN target T
    ON C.customer_id = T.customer_id 
    GROUP BY customer
    

    使用LEFT join获得正确结果的正确方法是什么?

2 个答案:

答案 0 :(得分:0)

我理解,因为您要加入achievedtarget 加入customer,您将获得achieved无意义的笛卡尔积和target

您可以暂时删除SUM以查看问题的原因。 如果没有SUM,此查询会为您提供不必要的大型结果集。 使用 SUM时,重复的值都会对总和产生影响,从而创建一个大于预期的值。

您可以通过加入常量序列强制MySQL将连接的表分开,如下所示。

SELECT C.name customer, SUM(A.achieved) achieved, SUM(T.target) target

FROM customers C

# Split every customer into two rows, joinType=1 vs. joinType=2
LEFT JOIN (SELECT 1 AS joinItem UNION ALL SELECT 2) AS joinItems
ON TRUE

# Join achieved only where joinType=1 (will be NULL elsewhere)
LEFT JOIN achieved A
ON joinItem = 1 AND C.customer_id = A.customer_id

# Join target only where joinType=2 (will be NULL elsewhere)
LEFT JOIN target T
ON joinItem = 2 AND C.customer_id = T.customer_id 

GROUP BY customer

现在,已实现和目标将不再相互增加。

EXPLAIN应该确认这仍然有效处理。

注意:最初,这会为每个匹配的“已实现”(“目标”数据为NULL)创建一个客户记录,并为每个匹配的“目标”添加一个单独的客户记录(“已实现”数据为NULL)。然而,这个场景中的GROUP BY会将它们重新组合回每个客户的单个记录中,并且具有我们想要的数据。

答案 1 :(得分:-1)

您也可以试试这个......

SELECT C.name customer, SUM(A.achieved) achived, SUM(T.target) target
FROM customers C,achieved A,target T
WHERE C.customer_id = A.customer_id 
      AND C.customer_id = T.customer_id 
      AND A.customer_id = T.customer_id
GROUP BY C.customer