我更喜欢公用表表达式而不是 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 )