SQL 聚合函数之字符串分组合并[通俗易懂]

SQL 聚合函数之字符串分组合并[通俗易懂]本文介绍了如何通过SQL函数对字符串进行聚合,也就是将多行字符串合并成单个字符串。包括Oracle(LISTAGG函数)、MySQL(GROUP_CONCAT函数)、SQLServer(STRING_AGG函数)、PostgreSQL(STRING_AGG函数)以及SQLite(GROUP_CONCAT函数)的语法和差异。

大家好,又见面了,我是你们的朋友全栈君。

大家好,我是只谈技术不剪发的 Tony 老师。

SQL 聚合函数(Aggregate Function)可以对一组数据进行汇总并返回单个结果。我们常见的聚合函数有 COUNT、AVG、SUM 等。今天给大家介绍一下如何通过 SQL 函数对字符串进行聚合,也就是将多行字符串合并成单个字符串。本文涉及的数据库包括 Oracle、MySQL、SQL Server、PostgreSQL 以及 SQLite。

如果觉得文章有用,欢迎评论?、点赞?、推荐?

Oracle 中的 LISTAGG 函数

Oracle 实现了 SQL:2016 标准中的 LISTAGG 函数,例如(示例数据)以下查询返回了每个部门中的员工:

SELECT dept_id, LISTAGG(emp_name, ';') 
FROM employee
GROUP BY dept_id;

DEPT_ID|LISTAGG(EMP_NAME,';')                    |
-------|-----------------------------------------|
      1|刘备;关羽;张飞                            |
      2|诸葛亮;黄忠;魏延                          |
      3|孙尚香;孙丫鬟                             |
      4|赵云;廖化;关平;赵氏;关兴;张苞;赵统;周仓;马岱|
      5|法正;庞统;蒋琬;黄权;糜竺;邓芝;简雍;孙乾    |

查询将每个部门中的多个员工姓名合并成了一行数据,多个姓名之间使用分号进行分隔。

如果想要在合并之前将员工进行排序,可以使用 WITHIN GROUP 选项。例如:

SELECT dept_id, LISTAGG(emp_name, ';') WITHIN GROUP (ORDER BY hire_date, salary DESC)
FROM employee
GROUP BY dept_id;

DEPT_ID|LISTAGG(EMP_NAME,';')WITHINGROUP(ORDERBYHIRE_DATE,SALARYDESC)              |
-------|---------------------------------------------------------------------------|
      1|刘备;关羽;张飞                                                              |
      2|诸葛亮;魏延;黄忠                                                            |
      3|孙尚香;孙丫鬟                                                               |
      4|赵云;廖化;周仓;关平;关兴;赵氏;赵统;张苞;马岱                                  |
      5|法正;庞统;蒋琬;黄权;糜竺;孙乾;邓芝;简雍                                      |

对于每个部门中的员工,首先按照入职日期进行排序,入职日期相同再按照月薪从高到低进行排序,然后将员工姓名进行合并。

除此之外,LISTAGG 函数还支持一些其他选项,完整的语法如下:

LISTAGG( [ ALL ] [ DISTINCT ] measure_expr [, 'delimiter'] [listagg_overflow_clause] )
  [ WITHIN GROUP ] (order_by_clause) [OVER query_partition_clause]

listagg_overflow_clause::=
{ ON OVERFLOW ERROR }
|
{ ON OVERFLOW TRUNCATE [ 'truncation-indicator' ] [ { WITH | WITHOUT } COUNT ] }

其中,DISTINCT 表示排除每个分组中的重复数据,ALL(默认值)表示使用全部数据;默认的分隔符为 NULL;listagg_overflow_clause 用于处理合并结果超长的情况,ON OVERFLOW ERROR(默认值)表示超长时返回错误,ON OVERFLOW TRUNCATE 表示超长时截断字符串;OVER 子句表示将该函数当作分析函数使用。

LISTAGG 函数忽略输入参数中的空值。如果想要了解 LISTAGG 函数的更多用法,可以参考 Oracle 官方文档

MySQL 中的 GROUP_CONCAT 函数

MySQL 提供了聚合字符串的 GROUP_CONCAT 函数,例如以下查询返回了每个部门中的员工:

SELECT dept_id, GROUP_CONCAT(emp_name SEPARATOR ';')
FROM employee
GROUP BY dept_id;

dept_id|GROUP_CONCAT(emp_name SEPARATOR ';')               |
-------|---------------------------------------------------|
      1|刘备;关羽;张飞                                      |
      2|诸葛亮;黄忠;魏延                                    |
      3|孙尚香;孙丫鬟                                       |
      4|赵云;廖化;关平;赵氏;关兴;张苞;赵统;周仓;马岱          |
      5|法正;庞统;蒋琬;黄权;糜竺;邓芝;简雍;孙乾              |

查询将每个部门中的多个员工姓名合并成了一行数据,多个姓名之间使用分号进行分隔。

如果想要在合并之前将员工进行排序,可以使用 ORDER BY 选项。例如:

