【问题标题】:MySQL Joining multiple tables each with multiple rowsMySQL连接多个表,每个表都有多行
【发布时间】:2020-03-23 04:52:15
【问题描述】:

我的表(bar、baz)有 1 行或多行与另一个表(foo)相关。当我将 bar 和 baz 都加入 foo 时,我会得到每个表的每一行的结果。

http://sqlfiddle.com/#!9/1c13f2/1/0

CREATE TABLE foo (`id` int, `value` varchar(5));
INSERT INTO foo (`id`, `value`) VALUES
    (1, 'two'),
    (2, 'two'),
    (3, 'one');

CREATE TABLE bar (`id` int, `foo_id` int, `value` int);
INSERT INTO bar (`id`, `foo_id`, `value`) VALUES
    (1, 1, 1),
    (2, 1, 1),
    (3, 2, 1),
    (4, 2, 1),
    (5, 3, 1);

CREATE TABLE baz (`id` int, `foo_id` int, `value` int);
INSERT INTO baz (`id`, `foo_id`, `value`) VALUES
    (1, 1, 1),
    (2, 1, 1),
    (3, 2, 1),
    (4, 2, 1),
    (5, 3, 1);

查询:

SELECT foo.value, SUM(bar.value), SUM(baz.value)
FROM foo
JOIN bar ON bar.foo_id = foo.id
JOIN baz ON baz.foo_id = foo.id
GROUP BY foo.id

结果:

value   SUM(bar.value)  SUM(baz.value)
two     4               4
two     4               4
one     1               1

预期结果:

value   SUM(bar.value)  SUM(baz.value)
two     2               2
two     2               2
one     1               1

【问题讨论】:

    标签: mysql join mariadb


    【解决方案1】:

    结果是预期的行为,来自交叉(半笛卡尔)积,来自bar 的多行与来自baz 的多行匹配。

    为避免这种情况,我们可以预先聚合来自barbaz 的计数,然后进行连接。

    还要考虑,当bar 中有匹配的行但baz 中没有匹配的行时,预期的结果是什么。我们要从bar 返回总数吗?对于当前查询,我们不会从bar 得到总数。 (在示例数据中,考虑从baz 删除行 id=5 后查询将返回什么。)

    我会这样写查询:

    SELECT foo.value
         , IFNULL( r.tot_bar_value ,0) AS tot_bar_value
         , IFNULL( z.tot_baz_value ,0) AS tot_baz_value 
      FROM foo
      LEFT
      JOIN ( -- aggregate total from bar
             SELECT bar.foo_id 
                  , SUM(bar.value) AS tot_bar_value
               FROM bar
              GROUP BY bar.foo_id
           ) r
        ON r.foo_id = foo.id
      LEFT
      JOIN ( -- aggregate total from bar
             SELECT baz.foo_id 
                  , SUM(baz.value) AS tot_baz_value
               FROM baz
              GROUP BY baz.foo_id
           ) z
        ON z.foo_id = foo.id
    

    请注意,我们使用外连接来处理barbaz 中没有匹配行的情况。

    为了测试,我们可以单独运行括号内的 SELECT 查询,看看返回了什么。

    【讨论】:

    • 在 bar 或 baz 中不可能没有匹配的行 - 这是在其他地方强制执行的。我希望有一个比嵌套聚合更干净的实现,但如果没有,为了便于阅读,我可能会将其分解为单独的语句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多