GROUP_CONCAT的进阶使用

Posted shyの程序猿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GROUP_CONCAT的进阶使用相关的知识,希望对你有一定的参考价值。

当使用mysql中的GROUP_CONCAT函数合并多行数据时,我们可能需要去重或者排序这些数据。在本篇博客中,我将为您介绍如何使用GROUP_CONCAT函数进行去重和排序操作。

函数语法

group_concat([distinct] 字段名 [order by 排序字段 asc/desc] [separator '分隔符'])

1、去重

如果您想要合并的数据中存在重复值,那么您可能需要在使用GROUP_CONCAT函数时进行去重操作。MySQL中的GROUP_CONCAT函数支持使用DISTINCT关键字进行去重操作。

下面是一个示例,假设我们有一个名为students的表,其中包含每个学生的ID和其选修的课程:

+----+-----------+
| id | course    |
+----+-----------+
|  1 | Math      |
|  1 | English   |
|  2 | Science   |
|  2 | History   |
|  3 | Geography |
|  3 | Math      |
+----+-----------+

如果我们想要将每个学生的选修课程合并到一行中,并且去除重复的课程,可以使用GROUP_CONCAT函数的DISTINCT关键字。下面是一个示例查询:

SELECT id, GROUP_CONCAT(DISTINCT course) AS courses
FROM students
GROUP BY id;

这将返回以下结果:

+----+----------------------+
| id | courses              |
+----+----------------------+
|  1 | Math,English         |
|  2 | Science,History      |
|  3 | Geography,Math       |
+----+----------------------+

可以看到,每个学生的课程都被合并到一行中,并且去除了重复的课程。

2、排序

如果您想要合并的数据按照特定的顺序排列,那么您可能需要在使用GROUP_CONCAT函数时进行排序操作。MySQL中的GROUP_CONCAT函数支持使用ORDER BY子句进行排序操作。

下面是一个示例,假设我们有一个名为students的表,其中包含每个学生的ID和其选修的课程:

+----+-----------+
| id | course    |
+----+-----------+
|  1 | Math      |
|  1 | English   |
|  2 | Science   |
|  2 | History   |
|  3 | Geography |
+----+-----------+

如果我们想要将每个学生的选修课程合并到一行中,并且按照课程名称的字母顺序排序,可以使用GROUP_CONCAT函数的ORDER BY子句。下面是一个示例查询:

SELECT id, GROUP_CONCAT(course ORDER BY course ASC) AS courses
FROM students
GROUP BY id;

这将返回以下结果:

+----+----------------------+
| id | courses              |
+----+----------------------+
|  1 | English,Math         |
|  2 | History,Science      |
|  3 | Geography            |
+----+----------------------+

可以看到,每个学生的课程都被合并到一行中,并且按照课程名称的字母顺序排序。

3、连接符

GROUP_CONCAT函数还支持使用SEPARATOR关键字指定连接符,用于将合并结果中的每个值连接在一起。如果不指定连接符,默认使用逗号作为连接符。其中,SEPARATOR关键字用于指定连接符,str_val是要使用的连接符。
下面是一个示例,假设我们有一个名为students的表,其中包含每个学生的ID和其选修的课程:

+----+-----------+
| id | course    |
+----+-----------+
|  1 | Math      |
|  1 | English   |
|  2 | Science   |
|  2 | History   |
|  3 | Geography |
|  3 | Math      |
+----+-----------+

如果我们想要将每个学生的选修课程合并到一行中,并使用分号作为连接符,可以使用以下查询:

SELECT id, GROUP_CONCAT(course ORDER BY course ASC SEPARATOR ';') AS courses
FROM students
GROUP BY id;

这将返回以下结果:

+----+----------------------+
| id | courses              |
+----+----------------------+
|  1 | English;Math         |
|  2 | History;Science      |
|  3 | Geography;Math       |
+----+----------------------+

可以看到,每个学生的课程都被合并到一行中,并使用分号作为连接符将它们连接在一起。
需要注意的是,连接符只用于连接每个值,而不用于连接每个合并结果。如果您需要将每个合并结果之间连接起来,请使用其他MySQL函数或子查询来实现。

4、总结

在本篇博客中,我们学习了如何使用MySQL中的GROUP_CONCAT函数进行去重和排序操作。在进行数据合并时,去重和排序是常见的需求,使用GROUP_CONCAT函数可以非常方便地实现这些操作。

在进行去重操作时,我们可以使用GROUP_CONCAT函数的DISTINCT关键字来去除重复的数据。在进行排序操作时,我们可以使用GROUP_CONCAT函数的ORDER BY子句按照指定的顺序进行排序。

需要注意的是,如果要对合并的数据进行复杂的去重或排序操作,可能需要使用其他MySQL函数或子查询来实现。GROUP_CONCAT函数只支持对合并的数据进行简单的去重和排序操作。

希望本篇博客对您有所帮助,如有疑问或建议,请随时在评论区留言。

使用 MySQL 在不同字段上的多个 GROUP_CONCAT

【中文标题】使用 MySQL 在不同字段上的多个 GROUP_CONCAT【英文标题】:Multiple GROUP_CONCAT on different fields using MySQL 【发布时间】:2011-11-22 08:00:33 【问题描述】:

我有一个这样的查询:

SELECT product.id,
       GROUP_CONCAT(image.id) AS images_id,
       GROUP_CONCAT(image.title) AS images_title,
       GROUP_CONCAT(facet.id) AS facets_id