SELECT dept_id, GROUP_CONCAT(emp_name ORDER BY hire_date, salary DESC SEPARATOR ';')
FROM employee
GROUP BY dept_id;

dept_id|GROUP_CONCAT(emp_name ORDER BY hire_date, salary DESC SEPARATOR ';')|
-------|--------------------------------------------------------------------|
      1|刘备;关羽;张飞                                                       |
      2|诸葛亮;魏延;黄忠                                                     |
      3|孙尚香;孙丫鬟                                                        |
      4|赵云;廖化;周仓;关平;关兴;赵氏;赵统;张苞;马岱                          |
      5|法正;庞统;蒋琬;黄权;糜竺;孙乾;邓芝;简雍                               |

对于每个部门中的员工,首先按照入职日期进行排序,入职日期相同再按照月薪从高到低进行排序,然后将员工姓名进行合并。

除此之外,GROUP_CONCAT 函数还支持一些其他选项,完整的语法如下:

GROUP_CONCAT([DISTINCT] expr [,expr ...]
             [ORDER BY {unsigned_integer | col_name | expr} [ASC | DESC] [,col_name ...]]
             [SEPARATOR str_val])

其中,DISTINCT 表示排除每个分组中的重复数据,默认表示使用全部数据;ORDER BY 表示聚合之前先排序;SEPARATOR 子句表用于指定分隔符,默认为逗号。

GROUP_CONCAT 函数忽略输入参数中的空值。如果 GROUP_CONCAT 函数返回的结果超过系统变量 group_concat_max_len 设置的长度,将会截断合并后的字符串。更多信息可以参考 MySQL 官方文档

SQL Server 中的 STRING_AGG 函数

SQL Server 2017 提供了字符串聚合函数:STRING_AGG。例如,以下查询返回了每个部门中的员工:

SELECT dept_id, STRING_AGG(emp_name, ';')
FROM employee
GROUP BY dept_id;

dept_id|                                         |
-------|-----------------------------------------|
      1|刘备;关羽;张飞                            |
      2|诸葛亮;黄忠;魏延                          |
      3|孙尚香;孙丫鬟                             |
      4|赵云;廖化;关平;赵氏;关兴;张苞;赵统;周仓;马岱|
      5|法正;庞统;蒋琬;黄权;糜竺;邓芝;简雍;孙乾     |

查询将每个部门中的多个员工姓名合并成了一行数据,多个姓名之间使用分号进行分隔。

如果想要在合并之前将员工进行排序,可以使用 WITHIN GROUP 选项。例如:

SELECT dept_id, STRING_AGG(emp_name, ';') WITHIN GROUP (ORDER BY hire_date, salary DESC)
FROM employee
GROUP BY dept_id;

dept_id|                                         |
-------|-----------------------------------------|
      1|刘备;关羽;张飞                            |
      2|诸葛亮;魏延;黄忠                          |
      3|孙尚香;孙丫鬟                             |
      4|赵云;廖化;周仓;关平;关兴;赵氏;赵统;张苞;马岱|
      5|法正;庞统;蒋琬;黄权;糜竺;孙乾;邓芝;简雍     |

对于每个部门中的员工,首先按照入职日期进行排序,入职日期相同再按照月薪从高到低进行排序,然后将员工姓名进行合并。

STRING_AGG 函数的完整语法如下:

STRING_AGG ( expression, separator ) [ <order_clause> ]

<order_clause> ::=   
    WITHIN GROUP ( ORDER BY <order_by_expression_list> [ ASC | DESC ] )

STRING_AGG 函数忽略输入参数中的空值。如果想要了解 STRING_AGG 函数的更多用法,可以参考 SQL Server 官方文档

PostgreSQL 中的 STRING_AGG 函数

PostgreSQL 实现了字符串聚合的 STRING_AGG 函数。例如,以下查询返回了每个部门中的员工:

SELECT dept_id, STRING_AGG(emp_name, ';')
FROM employee
GROUP BY dept_id;

dept_id|string_agg                               |
-------|-----------------------------------------|
      4|赵云;廖化;关平;赵氏;关兴;张苞;赵统;周仓;马岱|
      2|诸葛亮;黄忠;魏延                          |
      3|孙尚香;孙丫鬟                             |
      1|刘备;关羽;张飞                            |
      5|法正;庞统;蒋琬;黄权;糜竺;邓芝;简雍;孙乾     |

查询将每个部门中的多个员工姓名合并成了一行数据,多个姓名之间使用分号进行分隔。

如果想要在合并之前将员工进行排序,可以使用 ORDER BY 选项。例如:

SELECT dept_id, STRING_AGG(emp_name, ';' ORDER BY hire_date, salary DESC)
FROM employee
GROUP BY dept_id;

dept_id|string_agg                               |
-------|-----------------------------------------|
      1|刘备;关羽;张飞                            |
      2|诸葛亮;魏延;黄忠                          |
      3|孙尚香;孙丫鬟                             |
      4|赵云;廖化;周仓;关平;关兴;赵氏;赵统;张苞;马岱|
      5|法正;庞统;蒋琬;黄权;糜竺;孙乾;邓芝;简雍     |

