我有一个类似的表(这里有9列带有';'。这是示例表):
create table mytable as (
select
1 ID,
'T1;T2;T3' column_1,
'B1;B5;B10;B13' column_2
from dual
union all
select
2 ID,
'T7;T8;T9;T10,T11',
'B2;B3;B5'
from dual
)
我需要目标表,例如:
ID column_1 column_2
1 T1 B1
1 T1 B5
1 T1 B10
1 T1 B13
1 T2 B1
1 T2 B5
1 T2 B10
1 T2 B13
1 T3 B1
1 T3 B5
1 T3 B10
1 T3 B13
2 T7 B2
2 T7 B3
2 T7 B5
2 T8 B2
2 T8 B3
2 T8 B5
2 T9 B2
2 T9 B3
2 T9 B5
2 T10 B2
2 T10 B3
2 T10 B5
2 T11 B2
2 T11 B3
2 T11 B5
我找到了以下链接: pipelined function with cursor parameter oracle,但我无法定期创建函数。我只为一列创建函数,但无法循环,也无法调用表。这是我的功能:
create or replace function fun_pipelined(i_str in varchar2)
RETURN sys.odcivarchar2list PIPELINED
IS
v_arr dbms_sql.varchar2_table;
v_i long;
v_cnt number;
i number;
begin
v_arr := pl.split(nvl(i_str,' ,'),',');
v_cnt := regexp_count(nvl(i_str,','), ',') + 1;
i := 1;
loop
exit when i > v_cnt;
v_i := trim(v_arr(i));
pipe row (v_i);
i := i+1;
end loop;
end;
能给我一些建议吗?谢谢
答案 0 :(得分:1)
答案 1 :(得分:0)
与Oracle的connect by相比,我更喜欢公用表表达式。这是使用CTE的结果。
WITH
mytable AS
(SELECT 1 id, 'T1;T2;T3' column_1, 'B1;B5;B10;B13' column_2 FROM DUAL
UNION ALL
SELECT 2 id, 'T7;T8;T9;T10;T11', 'B2;B3;B5' FROM DUAL),
mytable2 AS( SELECT id, column_1 || ';' AS column_1, column_2 || ';' AS column_2 FROM mytable ),
splitset1 ( id
, column_1
, column_2
, REMAINDER ) AS
(SELECT id
, SUBSTR( column_1
, 1
, INSTR( column_1, ';' ) - 1 ) AS column1
, column_2
, SUBSTR( column_1, INSTR( column_1, ';' ) + 1 ) AS REMAINDER
FROM mytable2
UNION ALL
SELECT id
, SUBSTR( REMAINDER
, 1
, INSTR( REMAINDER, ';' ) - 1 )
, column_2
, SUBSTR( REMAINDER, INSTR( REMAINDER, ';' ) + 1 )
FROM splitset1
WHERE REMAINDER IS NOT NULL),
splitset2 ( id
, column_1
, column_2
, REMAINDER ) AS
(SELECT id
, column_1
, SUBSTR( column_2
, 1
, INSTR( column_2, ';' ) - 1 ) AS column2
, SUBSTR( column_2, INSTR( column_2, ';' ) + 1 ) AS REMAINDER
FROM splitset1
UNION ALL
SELECT id
, column_1
, SUBSTR( REMAINDER
, 1
, INSTR( REMAINDER, ';' ) - 1 )
, SUBSTR( REMAINDER, INSTR( REMAINDER, ';' ) + 1 )
FROM splitset2
WHERE REMAINDER IS NOT NULL)
SELECT id
, column_1
, column_2
FROM splitset2
ORDER BY id
, CAST( SUBSTR( column_1, 2 ) AS NUMBER )
, CAST( SUBSTR( column_2, 2 ) AS NUMBER )
如果您拥有Oracle 12,则可以使用SQL函数使您的SQL可读性强,但会增加一些开销:
WITH
FUNCTION after( p_value IN VARCHAR2, p_separator IN VARCHAR2 DEFAULT ';' )
RETURN VARCHAR2 AS
l_pos INTEGER;
BEGIN
l_pos := INSTR( p_value, p_separator );
RETURN CASE WHEN l_pos > 0 THEN SUBSTR( p_value, l_pos + 1 ) ELSE NULL END;
END after;
FUNCTION before( p_value IN VARCHAR2, p_separator IN VARCHAR2 DEFAULT ';' )
RETURN VARCHAR2 AS
l_pos INTEGER;
BEGIN
l_pos := INSTR( p_value, p_separator );
RETURN CASE
WHEN l_pos > 0
THEN
SUBSTR( p_value
, 1
, l_pos - 1 )
ELSE
p_value
END;
END before;
mytable AS
(SELECT 1 id, 'T1;T2;T3' column_1, 'B1;B5;B10;B13' column_2 FROM DUAL
UNION ALL
SELECT 2 id, 'T7;T8;T9;T10;T11', 'B2;B3;B5' FROM DUAL),
mytable2 AS( SELECT id, column_1 || ';' AS column_1, column_2 || ';' AS column_2 FROM mytable ),
splitset1 ( id
, column_1
, column_2
, REMAINDER ) AS
(SELECT id
, before( column_1 ) AS column1
, column_2
, after( column_1 ) AS REMAINDER
FROM mytable2
UNION ALL
SELECT id
, before( REMAINDER )
, column_2
, after( REMAINDER )
FROM splitset1
WHERE REMAINDER IS NOT NULL),
splitset2 ( id
, column_1
, column_2
, REMAINDER ) AS
(SELECT id
, column_1
, before( column_2 ) AS column2
, after( column_2 ) AS REMAINDER
FROM splitset1
UNION ALL
SELECT id
, column_1
, before( REMAINDER )
, after( REMAINDER )
FROM splitset2
WHERE REMAINDER IS NOT NULL)
SELECT id
, column_1
, column_2
FROM splitset2
ORDER BY id
, CAST( SUBSTR( column_1, 2 ) AS NUMBER )
, CAST( SUBSTR( column_2, 2 ) AS NUMBER )