Oracle兼容-函数-LISTAGG()函数


1. 语法

  1. LISTAGG ( [ { ALL | DISTINCT } ] measure_expr [ , 'delimiter' ] )
  2. [ WITHIN GROUP ( order_by_clause ) ]
  3. [ OVER query_partition_clause ]
  4. query_partition_clause := ( PARTITION BY column_name [,...] )

2. 定义和用法

参数说明:

  1. measure_expr 可以是列,常量或基于列的表达式。
  2. delimiter 分隔符,可以是 ‘’字符串文字数字浮点等。
  3. order_by_clause ORDER BY子句决定了列值被拼接的顺序。
  4. ALLDISTINCT 都未指定时,视为 ALL
  5. OVER query_partition_clause 不存在时,视为 聚合(AGGREGATE) 函数。反之,视为 分析(ANALYTIC) 函数。
  6. 目前不支持聚合类函数嵌套使用,例如:
  1. greatsql> SELECT listagg(sum(id)) FROM t1 GROUP BY id;
  2. ERROR 1111 (HY000): Invalid use of group function

3. Oracle兼容说明

  1. 在GreatSQL中的 LISTAGG() 函数语法参考 Oracle 19c 版本用法,与 Oracle 11r2 版本的 WITHIN GROUP 用法部分有差异。
  2. 目前尚未支持 LISTAGG OVERFLOW 语法,仍沿用GreatSQL中的 group_concat_max_len 选项限制方式。
  3. 分隔符 delimiter 目前只支持字符常量,不支持使用 session/global 设定或运算式(注意: 会将数字常量转换为字符常量,转换时可能会因浮点精度或格式问题,不一定如预期呈现,因此建议直接使用字符常量)。

4. 示例

说明:GreatSQL中返回结果顺序与Oracle顺序可能会因为使用字符集不同存在排序差异。

  1. -- 创建测试表,填充测试数据
  2. greatsql> CREATE TABLE plan1 (
  3. id int PRIMARY KEY,
  4. name VARCHAR(255)
  5. );
  6. greatsql> CREATE TABLE plandetail(
  7. id INT PRIMARY KEY,
  8. name VARCHAR(255),
  9. state INT,
  10. planid INT
  11. );
  12. greatsql> INSERT INTO plan1 VALUES(1,'计划一'), (2,'计划二'), (3,'计划三');
  13. greatsql> INSERT INTO plandetail VALUES(1,'明细一',0,1), (2,'明细2',1,1), (3,'明细3',1,1);
  14. greatsql> INSERT INTO plandetail VALUES(4,'明细一',0,2), (5,'明细2',0,2), (6,'明细3',1,2);
  15. greatsql> INSERT INTO plandetail VALUES(7,'明细一',1,3), (8,'明细2',1,3), (9,'明细3',1,3);

