Oracle根据CSF列规则分组拼接Data列值的SQL查询方法
Oracle按CSF标记分组拼接Data字段实现方案
问题场景
Oracle数据库中存在一张业务表,包含CSF、ID、seqNum、Data、rs_id五个字段,样例数据如下:
| CSF | ID | seqNum | Data | rs_id |
|---|---|---|---|---|
| 1 | 14176159 | 1 | ABC | 0x000055.0001882a.017c |
| 1 | 14176160 | 2 | DEF | 0x000055.0001882c.0010 |
| 1 | 14176161 | 3 | GHI | 0x000055.0001882d.00ac |
| 1 | 14176162 | 4 | JKL | 0x000055.0001882d.0164 |
| 0 | 14176163 | 5 | MNO | 0x000055.0001882f.001c |
| 0 | 14176163 | 1 | ABC | 0x000055.0001882f.00d4 |
| 1 | 14176164 | 1 | ABC | 0x000055.00018830.0144 |
| 1 | 14176165 | 2 | DEF | 0x000055.00018831.0010 |
| 1 | 14176166 | 3 | GHI | 0x000055.00018832.00e4 |
| 1 | 14176166 | 4 | JKL | 0x000055.00018832.019c |
| 0 | 14176167 | 5 | MNO | 0x000055.00018834.001c |
需要编写SELECT语句得到如下查询结果:
| CSF | ID | seqNum | Data | rs_id |
|---|---|---|---|---|
| 0 | 14176159 | 5 | ABCDEFGHIJKLMNO | 0x000055.0001882f.001c |
| 0 | 14176163 | 1 | ABC | 0x000055.0001882f.00d4 |
| 0 | 14176164 | 5 | ABCDEFGHIJKLMNO | 0x000055.00018834.001c |
业务规则
查询逻辑需要满足以下要求:
- 遍历记录过程中,遇到
CSF=1的记录需持续拼接其Data列值,直到遇到CSF=0的记录时结束该组拼接 - 结果行的
ID取值为每组内第一条CSF=1的记录对应的ID值 - 结果行的
seqNum、rs_id取值为每组内CSF=0的记录对应字段值 - 无前置
CSF=1记录的独立CSF=0记录直接作为结果行返回,所有结果行的CSF值统一为0
核心逻辑:
CSF=1标识当前记录的Data列需要和后续同组记录拼接,CSF=0标识当前记录为分组结束节点,对应Data为拼接的最后一段,无需继续拆分。
实现方案
通过窗口函数给每条记录分配分组标识,再按组聚合即可实现需求,SQL语句如下:
WITH group_mark AS ( SELECT t.*, -- 累计当前行之前(含当前行)CSF=0的数量作为分组ID,同一拼接组的ID相同 COUNT(CASE WHEN CSF = 0 THEN 1 END) OVER ( ORDER BY ID, seqNum ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS gid, -- 取当前组第一条记录的ID FIRST_VALUE(ID) OVER (PARTITION BY gid ORDER BY ID, seqNum) AS group_first_id FROM 替换为你的实际业务表名 t ) SELECT 0 AS CSF, group_first_id AS ID, MAX(CASE WHEN CSF = 0 THEN seqNum END) AS seqNum, LISTAGG(Data, '') WITHIN GROUP (ORDER BY ID, seqNum) AS Data, MAX(CASE WHEN CSF = 0 THEN rs_id END) AS rs_id FROM group_mark GROUP BY gid, group_first_id ORDER BY gid;
逻辑说明
- 分组规则:每遇到一个
CSF=0的结束节点,后续记录的分组ID自动加1,刚好把两个结束节点之间的连续CSF=1记录和后面的结束节点分到同一组 - 独立
CSF=0记录会单独成组,组首ID就是自身ID,拼接时仅保留自身Data,符合规则要求 - 聚合阶段用
LISTAGG按遍历顺序拼接同组所有Data,提取结束节点的seqNum、rs_id,固定输出CSF=0即可。如果实际业务的遍历顺序不是按ID,seqNum排序,替换ORDER BY后的字段即可。
内容的提问来源于stack exchange,提问作者Paritosh Shrivastava
相关产品推荐
相关产品推荐

