SQL分组文字排序聚合实现
作者:技术拾光时间:2026-06-13 08:24:07浏览:591
针对不同数据库实现分组内文字排序聚合功能,列出了Spark、Impala、Oracle、SQLServer、PostgreSQL、MySQL、SQLite、DuckDB、ClickHouse等产品的SQL语法差异,涵盖大数据、商业、开源、嵌入式及分析型数据库,并指出性能受架构影响,大模型时代无需死记硬背。
做数据处理的朋友应该都遇到过这种场景:需要对分组内的文字列做排序聚合,比如按价格高低把每个类别下的商品名字串起来,或者按成绩排好每个班级的学生名单。现在SQL数据库百花齐放,方言差异不小,为了方便查阅,这里整理了一份实测可跑的汇总,覆盖了常见的数据产品与平台。
假设一张销售表 `sales`,要展示每个类别下按价格排序的商品清单。
```sql
CREATE TABLE sales AS
SELECT 'Electronics' AS category, 'Laptop' AS product, 1000 AS price UNION ALL
SELECT 'Electronics', 'Mouse', 20 UNION ALL
SELECT 'Electronics', 'Keyboard', 80 UNION ALL
SELECT 'Furniture', 'Desk', 300 UNION ALL
SELECT 'Furniture', 'Chair', 150;
```
## 1. Spark
```sql
SELECT
category,
concat_ws(',',
TRANSFORM(
SORT_ARRAY(COLLECT_LIST(STRUCT(price, product))),
s -> s.product
)
) AS products_sorted
FROM sales
GROUP BY category;
```
## 2. Impala
```sql
SELECT
category,
regexp_replace(
group_concat(concat_ws('|', rn, product), ','),
'[0-9]+\\|',
''
) AS products_sorted
FROM (
SELECT
category,
product,
cast(row_number() OVER (PARTITION BY category ORDER BY price) AS STRING) AS rn
FROM sales
) t
GROUP BY category;
```
## 3. Oracle
```sql
select category, LISTAGG(product, ', ') WITHIN GROUP (ORDER BY price) AS product_sorted
from sales t
group by category
```
## 4. SQL Server
```sql
SELECT
category,
STRING_AGG(product, ', ') WITHIN GROUP (ORDER BY price) AS products_sorted
FROM sales
GROUP BY category;
```
## 5. PostgreSQL
```sql
SELECT
category,
string_agg(product, ', ' ORDER BY price) AS products_sorted
FROM sales
GROUP BY category;
```
## 6. MySQL
```sql
SELECT
category,
GROUP_CONCAT(product ORDER BY price SEPARATOR ',') AS products_sorted
FROM sales
GROUP BY category;
```
## 7. SQLite & DuckDB
```sql
SELECT
category,
string_agg(product, ', ' ORDER BY price) AS products_sorted,
group_concat(product, ', ' ORDER BY price DESC) AS products_sorted1
FROM sales
GROUP BY category;
```
## 8. ClickHouse
```sql
-- 方式一,利用子查询先行排序
SELECT
category,
arrayStringConcat(groupArray(product), ',') AS products_sorted
FROM (
SELECT category, product
FROM db_test.sales
ORDER BY category, price ASC
)
GROUP BY category;
-- 方式二,Lambda表达式
SELECT
category,
arrayStringConcat(
arrayMap(
x -> x.2, -- 提取元组的第二个元素,即 product
arraySort(
x -> x.1, -- 按元组的第一个元素(price)升序排序
groupArray((price, product))
)
),
','
) AS products_sorted
FROM db_test.sales
GROUP BY category;
```
## 总结
从上面的实现可以看出,不同生态的数据库对分组排序聚合的支持思路差异不小。
- **大数据体系**:Spark SQL 需要嵌套 `collect_list` + `sort_array` + `transform` + `concat_ws` 才能实现,逻辑绕,代码长;Impala 不支持在 `group_concat` 内直接 `order by`,得用子查询加 `row_number` 先排好序再正则替换,且只支持 2.3 以上版本。
- **商业数据库**:Oracle 的 `listagg...within group (order by)` 是最早也最经典的实现,后来 SQL Server 2017+ 也提供了 `string_agg...within group (order by)`,格式高度相似,很好记。
- **开源数据库**:PostgreSQL 直接用 `string_agg(expr, sep order by ...)`,MySQL 用 `group_concat(expr order by ... separator sep)`,与商业数据库的格式差异较大,需要额外记一下。
- **嵌入式数据库**:SQLite 和 DuckDB 都支持 `group_concat(expr, sep order by ...)` 或 `string_agg(expr, sep order by ...)`,格式与 PG 高度一致,可见 PG 的影响。SQLite 从 3.44.0 开始才支持带 `order by` 的版本,DuckDB 定位分析型,从最早版本就完整支持。
- **分析型数据库**:ClickHouse 早期相当复杂,要用子查询或 `arrayStringConcat` + `groupArray` + `arraySort` + `arrayMap` 等 Lambda 套路,类似 Spark 的写法;从 24.8 版本起支持 `groupConcat(sep)(expr ORDER BY ...)`,简化了不少,但语法仍保留自家特色。
- **国产信创数据库**:目前主要是兼容模式,比如达梦兼容 Oracle 可跑 `listagg`,海量 Vastbase 原生兼容 PostgreSQL 用 `string_agg`,暂时还没发展出独立的语法体系。
以上只记录了语法差异,实际性能会因为各产品架构设计不同而有较大差距。当然,如果数据量没到亿级,性能基本都能接受。
话说回来,现在大模型时代,死记硬背不同数据库的语法既费时间也没太大必要——只要描述一下场景,大模型直接就能生成完整的 SQL 语句。数据工程师真正需要掌握的是各类产品的特点和背景,这样面对新工具时,就能快速借助 AI 写出复杂逻辑的 SQL 了。
假设一张销售表 `sales`,要展示每个类别下按价格排序的商品清单。
```sql
CREATE TABLE sales AS
SELECT 'Electronics' AS category, 'Laptop' AS product, 1000 AS price UNION ALL
SELECT 'Electronics', 'Mouse', 20 UNION ALL
SELECT 'Electronics', 'Keyboard', 80 UNION ALL
SELECT 'Furniture', 'Desk', 300 UNION ALL
SELECT 'Furniture', 'Chair', 150;
```
## 1. Spark
```sql
SELECT
category,
concat_ws(',',
TRANSFORM(
SORT_ARRAY(COLLECT_LIST(STRUCT(price, product))),
s -> s.product
)
) AS products_sorted
FROM sales
GROUP BY category;
```
## 2. Impala
```sql
SELECT
category,
regexp_replace(
group_concat(concat_ws('|', rn, product), ','),
'[0-9]+\\|',
''
) AS products_sorted
FROM (
SELECT
category,
product,
cast(row_number() OVER (PARTITION BY category ORDER BY price) AS STRING) AS rn
FROM sales
) t
GROUP BY category;
```
## 3. Oracle
```sql
select category, LISTAGG(product, ', ') WITHIN GROUP (ORDER BY price) AS product_sorted
from sales t
group by category
```
## 4. SQL Server
```sql
SELECT
category,
STRING_AGG(product, ', ') WITHIN GROUP (ORDER BY price) AS products_sorted
FROM sales
GROUP BY category;
```
## 5. PostgreSQL
```sql
SELECT
category,
string_agg(product, ', ' ORDER BY price) AS products_sorted
FROM sales
GROUP BY category;
```
## 6. MySQL
```sql
SELECT
category,
GROUP_CONCAT(product ORDER BY price SEPARATOR ',') AS products_sorted
FROM sales
GROUP BY category;
```
## 7. SQLite & DuckDB
```sql
SELECT
category,
string_agg(product, ', ' ORDER BY price) AS products_sorted,
group_concat(product, ', ' ORDER BY price DESC) AS products_sorted1
FROM sales
GROUP BY category;
```
## 8. ClickHouse
```sql
-- 方式一,利用子查询先行排序
SELECT
category,
arrayStringConcat(groupArray(product), ',') AS products_sorted
FROM (
SELECT category, product
FROM db_test.sales
ORDER BY category, price ASC
)
GROUP BY category;
-- 方式二,Lambda表达式
SELECT
category,
arrayStringConcat(
arrayMap(
x -> x.2, -- 提取元组的第二个元素,即 product
arraySort(
x -> x.1, -- 按元组的第一个元素(price)升序排序
groupArray((price, product))
)
),
','
) AS products_sorted
FROM db_test.sales
GROUP BY category;
```
## 总结
从上面的实现可以看出,不同生态的数据库对分组排序聚合的支持思路差异不小。
- **大数据体系**:Spark SQL 需要嵌套 `collect_list` + `sort_array` + `transform` + `concat_ws` 才能实现,逻辑绕,代码长;Impala 不支持在 `group_concat` 内直接 `order by`,得用子查询加 `row_number` 先排好序再正则替换,且只支持 2.3 以上版本。
- **商业数据库**:Oracle 的 `listagg...within group (order by)` 是最早也最经典的实现,后来 SQL Server 2017+ 也提供了 `string_agg...within group (order by)`,格式高度相似,很好记。
- **开源数据库**:PostgreSQL 直接用 `string_agg(expr, sep order by ...)`,MySQL 用 `group_concat(expr order by ... separator sep)`,与商业数据库的格式差异较大,需要额外记一下。
- **嵌入式数据库**:SQLite 和 DuckDB 都支持 `group_concat(expr, sep order by ...)` 或 `string_agg(expr, sep order by ...)`,格式与 PG 高度一致,可见 PG 的影响。SQLite 从 3.44.0 开始才支持带 `order by` 的版本,DuckDB 定位分析型,从最早版本就完整支持。
- **分析型数据库**:ClickHouse 早期相当复杂,要用子查询或 `arrayStringConcat` + `groupArray` + `arraySort` + `arrayMap` 等 Lambda 套路,类似 Spark 的写法;从 24.8 版本起支持 `groupConcat(sep)(expr ORDER BY ...)`,简化了不少,但语法仍保留自家特色。
- **国产信创数据库**:目前主要是兼容模式,比如达梦兼容 Oracle 可跑 `listagg`,海量 Vastbase 原生兼容 PostgreSQL 用 `string_agg`,暂时还没发展出独立的语法体系。
以上只记录了语法差异,实际性能会因为各产品架构设计不同而有较大差距。当然,如果数据量没到亿级,性能基本都能接受。
话说回来,现在大模型时代,死记硬背不同数据库的语法既费时间也没太大必要——只要描述一下场景,大模型直接就能生成完整的 SQL 语句。数据工程师真正需要掌握的是各类产品的特点和背景,这样面对新工具时,就能快速借助 AI 写出复杂逻辑的 SQL 了。