1. 分别测试 GROUP_CONCAT() 和 LISTAGG()

  1. greatsql> SELECT t1.name ,GROUP_CONCAT(t2.name ORDER BY planid ASC SEPARATOR ',') FROM plan1 t1
  2. LEFT JOIN plandetail t2
  3. ON t1.id = t2.planid
  4. GROUP BY t1.name;
  5. +-----------+---------------------------------------------------------+
  6. | name | GROUP_CONCAT(t2.name ORDER BY planid ASC SEPARATOR ',') |
  7. +-----------+---------------------------------------------------------+
  8. | 计划一 | 明细一,明细2,明细3 |
  9. | 计划三 | 明细一,明细2,明细3 |
  10. | 计划二 | 明细一,明细2,明细3 |
  11. +-----------+---------------------------------------------------------+
  12. greatsql> SELECT t1.name ,LISTAGG(t2.name,',') WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  13. LEFT JOIN plandetail t2
  14. ON t1.id = t2.planid
  15. GROUP BY t1.name;
  16. +-----------+-------------------------------------------------------------+
  17. | name | LISTAGG(t2.name,',') WITHIN GROUP (ORDER BY t2.planid ASC) |
  18. +-----------+-------------------------------------------------------------+
  19. | 计划一 | 明细一,明细2,明细3 |
  20. | 计划三 | 明细一,明细2,明细3 |
  21. | 计划二 | 明细一,明细2,明细3 |
  22. +-----------+-------------------------------------------------------------+
  23. greatsql> SELECT t1.name ,LISTAGG(t2.name,'') WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  24. LEFT JOIN plandetail t2
  25. ON t1.id = t2.planid
  26. GROUP BY t1.name;
  27. +-----------+------------------------------------------------------------+
  28. | name | LISTAGG(t2.name,'') WITHIN GROUP (ORDER BY t2.planid ASC) |
  29. +-----------+------------------------------------------------------------+
  30. | 计划一 | 明细一明细2明细3 |
  31. | 计划三 | 明细一明细2明细3 |
  32. | 计划二 | 明细一明细2明细3 |
  33. +-----------+------------------------------------------------------------+
  34. greatsql> SELECT t1.name ,LISTAGG(t2.name,':') WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  35. LEFT JOIN plandetail t2
  36. ON t1.id = t2.planid
  37. GROUP BY t1.name;
  38. +-----------+-------------------------------------------------------------+
  39. | name | LISTAGG(t2.name,':') WITHIN GROUP (ORDER BY t2.planid ASC) |
  40. +-----------+-------------------------------------------------------------+
  41. | 计划一 | 明细一:明细2:明细3 |
  42. | 计划三 | 明细一:明细2:明细3 |
  43. | 计划二 | 明细一:明细2:明细3 |
  44. +-----------+-------------------------------------------------------------+
  45. greatsql> SELECT t1.name ,LISTAGG(t2.name,'\'') WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  46. LEFT JOIN plandetail t2
  47. ON t1.id = t2.planid
  48. GROUP BY t1.name;
  49. +-----------+--------------------------------------------------------------+
  50. | name | LISTAGG(t2.name,'\'') WITHIN GROUP (ORDER BY t2.planid ASC) |
  51. +-----------+--------------------------------------------------------------+
  52. | 计划一 | 明细一'明细2'明细3 |
  53. | 计划三 | 明细一'明细2'明细3 |
  54. | 计划二 | 明细一'明细2'明细3 |
  55. +-----------+--------------------------------------------------------------+
  56. greatsql> SELECT t1.name ,LISTAGG(t2.name,1) WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  57. LEFT JOIN plandetail t2
  58. ON t1.id = t2.planid
  59. GROUP BY t1.name;
  60. +-----------+-----------------------------------------------------------+
  61. | name | LISTAGG(t2.name,1) WITHIN GROUP (ORDER BY t2.planid ASC) |
  62. +-----------+-----------------------------------------------------------+
  63. | 计划一 | 明细一1明细21明细3 |
  64. | 计划三 | 明细一1明细21明细3 |
  65. | 计划二 | 明细一1明细21明细3 |
  66. +-----------+-----------------------------------------------------------+
  67. greatsql> SELECT t1.name ,LISTAGG(t2.name,-1) WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  68. LEFT JOIN plandetail t2
  69. ON t1.id = t2.planid
  70. GROUP BY t1.name;
  71. +-----------+------------------------------------------------------------+
  72. | name | LISTAGG(t2.name,-1) WITHIN GROUP (ORDER BY t2.planid ASC) |
  73. +-----------+------------------------------------------------------------+
  74. | 计划一 | 明细一-1明细2-1明细3 |
  75. | 计划三 | 明细一-1明细2-1明细3 |
  76. | 计划二 | 明细一-1明细2-1明细3 |
  77. +-----------+------------------------------------------------------------+
  78. greatsql> SELECT t1.name ,LISTAGG(t2.name,1.0000000001) WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  79. LEFT JOIN plandetail t2
  80. ON t1.id = t2.planid
  81. GROUP BY t1.name;
  82. +-----------+----------------------------------------------------------------------+
  83. | name | LISTAGG(t2.name,1.0000000001) WITHIN GROUP (ORDER BY t2.planid ASC) |
  84. +-----------+----------------------------------------------------------------------+
  85. | 计划一 | 明细一1.0000000001明细21.0000000001明细3 |
  86. | 计划三 | 明细一1.0000000001明细21.0000000001明细3 |
  87. | 计划二 | 明细一1.0000000001明细21.0000000001明细3 |
  88. +-----------+----------------------------------------------------------------------+
  89. greatsql> SELECT t1.name ,LISTAGG(t2.name,-1.0000000001) WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  90. LEFT JOIN plandetail t2
  91. ON t1.id = t2.planid
  92. GROUP BY t1.name;
  93. +-----------+-----------------------------------------------------------------------+
  94. | name | LISTAGG(t2.name,-1.0000000001) WITHIN GROUP (ORDER BY t2.planid ASC) |
  95. +-----------+-----------------------------------------------------------------------+
  96. | 计划一 | 明细一-1.0000000001明细2-1.0000000001明细3 |
  97. | 计划三 | 明细一-1.0000000001明细2-1.0000000001明细3 |
  98. | 计划二 | 明细一-1.0000000001明细2-1.0000000001明细3 |
  99. +-----------+-----------------------------------------------------------------------+
  100. greatsql> SELECT t1.name ,LISTAGG(t2.name,'|分割|') WITHIN GROUP (ORDER BY t2.planid ASC) FROM plan1 t1
  101. LEFT JOIN plandetail t2
  102. ON t1.id = t2.planid
  103. GROUP BY t1.name;
  104. +-----------+--------------------------------------------------------------------+
  105. | name | LISTAGG(t2.name,'|分割|') WITHIN GROUP (ORDER BY t2.planid ASC) |
  106. +-----------+--------------------------------------------------------------------+
  107. | 计划一 | 明细一|分割|明细2|分割|明细3 |
  108. | 计划三 | 明细一|分割|明细2|分割|明细3 |
  109. | 计划二 | 明细一|分割|明细2|分割|明细3 |
  110. +-----------+--------------------------------------------------------------------+

