我有一个包含两列的表格,如下所示:
A001 A1;A2;A3
B002 B1
C003 C1;C2
D004 D1;D2;D3;D4
E005 E1
该表有两列,第二列包含单个值或多个值作为由分号分隔的字符串。
我想要做的是每个行的值是一个具有多个值的字符串,我想拆分字符串并使用每个值插入一个新行(复制第一列中的值为新行)。
使用上面的示例数据,输出将是这样的:
A001 A1
A001 A2
A001 A3
B002 B1
C003 C1
C003 C2
D004 D1
D004 D2
D004 D3
D004 D4
E005 E1
答案 0 :(得分:2)
select id, txt from table1
model partition by (id) dimension by (1 as n) measures (txt) (
txt[for n from regexp_count(txt[1], '[^;]+') to 1 decrement 1] =
regexp_substr(txt[1], '[^;]+', 1, cv(n))
)
order by id, n
答案 1 :(得分:1)
这是一个解决方案,我从另一个网站上获取了一些代码,但不记得是谁,然后对其进行了修改。我在临时表中添加了一些数据以显示它的工作原理
DECLARE @DATA TABLE (COL1 NVARCHAR(10), COL2 NVARCHAR(100))
DECLARE @RESULT TABLE (COL1 NVARCHAR(10),COL2 NVARCHAR(100))
DECLARE @COL1 NVARCHAR(10)
DECLARE @COL2 NVARCHAR(10)
INSERT INTO @DATA VALUES ( 'A001', 'A1;A2;A3')
INSERT INTO @DATA VALUES ( 'B002', 'B1')
INSERT INTO @DATA VALUES ( 'C003', 'C1;C2')
INSERT INTO @DATA VALUES ( 'D004', 'D1;D2;D3;D4')
INSERT INTO @DATA VALUES ( 'E005', 'E1')
DECLARE CURDB CURSOR FOR
SELECT *
FROM @DATA
OPEN CURDB
FETCH NEXT FROM CURDB
INTO @COL1, @COL2
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @S varchar(max),
@Split char(1),
@X xml
SELECT @S = @COL2,
@Split = ';'
SELECT @X = CONVERT(xml,'<root><s>' + REPLACE(@S,@Split,'</s><s>') + '</s></root>')
INSERT INTO @RESULT
SELECT @COL1,[Value] = T.c.value('.','varchar(20)')
FROM @X.nodes('/root/s') T(c)
FETCH NEXT FROM CURDB
INTO @COL1, @COL2
END
CLOSE CURDB;
DEALLOCATE CURDB;
SELECT *
FROM @RESULT
答案 2 :(得分:1)
with src as
(
select 'A001' col1, 'A1;A2;A3' col2 from dual union all
select 'B002', 'B1' from dual union all
select 'C003', 'C1;C2' from dual union all
select 'D004', 'D1;D2;D3;D4' from dual union all
select 'E005', 'E1' from dual
)
, explode as
(
select col1
, regexp_substr(col2, '\w+', 1, 1) as col2_1
, regexp_substr(col2, '\w+', 1, 2) as col2_2
, regexp_substr(col2, '\w+', 1, 3) as col2_3
, regexp_substr(col2, '\w+', 1, 4) as col2_4
-- if there is more add more...
from src
)
select col1, col2_1 from explode where col2_1 is not null union all
select col1, col2_2 from explode where col2_2 is not null union all
select col1, col2_3 from explode where col2_3 is not null union all
select col1, col2_4 from explode where col2_4 is not null
order by col1
;
结果:
/*
A001 A1
A001 A2
A001 A3
B002 B1
C003 C2
C003 C1
D004 D1
D004 D4
D004 D2
D004 D3
E005 E1
*/
答案 3 :(得分:1)
有很多方法可以将数据从行转换为列。
在这种情况下,您还需要将字符串拆分为不同的元素,我喜欢使用流水线函数:
SQL> CREATE OR REPLACE PACKAGE pkg AS
2 TYPE tab_varchar2 IS TABLE OF VARCHAR2(4000);
3 FUNCTION split_string (p VARCHAR2) RETURN tab_varchar2 PIPELINED;
4 END;
5 /
Package created
SQL> CREATE OR REPLACE PACKAGE BODY pkg AS
2 FUNCTION split_string (p VARCHAR2) RETURN tab_varchar2 PIPELINED IS
3 l_tail LONG := p;
4 l_separator NUMBER;
5 BEGIN
6 WHILE l_tail IS NOT NULL LOOP
7 l_separator := instr(l_tail, ';');
8 IF l_separator <= 0 THEN
9 PIPE ROW (l_tail);
10 l_tail := '';
11 ELSE
12 PIPE ROW (substr(l_tail, 1, l_separator - 1));
13 l_tail := substr(l_tail, l_separator + 1);
14 END IF;
15 END LOOP;
16 RETURN;
17 END split_string;
18 END;
19 /
Package body created
您使用横向联接查询数据:
SQL> WITH data AS (
2 SELECT 'A001' ID, 'A1;A2;A3' txt FROM dual UNION ALL
3 SELECT 'B002' ID, 'B1' txt FROM dual UNION ALL
4 SELECT 'C003' ID, 'C1;C2' txt FROM dual UNION ALL
5 SELECT 'D004' ID, 'D1;D2;D3;D4' txt FROM dual UNION ALL
6 SELECT 'E005' ID, 'E1' txt FROM dual
7 )
8 SELECT d.id, COLUMN_VALUE
9 FROM data d
10 CROSS JOIN TABLE(pkg.split_string(d.txt));
ID COLUMN_VALUE
------------ --------------------------------------------------
A001 A1
A001 A2
A001 A3
B002 B1
C003 C1
C003 C2
D004 D1
D004 D2
D004 D3
D004 D4
E005 E1
答案 4 :(得分:1)
可以使用以下查询转换行中的逗号分隔值
SELECT trim(x.column_value.extract('e/text()')) COLUMNS
from t t, table (xmlsequence(xmltype('<e><e>' || replace(valuestring,':','</e><e>')||
'</e></e>').extract('e/e'))) x );