TDengine 字符串函数 GROUP_CONCAT 用户手册

GROUP_CONCAT 函数用户手册

1. 函数概述

1.1 功能说明

GROUP_CONCAT 函数是一个聚合函数,用于将分组中的多行字符串值连接成一个字符串。它在需要将分组数据汇总为单个字符串表示时非常有用,例如将同一电表在不同时间点的状态信息合并展示。

核心特点

  • 属于聚合函数,配合 GROUP BY 使用
  • 支持多列字段连接
  • 支持自定义分隔符
  • 自动跳过 NULL 值

1.2 语法

sql 复制代码
GROUP_CONCAT(expr1 [, expr2, ..., exprN, separator])

1.3 参数说明

参数 类型 说明 是否必需
expr1, expr2, ... VARCHAR/NCHAR 要连接的字符串字段或表达式 必需(至少1个)
separator VARCHAR/NCHAR 分隔符,作为最后一个参数 必需

1.4 返回值

  • 类型:VARCHAR
  • 说明 :返回连接后的字符串,最大长度不超过 TSDB_MAX_FIELD_LEN
  • 如果所有输入值均为 NULL,则返回 NULL
  • 如果输入包含 NCHAR 类型,会自动进行字符集转换

1.5 适用版本

自 TDengine v3.3.8.0 开始支持

1.6 适用范围

  • ✅ 普通表
  • ✅ 超级表
  • ✅ 支持嵌套子查询
  • ✅ 可与 GROUP BY 结合使用

2. GROUP_CONCAT 与 CONCAT 的区别

2.1 核心差异对比

对比项 GROUP_CONCAT CONCAT
函数类型 聚合函数(Aggregate) 标量函数(Scalar)
作用范围 多行数据 → 单个结果 单行数据 → 单个结果
使用场景 分组汇总,将多行合并 行内字段拼接
GROUP BY 通常配合使用 不需要
NULL 处理 自动跳过 NULL 值 任何参数为 NULL 则返回 NULL
参数个数 至少2个(字段+分隔符) 2-8个
分隔符 最后一个参数作为分隔符 无分隔符(CONCAT_WS 支持)

2.2 示例对比

CONCAT - 单行字段拼接
sql 复制代码
-- 拼接单行的多个字段
SELECT CONCAT(location, '-', tbname) AS device_info
FROM meters
LIMIT 1;

-- 输出:
-- device_info
-- ===================
-- Beijing.Chaoyang-d1001
GROUP_CONCAT - 多行数据聚合
sql 复制代码
-- 将同一位置的所有电表名连接起来
SELECT 
    location,
    GROUP_CONCAT(tbname, ',') AS all_meters
FROM meters
GROUP BY location;

-- 输出:
-- location          | all_meters
-- =======================================
-- Beijing.Chaoyang  | d1001,d1002,d1003
-- Beijing.Haidian   | d2001,d2002

2.3 适用场景选择

场景 推荐函数 说明
单行多列拼接 CONCAT 如:姓+名、城市+区域
多行汇总 GROUP_CONCAT 如:同组数据合并显示
需要分隔符的单行拼接 CONCAT_WS 带分隔符的 CONCAT
需要分隔符的多行汇总 GROUP_CONCAT 带分隔符的聚合

3. 基础使用示例

3.1 智能电表表结构

sql 复制代码
-- 创建智能电表超级表
CREATE STABLE meters (
    ts TIMESTAMP,
    current FLOAT,
    voltage INT,
    phase FLOAT
) TAGS (
    groupid INT,
    location VARCHAR(64)
);

-- 创建子表
CREATE TABLE d1001 USING meters TAGS (1, 'Beijing.Chaoyang');
CREATE TABLE d1002 USING meters TAGS (1, 'Beijing.Chaoyang');
CREATE TABLE d1003 USING meters TAGS (1, 'Beijing.Haidian');
CREATE TABLE d1004 USING meters TAGS (2, 'Shanghai.Pudong');

-- 插入测试数据
INSERT INTO d1001 VALUES
    ('2024-01-15 00:00:00', 10.2, 220, 0.95),
    ('2024-01-15 12:00:00', 15.8, 219, 0.94);

INSERT INTO d1002 VALUES
    ('2024-01-15 00:00:00', 9.8, 221, 0.96),
    ('2024-01-15 12:00:00', 14.5, 220, 0.95);

3.2 简单字符串连接

sql 复制代码
-- 连接两个字符串字段
SELECT GROUP_CONCAT(location, tbname, '-') AS device_list
FROM (
    SELECT DISTINCT location, tbname FROM meters LIMIT 3
);

预期输出

复制代码
 device_list                              |