...
GROUP BY product.id

查询有效,但不如预期,因为如果我有一个具有 5 个面和 1 个图像的产品(假设一个 id=7 的图像),那么我会在“images_id”中得到类似的内容:“7,7,7,7,7” 如果我有 2 张图片(7 和 3),那么我会得到类似:"7,7,7,7,7,3,3,3,3,3" 在方面我得到类似:"8,7,6,5,4,8,7,6,5,4"

我认为 MySQL 正在对查询返回的不同行进行某种类型的联合,然后将所有内容连接起来。

我的预期结果是(最后一个例子):

images_id = "7,3" facets_id = "8,7,6,5,4"

我可以在 GROUP_CONCAT 中使用 DISTINCT 来获得它,但是我遇到了另一个问题: 如果我有两个具有相同标题的图像,其中一个被省略,然后我得到类似: images_id = "7,3,5" images_title = "Title7and3,Title5"

所以我错过了 images_id 和 images_title 之间的关系。

有人知道是否可以在 MySQL 中进行此查询吗?

也许我在没有任何实际好处的情况下使一切复杂化。 由于性能原因,我只尝试执行一个查询,但现在我不确定执行两个查询是否更快(例如一个用于选择构面,另一个用于图像)。

请说明您认为最好的解决方案是什么以及为什么。

谢谢!

【问题讨论】:

【参考方案1】:

只需添加DISTINCT

示例:GROUP_CONCAT(DISTINCT image.id) AS images_id

【讨论】:

我认为这需要扩展。 ' DISTINCT ' => GROUP_CONCAT(DISTINCT image.id) AS images_id 似乎不是 SQL 语法,MySQL 5.1 抛出语法错误。提问者没有提到任何编程语言,所以如果这个答案不是 SQL,则需要转换或解释。【参考方案2】:

您需要分别获取每个组:

SELECT
    p.id,
    images_id,
    images_title,
    facets_id,
    ...
FROM PRODUCT p
JOIN (SELECT product.id, GROUP_CONCAT(image.id) AS images_id
      FROM PRODUCT GROUP BY product.id) a on a.id = p.id
JOIN (SELECT product.id, GROUP_CONCAT(image.title) AS images_title
      FROM PRODUCT GROUP BY product.id) b on b.id = p.id
JOIN (SELECT product.id, GROUP_CONCAT(facet.id) AS facets_id
      FROM PRODUCT GROUP BY product.id) b on c.id = p.id
...

【讨论】:

我不太了解您的查询,但它看起来很复杂,我的意思是,我们需要为每个 concat 设置一个带有 group by 的子选择?看起来很慢,不是更快2个查询吗? @Enrique,这不是关于速度,而是关于正确性。如果我的代码不需要实际工作,我可以立即完成所有工作。 @Enrique,您不需要为每个组 concat 进行子选择,仅适用于与 p.id 匹配返回每个 p.id 超过 1 行的那些表。 好吧,我在我的问题中所说的,它是关于速度的,我试图在一个查询中选择所有内容,只是因为我想要表现出色。因为在不同的查询中选择我的所有数据对我来说要容易得多。但是 GROUP_CONCAT 变得如此困难,以至于我不确定我是否没有杀死 MySQL 而不是节省几毫秒。这就是我要求“最佳”解决方案的原因(以及您认为这是“最佳”解决方案的原因)。无论如何,我会测试你的查询,因为它真的很有趣,我从来没有做过这样的事情。 好吧,我无法调整您的查询来测试它,我的查询比我的问题中发布的要复杂得多。我将使用 2 查询解决方案。谢谢!【参考方案3】:

你可以只添加 DISTINCT 关键字,你会得到你想要的结果。

SELECT tb_mod.*, tb_van.*,
GROUP_CONCAT(DISTINCT tb_voil.vt_id) AS voil,
GROUP_CONCAT(DISTINCT tb_other.oa_id) AS other, 
GROUP_CONCAT(DISTINCT tb_ref.rp_id) AS referral
FROM cp_modules_record_tbl tb_mod 
LEFT JOIN cp_vane_police_tbl tb_van ON tb_van.mr_id= tb_mod.id
LEFT JOIN cp_mod_voilt_tbl tb_voil ON tb_voil.mr_id= tb_mod.id
LEFT JOIN cp_mod_otheraction_tbl tb_other ON tb_other.mr_id= tb_mod.id
LEFT JOIN cp_mod_referral_tbl tb_ref ON tb_ref.mr_id= tb_mod.id
WHERE tb_mod.mod_type = 2 GROUP BY tb_mod.id

【讨论】:

【参考方案4】:

如果问题是速度,那么简单地选择您需要的所有数据作为单独的行并在应用程序中进行分组可能会快得多,即:

SELECT product.id, image.id, image.title, facet.id

然后在应用程序中:

foreach row:
    push product_id onto list_of_product_ids
    push image_id onto list_of_image_ids
etc.

【讨论】:

以上是关于GROUP_CONCAT的进阶使用的主要内容,如果未能解决你的问题,请参考以下文章

mysql 的group_concat方法

mysql—group_concat函数

MYSQL中group_concat有长度限制!默认1024

mysql函数GROUP_CONCAT()

MYSQL中group_concat有长度限制!默认1024(转载)

如何使用 GROUP_CONCAT 正确地将 MySQL 查询转换为 MSSQL 查询