如何使用正确的 GROUP_CONCAT 数据加入多个 SQL table 和 return 每个基本 table 记录一行?

How do I join with multiple SQL tables and return one row per base table record with the correct GROUP_CONCAT data?

我有一种情况,我想加入多个 SQL table 并在基础 table 和 GROUP_CONCAT 中为每条记录取回一行其他 table 数据以及 |。不幸的是,使用我当前使用的查询方法,我在 GROUP_CONCAT 数据中返回了不需要的多重性,我不知道如何解决它。

我有以下基本数据库结构:

things
id | name
1  | Some Thing
2  | Some Other Thing

items
id | name
1  | Blob
2  | Starfish
3  | Wrench
4  | Stereo

users
id | name
1  | Alice
2  | Bill
3  | Charlie
4  | Daisy

things_items
thing_id | item_id
1        | 1
1        | 2
2        | 3
2        | 4

things_users
thing_id | user_id
1        | 1
1        | 2
1        | 3
2        | 4

理想情况下,我想编写一个查询,为 things table 中的 Some Thing 行返回以下内容:

Some Thing | Blob|Starfish | Alice|Bill|Charlie

但是,我得到的结果如下:

Some Thing | Blob|Blob|Blob|Starfish|Starfish|Starfish | Alice|Alice|Bill|Bill|Charlie|Charlie

这是我正在使用的查询:

SELECT things.name,
        GROUP_CONCAT(items.name SEPARATOR '|')
        GROUP_CONCAT(users.name SEPARATOR '|')
FROM things
    JOIN things_items ON things.id = things_items.thing_id
    JOIN items ON things_items.item_id = items.id
    JOIN things_users ON things.id = things_users.thing_id
    JOIN users ON things_items.user_id = users.id
GROUP BY things.id;

我应该如何更改查询以按照我想要的方式取回数据并避免 GROUP_CONCAT 数据相乘?谢谢。

您正在沿着两个不同的维度串联。最简单的解决方案是 DISTINCT:

SELECT t.name,
       GROUP_CONCAT(DISTINCT i.name SEPARATOR '|')
       GROUP_CONCAT(DISTINCT u.name SEPARATOR '|')
FROM things t JOIN
     things_items ti
     ON t.id = ti.thing_id JOIN
     items i
     ON ti.item_id = i.id JOIN
     things_users tu
     ON t.id = tu.thing_id JOIN
     users u
     ON tu.user_id = u.id
GROUP BY t.id;

请注意,以上过滤掉了没有项目或没有用户的东西。

如果每个事物都有少量项目和用户,则上述方法可以正常工作。随着数字的增长,性能会变差,因为它会为每个事物生成笛卡尔积。

加入前聚合即可解决:

SELECT t.name, i.items, u.users
FROM things t JOIN
     (SELECT ti.thing_id, GROUP_CONCAT(i.name SEPARATOR '|') as items
      FROM things_items ti JOIN
           items i
           ON ti.item_id = i.id
      GROUP BY ti.thing_id
     ) i
     ON t.id = ti.thing_id JOIN         
     (SELECT tu.user_id, GROUP_CONCAT(DISTINCT u.name SEPARATOR '|') as users
      FROM things_users tu JOIN
           users u
           ON tu.user_id = u.id
      GROUP BY tu.user_id
     ) tu
      ON t.id = tu.thing_id ;

如果你想要所有的东西,甚至那些没有物品或名字的东西,你可以用 LEFT JOIN 替换外面的 JOIN