===========================================
 Beijing.Chaoyangd1001-Beijing.Chaoyangd1002-Beijing.Haiدياند1003 |

3.3 配合 GROUP BY 使用

sql 复制代码
-- 按区域分组,列出每个区域的所有电表
SELECT 
    SUBSTRING_INDEX(location, '.', 1) AS city,
    GROUP_CONCAT(tbname, ',') AS meter_list,
    COUNT(*) AS meter_count
FROM meters
GROUP BY city;

预期输出

复制代码
 city     | meter_list           | meter_count |
====================================================
 Beijing  | d1001,d1002,d1003    | 3           |
 Shanghai | d1004                | 1           |

4. 智能电表应用场景

场景 1:按区域汇总电表设备清单

业务需求:运维人员需要快速查看每个区域部署了哪些电表设备。

sql 复制代码
-- 按位置分组,列出所有电表编号
SELECT 
    location,
    COUNT(*) AS total_meters,
    GROUP_CONCAT(tbname, ', ') AS meter_ids
FROM meters
GROUP BY location
ORDER BY total_meters DESC;

预期输出

复制代码
 location          | total_meters | meter_ids        |
========================================================
 Beijing.Chaoyang  | 2            | d1001, d1002     |
 Beijing.Haidian   | 1            | d1003            |
 Shanghai.Pudong   | 1            | d1004            |

业务价值

  • 快速了解设备分布情况
  • 便于运维人员制定巡检计划
  • 支持设备清单导出

场景 2:多维度数据展示

业务需求:将电表的多个状态信息合并为一条记录便于展示。

sql 复制代码
-- 将电表的关键指标连接成摘要信息
SELECT 
    tbname,
    location,
    GROUP_CONCAT(
        CONCAT(
            TO_CHAR(ts, 'HH24:MI'),
            ':',
            CAST(current AS VARCHAR),
            'A'
        ),
        ' | '
    ) AS hourly_current_summary
FROM meters
WHERE ts >= '2024-01-15 00:00:00' 
  AND ts < '2024-01-15 06:00:00'
GROUP BY tbname, location
LIMIT 3;

预期输出

复制代码
 tbname | location          | hourly_current_summary        |
==================================================================
 d1001  | Beijing.Chaoyang  | 00:00:10.2A | 12:00:15.8A   |
 d1002  | Beijing.Chaoyang  | 00:00:9.8A | 12:00:14.5A    |

业务价值

  • 紧凑的数据展示
  • 便于移动端查看
  • 减少数据传输量

5. 与其他数据库的兼容性

5.1 MySQL 中的 GROUP_CONCAT

MySQL 原生支持 GROUP_CONCAT 函数,是该函数的标准实现。

MySQL 语法
sql 复制代码
GROUP_CONCAT([DISTINCT] expr [,expr ...]
             [ORDER BY {unsigned_integer | col_name | expr}
                 [ASC | DESC] [,col_name ...]]
             [SEPARATOR str_val])
MySQL 特有功能
  1. DISTINCT 去重
sql 复制代码
-- MySQL 支持
SELECT dept, GROUP_CONCAT(DISTINCT name SEPARATOR ', ')
FROM employees
GROUP BY dept;
  1. ORDER BY 排序
sql 复制代码
-- MySQL 支持
SELECT dept, GROUP_CONCAT(name ORDER BY salary DESC SEPARATOR ', ')
FROM employees
GROUP BY dept;
  1. 自定义分隔符(可选)
sql 复制代码
-- MySQL 分隔符可选,默认为逗号
SELECT GROUP_CONCAT(name SEPARATOR ' | ') FROM users;
SELECT GROUP_CONCAT(name) FROM users;  -- 默认用逗号
  1. 长度限制
  • group_concat_max_len 系统变量控制
  • 默认 1024 字节,可动态调整
sql 复制代码
SET SESSION group_concat_max_len = 10000;
MySQL 示例
sql 复制代码
-- MySQL 完整示例
SELECT 
    department,
    GROUP_CONCAT(
        DISTINCT employee_name 
        ORDER BY salary DESC 
        SEPARATOR ' | '
    ) AS top_employees
FROM employees
WHERE salary > 5000
GROUP BY department;

5.2 PostgreSQL 中的 STRING_AGG

PostgreSQL 不支持 GROUP_CONCAT,但提供了功能相似的 STRING_AGG 函数(SQL标准函数)。

PostgreSQL 语法
sql 复制代码
STRING_AGG(expression, delimiter [ORDER BY ...])
PostgreSQL 特点
  1. 必须指定分隔符
sql 复制代码
-- PostgreSQL (9.0+)
SELECT dept, STRING_AGG(name, ', ' ORDER BY name)
FROM employees
GROUP BY dept;
  1. 支持 ORDER BY
