MySQL - GROUP_CONCAT 返回重复数据,不能使用 DISTINCT
Posted
技术标签:
【中文标题】MySQL - GROUP_CONCAT 返回重复数据,不能使用 DISTINCT【英文标题】:MySQL - GROUP_CONCAT returns duplicate data, can't use DISTINCT 【发布时间】:2014-06-20 11:41:48 【问题描述】:我有一个规范化的数据库,我正在尝试使用 JOIN 和 GROUP_CONCAT 从多个表中返回数据。
问题:行与 GROUP_CONCAT 重复。我不能使用 DISTINCT,因为某些数据(配料 mfr)确实需要复制。
这是我当前的查询和数据库结构 (SQL Fiddle):
SELECT recipe.*,
GROUP_CONCAT(recipe_detail.ingredient_id) AS iid,
GROUP_CONCAT(ingredient.name) AS iname,
GROUP_CONCAT(ingredient_mfr.abbr) AS mabbr,
GROUP_CONCAT(recipe_tag.name) AS tag
FROM recipe
LEFT JOIN recipe_detail
ON recipe.id = recipe_detail.recipe_id
LEFT JOIN ingredient
ON recipe_detail.ingredient_id = ingredient.id
LEFT JOIN ingredient_mfr
ON ingredient.mfr_id = ingredient_mfr.id
LEFT JOIN recipe_tagmap
ON recipe.id = recipe_tagmap.recipe_id
LEFT JOIN recipe_tag
ON recipe_tagmap.tag_id = recipe_tag.id
WHERE recipe.user_id = 1
GROUP BY recipe.id
recipe
+------------+------------+-----------+
| id | name | user_id |
+============+============+===========+
| 1 | Test123 | 1 |
+------------+------------+-----------+
| 2 | Test456 | 1 |
+------------+------------+-----------+
| 3 | Test789 | 1 |
+------------+------------+-----------+
recipe_detail
+------------+---------------+
| recipe_id | ingredient_id |
+============+===============+
| 1 | 193 |
+------------+---------------+
| 1 | 194 |
+------------+---------------+
| 2 | 16 |
+------------+---------------+
| 3 | 277 |
+------------+---------------+
ingredient
+------------+---------------+---------+
| id | name | mfr_id |
+============+===============+=========+
| 16 | Gin | 4 |
+------------+---------------+---------+
| 193 | Fig | 3 |
+------------+---------------+---------+
| 194 | Tea | 3 |
+------------+---------------+---------+
| 277 | Nut | 2 |
+------------+---------------+---------+
ingredient_mfr
+------------+------------+
| id | abbr |
+============+============+
| 2 | TFA |
+------------+------------+
| 3 | FA |
+------------+------------+
| 4 | LOR |
+------------+------------+
recipe_tag
+------------+------------+
| id | name |
+============+============+
| 1 | one |
+------------+------------+
| 2 | two |
+------------+------------+
| 3 | three |
+------------+------------+
| 4 | four |
+------------+------------+
| 5 | five |
+------------+------------+
| 6 | six |
+------------+------------+
| 7 | seven |
+------------+------------+
| 8 | eight |
+------------+------------+
| 9 | nine |
+------------+------------+
recipe_tagmap
+------------+---------------+---------+
| id | recipe_id | tag_id |
+============+===============+=========+
| 1 | 1 | 1 |
+------------+---------------+---------+
| 2 | 1 | 2 |
+------------+---------------+---------+
| 3 | 1 | 3 |
+------------+---------------+---------+
| 4 | 2 | 4 |
+------------+---------------+---------+
| 5 | 2 | 5 |
+------------+---------------+---------+
| 6 | 2 | 6 |
+------------+---------------+---------+
| 7 | 3 | 7 |
+------------+---------------+---------+
| 8 | 3 | 8 |
+------------+---------------+---------+
| 9 | 3 | 9 |
+------------+---------------+---------+
使用我当前的查询,我的结果如下所示:
+------+---------+--------------+----------- ----+---------------+------------------+
| id | name | iid | iname | mabbr | tag |
+======+=========+==============+================+===============+==================+
| 1 | Test123 | 193,193,193, | Fig, Fig, Fig, | FA, FA, FA, | one, two, three, |
| | | 194,194,194 | Tea, Tea, Tea | FA, FA, FA | one, two, three |
+------+---------+--------------+----------------+---------------+------------------+
| 2 | Test456 | 16,16,16 | Gin, Gin, Gin | LOR, LOR, LOR | four, five six |
+------+---------+--------------+----------------+---------------+------------------+
| 3 | Test789 | 277,277,277 | Nut, Nut, Nut | TFA, TFA, TFA | seven,eight,nine |
+------+---------+--------------+----------------+---------------+------------------+
我希望我的结果是什么样的:
+------+---------+--------------+----------- ----+---------------+------------------+
| id | name | iid | iname | mabbr | tag |
+======+=========+==============+================+===============+==================+
| 1 | Test123 | 193, 194 | Fig, Tea | FA, FA | one, two, three, |
+------+---------+--------------+----------------+---------------+------------------+
| 2 | Test456 | 16 | Gin | LOR | four, five six |
+------+---------+--------------+----------------+---------------+------------------+
| 3 | Test789 | 277 | Nut | TFA | seven,eight,nine |
+------+---------+--------------+----------------+---------------+------------------+
如您所见,多个标签的存在会导致成分数据重复。多种成分的存在会导致标签重复。我曾尝试使用 DISTINCT,但有时我会有多种成分,并且每种成分都会返回它自己的“mabbr”,这可能与其他成分相同(参见预期结果的第一行)。使用 DISTINCT,它只会返回该“mabbr”的一个实例。
我可以对查询进行更改以实现我想做的事情吗?
SQL Fiddle
【问题讨论】:
+1 提出了一个很好的问题,显示了您的起始数据,您尝试过的内容(呃,好吧,将来也请在这里),您面临的问题(以及你知道是什么原因造成的!),以及你想要的结果。 #sigh#我希望更多新用户会提出类似这样的问题... 感谢您的夸奖。我知道如果你有尽可能多的信息,你们会更容易回答。 【参考方案1】:您可以通过将tag
分组提取到它自己的子查询来解决此问题:
SELECT
recipe.*,
GROUP_CONCAT(recipe_detail.ingredient_id) AS iid,
GROUP_CONCAT(ingredient.name) AS iname,
GROUP_CONCAT(ingredient_mfr.abbr) AS mabbr,
(
SELECT GROUP_CONCAT(recipe_tag.name)
FROM recipe_tag
INNER JOIN recipe_tagmap
ON recipe_tagmap.tag_id = recipe_tag.id
WHERE recipe_tagmap.recipe_id = recipe.id
) AS tag
FROM recipe
LEFT JOIN recipe_detail
ON recipe.id = recipe_detail.recipe_id
LEFT JOIN ingredient
ON recipe_detail.ingredient_id = ingredient.id
LEFT JOIN ingredient_mfr
ON ingredient.mfr_id = ingredient_mfr.id
WHERE recipe.user_id = 1
GROUP BY recipe.id
(例如fiddle)
【讨论】:
在您的示例中,mabbr 的重复次数仍然超过应有的次数。 +1 以获得有效的答案。我已经为您从链接中提取了它,否则它应该被删除,特别是它确实 NOT 符合您的回答。我已经更新了子查询中使用的JOIN
,以匹配优化器实际提供给您的内容。请注意,对于大型结果集,将tag2
子查询(的修改版本)作为表引用而不是在SELECT
列表中可能更有效。【参考方案2】:
在执行 GROUP_CONCAT 时添加 distinct 将为您提供唯一值。
SELECT recipe.*,
GROUP_CONCAT(distinct recipe_detail.ingredient_id) AS iid,
GROUP_CONCAT(distinct ingredient.name) AS iname,
GROUP_CONCAT(distinct ingredient_mfr.abbr) AS mabbr,
GROUP_CONCAT(distinct recipe_tag.name) AS tag
FROM recipe
LEFT JOIN recipe_detail
ON recipe.id = recipe_detail.recipe_id
LEFT JOIN ingredient
ON recipe_detail.ingredient_id = ingredient.id
LEFT JOIN ingredient_mfr
ON ingredient.mfr_id = ingredient_mfr.id
LEFT JOIN recipe_tagmap
ON recipe.id = recipe_tagmap.recipe_id
LEFT JOIN recipe_tag
ON recipe_tagmap.tag_id = recipe_tag.id
WHERE recipe.user_id = 1
GROUP BY recipe.id
SQL Fiddle
【讨论】:
正如 OP 所说,他不能使用 DISTINCT,因为必须复制某些值以上是关于MySQL - GROUP_CONCAT 返回重复数据,不能使用 DISTINCT的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL Server 中完成 MYSQL 的 Group_Concat [重复]