我正在尝试找到一个sql来将逗号分隔的值拆分为一列中的单独列。我发现了几个类似的问题,但没有一个答案能够处理未来行中分离值增加的情况。在SQL中是不可能这样做的,PL / SQL是唯一的解决方案吗?
Example Data
col1
val1,val2,val3,val4...
valA,valB,valC
Expected output
col1 col2 col3 col4 .....
val1 val2 val3 val4 .....
valA valB valC null .....
注意:因此,如果当前行中的逗号分隔值的最大值为200,那么我可以在select子句中硬编码200个regexp_substr()函数,但是如果在将来添加205个逗号分隔值的新行怎么办?如何在sql中处理这个未来可能的情况。
答案 0 :(得分:1)
不要使用列 - 如果您需要将其转换为列,则在您用于从数据库中读取的任何客户端上动态执行此操作,并将结果作为查询中的行返回,并附带相关索引以指示它应该在哪一列。
在Oracle中有many, many ways分隔分隔字符串。
不使用正则表达式的是:
Oracle 11g R2架构设置:
CREATE TABLE data ( cols ) AS
SELECT 'col1' FROM DUAL UNION ALL
SELECT 'val1,val2,val3,val4' FROM DUAL UNION ALL
SELECT 'valA,valB,valC' FROM DUAL;
查询1 :
WITH bounds ( id, list, start_pos, end_pos, lvl ) AS (
SELECT ROWNUM,
cols,
1,
INSTR( cols, ',' ),
1
FROM data
UNION ALL
SELECT id,
list,
end_pos + 1,
INSTR( list, ',', end_pos + 1 ),
lvl + 1
FROM bounds
WHERE end_pos > 0
)
SELECT id,
SUBSTR(
list,
start_pos,
DECODE( end_pos, 0, LENGTH( list ) + 1, end_pos ) - start_pos
) AS item,
lvl,
MAX( lvl ) OVER () AS num_columns
FROM bounds
ORDER BY id, lvl
<强> Results 强>:
| ID | ITEM | LVL | NUM_COLUMNS |
|----|------|-----|-------------|
| 1 | col1 | 1 | 4 |
| 2 | val1 | 1 | 4 |
| 2 | val2 | 2 | 4 |
| 2 | val3 | 3 | 4 |
| 2 | val4 | 4 | 4 |
| 3 | valA | 1 | 4 |
| 3 | valB | 2 | 4 |
| 3 | valC | 3 | 4 |
查询2 :
如果要将输出转换为纯SQL中的行,则需要知道最大列数,如果这样做,则可以使用PIVOT
(这就是为什么,因为你似乎没有固定的最大值,我说要在行中输出它并在客户端中转换它:
WITH bounds ( id, list, start_pos, end_pos, lvl ) AS (
SELECT ROWNUM,
cols,
1,
INSTR( cols, ',' ),
1
FROM data
UNION ALL
SELECT id,
list,
end_pos + 1,
INSTR( list, ',', end_pos + 1 ),
lvl + 1
FROM bounds
WHERE end_pos > 0
),
items ( id, item, col ) AS (
SELECT id,
SUBSTR(
list,
start_pos,
DECODE( end_pos, 0, LENGTH( list ) + 1, end_pos ) - start_pos
),
lvl
FROM bounds
)
SELECT *
FROM items
PIVOT (
MAX( item ) FOR col IN (
1 AS col1,
2 AS col2,
3 AS col3,
4 AS col4
)
)
ORDER BY id
<强> Results 强>:
| ID | COL1 | COL2 | COL3 | COL4 |
|----|------|--------|--------|--------|
| 1 | col1 | (null) | (null) | (null) |
| 2 | val1 | val2 | val3 | val4 |
| 3 | valA | valB | valC | (null) |
如果最大列数发生变化,您可以通过更改末尾的PIVOT
部分并硬编码新的最大列数来轻松更新查询。
如果您不知道最大值并且必须在数据库中执行,那么您将需要使用PL / SQL生成dynamic query,但这不太可能是高效的。