【问题标题】:Left Join query returns duplicatesLeft Join 查询返回重复项
【发布时间】:2013-08-03 14:08:46
【问题描述】:

我有添加剂表:

id   name
30   gro
31   micro
32   bloom
33   test

还有stage_additives表:

stage_id  additive_id   dose
195       30            2
195       31            3
195       32            1

Mysql查询:

SELECT a.id,
       a.name,
       sa.dose
FROM   additives a
LEFT JOIN stage_additives sa
ON     sa.stage_id = 195

结果是:

id name  dose
32 Bloom 2
32 Bloom 3
32 Bloom 1
30 Gro 2
30 Gro 3
30 Gro 1
31 Micro 2
31 Micro 3
31 Micro 1
33 test 2
33 test 3
33 test 1

这对我来说没有意义,因为即使每个表只有一个具有相同 ID/名称的项目,结果中的每个项目也有 3 个。

我也尝试过内连接,右连接,但结果几乎相同,除了顺序。

我想要的是所有 id、添加剂的名称和 stage_additives 的剂量(如果存在),否则为 NULL(或更好的自定义值 0)

【问题讨论】:

    标签: mysql sql left-join


    【解决方案1】:

    您在left join 中缺少条件:

    SELECT a.id,
           a.name,
           sa.dose
    FROM   additives a
    LEFT JOIN stage_additives sa
    ON     a.id = sa.additive_id and sa.stage_id = 195;
    

    请记住,join 在概念上是在两个表之间执行cross join,并且只获取与on 条件匹配的行(left join 也将所有行保留在第一个表中)。由于没有on 条件,连接将保留sa.stage_id = 195 所在的两个表中的所有行对——这是很多对。

    编辑:

    (响应将条件 sa.stage_id = 195 移动到 where 子句中。)

    条件sa.stage_id = 195 故意在on 子句中。这确保了left join 实际上的行为与所写的一样。如果将条件移至where 子句,则left join 将变为inner join。来自additive 且在stage_additive 中不匹配的行将具有sa.stage_idNULL 值并被过滤掉。我必须假设 OP 打算让 left join 将所有行保留在 additive 中,因为明确使用了 left join

    【讨论】:

    • 就是这样!我仍然很困惑,为什么我得到 3 个相同的项目,而不是 2 个或 4 个?
    • @DominicM 。 . .使用测试数据,我希望您得到 4 个输出行,additive 中的每一行一个。如果您将stage_id 上的条件移动到where 子句,那么您将获得3 行。
    • A JOIN 基本上是表的叉积。假设表 a 包含 (1),(2) 并且表 b 包含 (3),(4),(5) a JOIN b 将产生 6 行结果:(1,3), (1,4 ), (1,5), (2,3) (2,4) 和 (2,5)。即 3 倍 左表的值和 2 倍 右表的值。从概念上讲,ONWHERE 子句只是用于从该交叉产品中删除不需要的结果。
    【解决方案2】:

    in 子句ON 应该是WHERE 中stage_id 的表和条件之间的关系

    【讨论】:

      【解决方案3】:

      你可能想要类似的东西

      SELECT a.id,
             a.name,
             sa.dose
      FROM   additives a
      LEFT JOIN stage_additives sa 
                ON sa.additive_id = a.id
      WHERE  sa.stage_id = 195
      

      SQLFiddle:http://sqlfiddle.com/#!2/fd607/4

      在这种情况下,您可以使用INNER JOIN 而不是LEFT JOIN,因为WHERE 子句基于连接的成功。

      SELECT a.id,
             a.name,
             sa.dose
      FROM   additives a
      INNER JOIN stage_additives sa 
                 ON sa.additive_id = a.id AND sa.stage_id = 195
      

      SQLFiddle:http://sqlfiddle.com/#!2/fd607/8

      但也许你真的想要LEFT JOIN

      SELECT a.id,
             a.name,
             sa.dose
      FROM   additives a
      LEFT JOIN stage_additives sa
                ON sa.additive_id = a.id AND sa.stage_id = 195
      

      这将返回第四行:

      33  test    (null)
      

      SQLFiddle:http://sqlfiddle.com/#!2/fd607/7

      【讨论】:

      • Gordon Linoff 说条件应该在 ON 子句中而不是 WHERE 是正确的,因为我想要添加剂表中的所有行,而不管 stage_additives 是什么