对于每个部门中的员工,首先按照入职日期进行排序,入职日期相同再按照月薪从高到低进行排序,然后将员工姓名进行合并。

STRING_AGG 函数的完整语法如下:

STRING_AGG ( [ALL|DISTINCT] expression, separator [ORDER BY]) [ FILTER ( WHERE filter_clause ) ]

其中,DISTINCT 表示排除每个分组中的重复数据,ALL(默认值)表示使用全部数据;FILTER 子句用于指定一个过滤条件,只有满足条件的数据才会进行聚合。STRING_AGG 函数忽略输入参数中的空值。

关于聚合函数的详细介绍,可以参考 PostgreSQL 官方文档

SQLite 中的 GROUP_CONCAT 函数

SQLite 提供了实现字符串聚合的GROUP_CONCAT 函数。例如,以下查询返回了每个部门中的员工:

SELECT dept_id, GROUP_CONCAT(emp_name, ';')
FROM employee
GROUP BY dept_id;

dept_id|GROUP_CONCAT(emp_name, ';')               |
-------|------------------------------------------|
      1|刘备;关羽;张飞                             |
      2|诸葛亮;黄忠;魏延                           |
      3|孙尚香;孙丫鬟                              |
      4|赵云;廖化;关平;赵氏;关兴;张苞;赵统;周仓;马岱 |
      5|法正;庞统;蒋琬;黄权;糜竺;邓芝;简雍;孙乾     |

查询将每个部门中的多个员工姓名合并成了一行数据,多个姓名之间使用分号进行分隔。

如果不指定分隔符,GROUP_CONCAT 函数默认使用逗号进行分隔。GROUP_CONCAT 函数忽略输入参数中的空值。同时,该函数不支持分组内的数据排序,按照随意顺序进行字符串合并。

总结

本文介绍了 5 种主流数据库中的字符串聚合函数,使用时需要注意不同数据库中的参数差异。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/151853.html原文链接:https://javaforall.net

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • MySQL数据库面试题(2020最新版)

    MySQL数据库面试题(2020最新版)文章目录数据库基础知识为什么要使用数据库什么是SQL?什么是MySQL?数据库三大范式是什么mysql有关权限的表都有哪几个MySQL的binlog有有几种录入格式?分别有什么区别?数据类型mysql有哪些数据类型引擎MySQL存储引擎MyISAM与InnoDB区别MyISAM索引与InnoDB索引的区别?InnoDB引擎的4大特性存储引擎选择索引什么是索引?索引有哪些优缺点?索引使用场景(重点)…

    2022年6月13日
    18
  • Asp.net页面跳转的方法

    Asp.net页面跳转的方法Asp.net几种页面跳转的方法在asp.net下,经常需要页面的跳转,下面是具体的几种方法。跳转页面是大部编辑语言中都会有的,正面我们来分别介绍一下关于.net中response.redirectsever.executeserver.transfer三种页面跳转的方法①response.redirect(慢!但全能!)这个跳转页面的方法跳转的速度不快,因为它要走2个来回(2次postback),但他可以跳转到任何页面,没有站点页面限制(即可以由雅虎跳到新浪),同时不

    2022年7月20日
    14
  • FFmepg_ffmpeg下载

    FFmepg_ffmpeg下载FFMpeg0.6版源码下载:来自:http://sourceforge.net/projects/mplayer-win32/files/FFmpeg/FFmpeg-svn-24623.7zffmpeg-r24623.tar.bz2我收集到的相关开发资料:(均来自网络) FFMpeg中apiexample_c例子分析——解码分析.txtffmpeg初级教程.rarff

    2022年9月24日
    2
  • 电平转换实现简述_为什么要进行电平转换

    电平转换实现简述_为什么要进行电平转换电平转换实现简述1.前言2.BJT和mos实现3.二极管实现4.电阻实现1.前言在设计电路时,很多情况下会出现电平不匹配的情况,最常用的方式就是增加电平转换芯片。那自然就会想到其实现思想源自于哪?如果用分离器件搭,如何能实现?下图是SN74ALVC164245的逻辑框图,包含与门和反相器,与门主要实现使能和方向控制,反向器用来实现信号传输。2.BJT和mos实现以NPN的BJT和NMOS为例来说,集电极输出和漏极输出是最简单的反相器。只不过由于BJT和MOS本身的特性,BJT只能单向传输

    2022年8月10日
    12
  • Pytorch搭建ResNet18

    Pytorch搭建ResNet18ResNet代码importtorchimporttorchvisionimporttorch.nnasnnimporttorch.nn.functionalasFimportmatplotlib.pyplotaspltimportnumpyasnp#definestructureclassBasicBlock(nn.Module):def__init__(self,in_planes,planes,stride=1):

    2022年5月26日
    47
  • webstorm2021.11.4激活码[最新免费获取]

    (webstorm2021.11.4激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlF6EG2ZUBVX-eyJsaWNlbnNlSWQi…

    2022年3月28日
    53

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号