2. 测试分析性查询

  1. -- 创建测试表,填充测试数据
  2. greatsql> CREATE TABLE p (population INT, nation CHAR(20), city CHAR(20));
  3. greatsql> INSERT INTO p VALUES (500, 'China','Guangzhou'),
  4. (1500, 'China','Shanghai'),
  5. (500, 'China','Beijing'),
  6. (1000, 'USA','New York'),
  7. (500, 'USA','Bostom'),
  8. (500, 'Japan','Tokyo');
  9. -- 测试LISTAGG over partition
  10. greatsql> SELECT
  11. nation, LISTAGG(p.city, ',') OVER (PARTITION BY nation ) la_a_city
  12. FROM p;
  13. +--------+----------------------------+
  14. | nation | la_a_city |
  15. +--------+----------------------------+
  16. | China | Guangzhou,Shanghai,Beijing |
  17. | China | Guangzhou,Shanghai,Beijing |
  18. | China | Guangzhou,Shanghai,Beijing |
  19. | Japan | Tokyo |
  20. | USA | New York,Bostom |
  21. | USA | New York,Bostom |
  22. +--------+----------------------------+
  23. greatsql> SELECT
  24. nation, city, LISTAGG(p.city, ',') OVER (PARTITION BY nation ) la_a_city
  25. FROM p;
  26. +--------+-----------+----------------------------+
  27. | nation | city | la_a_city |
  28. +--------+-----------+----------------------------+
  29. | China | Guangzhou | Guangzhou,Shanghai,Beijing |
  30. | China | Shanghai | Guangzhou,Shanghai,Beijing |
  31. | China | Beijing | Guangzhou,Shanghai,Beijing |
  32. | Japan | Tokyo | Tokyo |
  33. | USA | New York | New York,Bostom |
  34. | USA | Bostom | New York,Bostom |
  35. +--------+-----------+----------------------------+
  36. greatsql> SELECT
  37. nation, city, LISTAGG(p.city, ',') WITHIN GROUP (ORDER BY city ASC)
  38. OVER (PARTITION BY nation ) la_a_city
  39. FROM p;
  40. +--------+-----------+----------------------------+
  41. | nation | city | la_a_city |
  42. +--------+-----------+----------------------------+
  43. | China | Beijing | Beijing,Guangzhou,Shanghai |
  44. | China | Guangzhou | Beijing,Guangzhou,Shanghai |
  45. | China | Shanghai | Beijing,Guangzhou,Shanghai |
  46. | Japan | Tokyo | Tokyo |
  47. | USA | Bostom | Bostom,New York |
  48. | USA | New York | Bostom,New York |
  49. +--------+-----------+----------------------------+
  50. -- 测试其他分析型函数
  51. greatsql> SELECT
  52. SUM(population) OVER (PARTITION BY nation) population,
  53. LISTAGG(p.city, ',') OVER (PARTITION BY nation) la_a_city
  54. FROM p;
  55. +------------+----------------------------+
  56. | population | la_a_city |
  57. +------------+----------------------------+
  58. | 2500 | Guangzhou,Shanghai,Beijing |
  59. | 2500 | Guangzhou,Shanghai,Beijing |
  60. | 2500 | Guangzhou,Shanghai,Beijing |
  61. | 500 | Tokyo |
  62. | 1500 | New York,Bostom |
  63. | 1500 | New York,Bostom |
  64. +------------+----------------------------+
  65. greatsql> SELECT
  66. SUM(population) OVER (PARTITION BY nation) population,
  67. LISTAGG(p.city, ',') WITHIN GROUP (ORDER BY city ASC)
  68. OVER (PARTITION BY nation ) la_a_city
  69. FROM p;
  70. +------------+----------------------------+
  71. | population | la_a_city |
  72. +------------+----------------------------+
  73. | 2500 | Beijing,Guangzhou,Shanghai |
  74. | 2500 | Beijing,Guangzhou,Shanghai |
  75. | 2500 | Beijing,Guangzhou,Shanghai |
  76. | 500 | Tokyo |
  77. | 1500 | Bostom,New York |
  78. | 1500 | Bostom,New York |
  79. +------------+----------------------------+
  80. greatsql> SELECT
  81. SUM(population) OVER (PARTITION BY nation ORDER BY city ASC) population,
  82. LISTAGG(p.city, ',') OVER (PARTITION BY nation ) la_a_city
  83. FROM p;
  84. +------------+----------------------------+
  85. | population | la_a_city |
  86. +------------+----------------------------+
  87. | 500 | Beijing,Guangzhou,Shanghai |
  88. | 1000 | Beijing,Guangzhou,Shanghai |
  89. | 2500 | Beijing,Guangzhou,Shanghai |
  90. | 500 | Tokyo |
  91. | 500 | Bostom,New York |
  92. | 1500 | Bostom,New York |
  93. +------------+----------------------------+

问题反馈

联系我们

扫码关注微信公众号

greatsql-wx