惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
爱范儿
爱范儿
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家
有赞技术团队
有赞技术团队
美团技术团队
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Engineering at Meta
Engineering at Meta
T
Tailwind CSS Blog
J
Java Code Geeks
Martin Fowler
Martin Fowler
I
InfoQ
小众软件
小众软件
MongoDB | Blog
MongoDB | Blog

博客园 - 大汪的数据之路

外企的问卷调查 10 Tips On How To Be Exceptional In Anything You Do(在所做的任何事情上变得卓越的10个方法) 企业网络环境全景解析——面向AI智能数据分析场景的数据工程师指南 数据虚拟化技术解析:从概念到实践 数据虚拟化:从“搬运数据”到“连接数据”的范式革命 数据运维值班预警自动化 数据“搬砖”实战经验 星环大数据使用体验 vibe coding使用体验 基于SQL实现分组的文字排序聚合 数据码农马年大吉 BI报表及可视化分析类工具使用经验总结(下) BI报表及可视化分析类工具使用经验总结(上) 基于Python实现自动化微信通知和预警 Chat2DB测试体验 常用数据管理工具与平台汇总 OneID系统建设实践总结 网易有数BI使用总结 网易NDH大数据平台使用经验 版本管理总结 程序自动化vs人工手动处理 SQL开发总结 数据平台使用经验 数据团队运维值班任务简介 Python环境安装、管理与部署 windows获取kerberos认证 SQL动态长度行列转置 ODI Scenario 场景 Oracle KEEP 分析函数
字符串分割并展开成表格的SQL实现方法
大汪的数据之路 · 2026-01-20 · via 博客园 - 大汪的数据之路

一、场景案例

在数据开发类项目中,常常会遇到需要将字符串进行切割并展开成表格的场景,如以下两种常见的案例:

  1. 标签类型数据:如将员工标签类型的数据
    - 技能:Java、Spring、微服务、项目管理
    - 项目经验:电商、金融、教育
    - 工作风格:#执行力强 #跨部门协作 #数据驱动
  2. 分类层级数据:如将组织部门层级数据:“/集团/分公司/信息技术部/数据团队”

除此之外,在一些特定的业务场景中,如证券场景中,需要将一笔回购合约涉及到的多个质押券进行拆分(提取每个质押券有质押数量及对应标准券转换比例),数据示例如下:

image

 另外,API请求的返回的数据多为半结构化的字典列表数据,需要将每行数据从列表中进行提取出来再进行后续的处理,如以下数据:

{"data": [
   {
"AMOUNT":-9000,"SUB_TYPE_NAME":"债券分销","BRANCH_NAME":"银行间","TYPE_NAME":"收入","BUSI_DATE":"20250831","PROJECT_NAME":"调整1月分销佣金-24****MTN001"}, {"AMOUNT":-1075.61,"SUB_TYPE_NAME":"债券分销","BRANCH_NAME":"银行间","TYPE_NAME":"收入","BUSI_DATE":"20250531","PROJECT_NAME":"调整计提1月及3月分销佣金"} ], "success":true }

二,各类主流SQL方言实现方法

针对这类场景,目前没有标准SQL函数支持实现该功能。各类SQL方言通过自定义方法进行支持,以下是常用的实现方法。

Spark/Hive SQL

采用split + explode(及升级版posexplode)。以下为测试案例:

0

 利用该方法可以轻松的回购质押券进行拆分处理:

image

PostgreSQL

有两种方法:

方法一:首先利用string_to_array将字符串切割成数组,然后利用unnest将数组扩展成表

image

方法二:直接利用regexp_split_to_table将字符串切割并转换成表

image

select string_to_array('apple,banana,orange', ',') as item;
select string_to_array('apple|banana|orange', '|') as item;
select unnest(string_to_array('apple,banana,orange', ',')) as item;

select regexp_split_to_array('apple|banana|orange', '\|') as item;
select regexp_split_to_table('apple|banana|orange', '\|') as item;

View Code

Oracle

利用connect by + Level来实现

0

WITH CTE_DATA AS (
    SELECT 'tom' AS NAME, 'apple,banana,cherry' AS FRUIT FROM DUAL
)
SELECT NAME, REGEXP_SUBSTR(FRUIT, '[^,]+', 1, LEVEL) AS FRUIT
FROM CTE_DATA
CONNECT BY REGEXP_SUBSTR(FRUIT, '[^,]+', 1, LEVEL) IS NOT NULL
;

View Code

MySQL

5.x+版本只能使用数字辅助表+SUBSTRING_INDEX。

image

CREATE TABLE IF NOT EXISTS numbers (n INT PRIMARY KEY);
INSERT INTO numbers
SELECT a.N + b.N * 10 + c.N * 100 + 1 AS n
FROM (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) a
CROSS JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) b
CROSS JOIN (SELECT 0 AS N UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) c;
-- 使用数字表分割
SELECT
SUBSTRING_INDEX(
SUBSTRING_INDEX('a,b,c,d', ',', numbers.n),
',',
-1
) AS part
FROM numbers
WHERE numbers.n <= LENGTH('a,b,c,d') - LENGTH(REPLACE('a,b,c,d', ',', '')) + 1;

View Code

8.0+版本可使用json_table

SELECT 
    o.order_id,
    j.product_id
FROM orders o
JOIN JSON_TABLE(
    CONCAT('["', REPLACE(o.product_ids, ',', '","'), '"]'),
    '$[*]' COLUMNS (product_id INT PATH '$')
) AS j;

SQL Server

早期版本无内置函数,只能通过自定义表值函数(TVF)或者XML方法

CREATE FUNCTION dbo.SplitString
(
    @String NVARCHAR(MAX),
    @Delimiter CHAR(1)
)
RETURNS @Results TABLE 
(
    ID INT IDENTITY(1,1),
    Value NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE @pos INT = 0
    DECLARE @slice NVARCHAR(MAX)

    IF RIGHT(@String, 1) != @Delimiter
        SET @String = @String + @Delimiter

    WHILE CHARINDEX(@Delimiter, @String) > 0
    BEGIN
        SET @pos = CHARINDEX(@Delimiter, @String)
        SET @slice = LEFT(@String, @pos - 1)
        
        INSERT INTO @Results (Value) VALUES (@slice)
        SET @String = STUFF(@String, 1, @pos, '')
    END
    
    RETURN
END

-- 使用示例
SELECT * FROM dbo.SplitString('张三,李四,王五', ',')

View Code

DECLARE @str NVARCHAR(100) = '苹果|香蕉|橙子';
DECLARE @separator CHAR(1) = '|';

SELECT 
    LTRIM(RTRIM(m.n.value('.[1]', 'NVARCHAR(100)'))) AS SplitValue
FROM 
    (SELECT CAST('<x>' + REPLACE(@str, @separator, '</x><x>') + '</x>' AS XML)) AS t(x)
CROSS APPLY 
    x.nodes('/x') AS m(n);

View Code

2016之后的版本可使用原生方法STRING_SPLIT

--带序号的版本(SQL Server 2022+)
SELECT value, ordinal
FROM STRING_SPLIT('a,b,c', ',', 1) -- 第三个参数启用序号

三、结论

  Spark SQL、PostgreSQL最方便,思路也比较相似,都是先将字符串拆分数组,然后扩展成表。SQLServer新版本实现较为方法,直接一个函数搞定。Oracle利用其connect by来实现,也相对便捷,只是相对主流SQL方言比较小众一点。Mysql新版本相对方便一点,老版本需要辅助表增加维护成本。

四、参考链接