sql 复制代码
SELECT STRING_AGG(name, ', ' ORDER BY salary DESC)
FROM employees;
  1. 支持 DISTINCT(PostgreSQL 9.0+)
sql 复制代码
SELECT STRING_AGG(DISTINCT city, ', ')
FROM customers;
  1. 无长度限制(除了内存限制)
PostgreSQL 替代方案
sql 复制代码
-- 使用 ARRAY_AGG + ARRAY_TO_STRING
SELECT ARRAY_TO_STRING(ARRAY_AGG(name ORDER BY name), ', ')
FROM employees;

5.3 TDengine vs MySQL vs PostgreSQL

特性 TDengine MySQL PostgreSQL
函数名 GROUP_CONCAT GROUP_CONCAT STRING_AGG
分隔符 必需(最后参数) 可选(SEPARATOR) 必需
DISTINCT ❌ 不支持 ✅ 支持 ✅ 支持
ORDER BY ❌ 不支持 ✅ 支持 ✅ 支持
长度限制 TSDB_MAX_FIELD_LEN group_concat_max_len 无限制
版本 v3.3.8.0+ 原生支持 9.0+ (STRING_AGG)
NULL 处理 跳过 跳过 跳过
多列连接 ✅ 支持 ✅ 支持 ❌ 单列(需嵌套)

5.4 跨数据库迁移建议

从 MySQL 迁移到 TDengine
sql 复制代码
-- MySQL 原始查询
SELECT GROUP_CONCAT(DISTINCT name ORDER BY name SEPARATOR '|')
FROM users;

-- TDengine 等效查询(需要调整)
SELECT GROUP_CONCAT(name, '|')
FROM (SELECT DISTINCT name FROM users ORDER BY name);

注意事项

  • ❌ TDengine 不支持 DISTINCTORDER BY 子句
  • ✅ 需要通过子查询实现去重和排序
  • ✅ 分隔符位置不同(TDengine 在最后)
从 PostgreSQL 迁移到 TDengine
sql 复制代码
-- PostgreSQL 原始查询
SELECT STRING_AGG(name, ', ' ORDER BY name)
FROM users;

-- TDengine 等效查询
SELECT GROUP_CONCAT(name, ', ')
FROM (SELECT name FROM users ORDER BY name);

注意事项

  • ✅ 函数名不同但语义相似
  • ✅ 分隔符参数位置调整
  • ✅ 排序需通过子查询实现

6. 使用注意事项

6.1 NULL 值处理

sql 复制代码
-- NULL 值会被自动跳过
CREATE TABLE test_null (ts TIMESTAMP, name VARCHAR(20));
INSERT INTO test_null VALUES 
    ('2024-01-01 00:00:00', 'A'),
    ('2024-01-01 00:00:01', NULL),
    ('2024-01-01 00:00:02', 'B');

SELECT GROUP_CONCAT(name, ',') FROM test_null;
-- 输出:A,B (NULL 被跳过)

6.2 去重需要使用子查询

sql 复制代码
-- ❌ 错误:TDengine 不支持 DISTINCT 直接用在 GROUP_CONCAT 中
SELECT GROUP_CONCAT(DISTINCT location, ',') FROM meters;

-- ✅ 正确:通过子查询去重
SELECT GROUP_CONCAT(location, ',')
FROM (SELECT DISTINCT location FROM meters);

6.3 字符集处理

sql 复制代码
-- 自动处理 NCHAR 和 VARCHAR 混合
SELECT GROUP_CONCAT(varchar_col, nchar_col, '-')
FROM mixed_charset_table;
-- 会自动进行字符集转换

6.4 结果长度限制

sql 复制代码
-- 注意:结果字符串不能超过 TSDB_MAX_FIELD_LEN
-- 对于大量数据,可能需要分批处理或使用 LIMIT
SELECT 
    location,
    GROUP_CONCAT(tbname, ',') AS meters
FROM meters
GROUP BY location
HAVING COUNT(*) < 1000;  -- 避免结果过长

6.5 分隔符必需性

sql 复制代码
-- ❌ 错误:缺少分隔符
SELECT GROUP_CONCAT(name) FROM users;

-- ✅ 正确:必须提供分隔符
SELECT GROUP_CONCAT(name, ',') FROM users;

7. 性能优化建议

7.1 限制分组大小

sql 复制代码
-- ✅ 推荐:对大表使用 WHERE 过滤
SELECT 
    location,
    GROUP_CONCAT(tbname, ',') AS meters
FROM meters
WHERE ts >= NOW - 1d  -- 限制时间范围
GROUP BY location;

7.2 避免过大的结果集

sql 复制代码
-- ✅ 使用 HAVING 限制组大小
SELECT 
    location,
    GROUP_CONCAT(tbname, ',') AS meters
FROM meters
GROUP BY location
HAVING COUNT(*) <= 100;  -- 限制每组记录数

7.3 合理使用子查询

sql 复制代码
-- ✅ 先过滤再聚合
SELECT 
    location,
    GROUP_CONCAT(tbname, '|') AS active_meters
FROM (
    SELECT DISTINCT location, tbname 
    FROM meters 
    WHERE groupid = 1
    LIMIT 1000
)
GROUP BY location;

8. 常见问题 FAQ

Q1: GROUP_CONCAT 和 CONCAT 有什么区别?

A:

  • CONCAT标量函数,用于单行内多个字段的拼接
  • GROUP_CONCAT聚合函数,用于多行数据的汇总连接
  • CONCAT 不需要 GROUP BY,GROUP_CONCAT 通常配合 GROUP BY 使用

Q2: 如何实现 MySQL 的 DISTINCT 和 ORDER BY 功能?

A: 通过子查询实现:

sql 复制代码
-- 去重 + 排序
SELECT GROUP_CONCAT(name, ',')
FROM (
    SELECT DISTINCT name 
    FROM users 
    ORDER BY name
);

Q3: 分隔符可以省略吗?

A : 不可以。TDengine 的 GROUP_CONCAT 必须提供分隔符作为最后一个参数,这与 MySQL 不同。

Q4: 如何处理结果字符串过长的情况?

A:

  1. 使用 LIMIT 限制输入行数
  2. 使用 HAVING 过滤大组
  3. 缩短分隔符长度
  4. 分批查询

Q5: 能否连接数值类型字段?

A: 需要先转换为字符串类型:

sql 复制代码
SELECT GROUP_CONCAT(CAST(id AS VARCHAR), ',')
FROM users;

Q6: COUNT(DISTINCT ...) 不支持怎么办?

A: 使用子查询实现:

sql 复制代码
-- ❌ 不支持
SELECT COUNT(DISTINCT tbname) FROM meters;

-- ✅ 使用子查询
SELECT COUNT(*) FROM (SELECT DISTINCT tbname FROM meters);

Q7: PostgreSQL 用户如何适应 TDengine?

A:

  • STRING_AGG 改为 GROUP_CONCAT
  • 分隔符参数移到最后
  • 通过子查询实现排序

Q8: 空字符串和 NULL 有什么区别?

A:

  • NULL 值会被跳过,不影响结果
  • 空字符串 '' 会被保留,参与连接

Q9: 可以连接多少个字段?

A: 理论上没有字段数量限制,但要注意:

  • 总结果长度不能超过 TSDB_MAX_FIELD_LEN
  • 字段越多,性能可能下降

9. 相关函数

函数 类型 说明 关系
CONCAT 标量函数 单行多列拼接 行级操作,不聚合
CONCAT_WS 标量函数 带分隔符的单行拼接 类似 CONCAT
GROUP_CONCAT 聚合函数 多行汇总连接 分组聚合
STRING_AGG 聚合函数(PG) PostgreSQL 等效函数 功能相似

文档版本 :v3.3.8.0
最后更新 :2024-01-15
适用场景:智能电表数据分析、设备清单汇总、多行数据展示

重要提示

  • TDengine 不支持 WITH 子句(CTE)
  • TDengine 的 COUNT 函数不支持 DISTINCT,需使用子查询实现
  • GROUP_CONCAT 必须提供分隔符参数

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
rchmin43 分钟前
阿里Canal数据库增量日志解析工具介绍
数据库·mysql
断春风1 小时前
Java 集成 AI 大模型最佳实践:从零到一打造智能化后端
java·人工智能·ai
铅笔侠_小龙虾1 小时前
Java 模拟实现 Vue
java·开发语言·vue.js
淘源码d1 小时前
智慧工地企项一体化平台,Spring Cloud +UniApp 智慧工地源码,BIM+AI+物联网,施工全过程数字化智慧工地管理平台
java·人工智能·物联网·智慧工地·智慧工地源码·智慧工地app·数字工地
神算大模型APi--天枢6461 小时前
聚合模型 API 算力平台:前端开发的强劲助力
大数据·人工智能·科技·架构·gpu算力
·云扬·1 小时前
MongoDB分片集群部署与高可用测试实战指南
数据库·mongodb
谷粒.1 小时前
API测试全解析:从基础到性能压测
java·运维·网络·人工智能·python·测试工具·自动化
Jtti1 小时前
网站服务器首页正常但内页全部404是什么原因?
运维·服务器·数据库
月亮!1 小时前
敏捷开发中测试左移的5个关键实践
java·人工智能·python·selenium·测试工具·测试用例·敏捷流程