Oracle 不支持前瞻组和非捕获组,因此您需要匹配引号。
假设您可以使用不带引号的字符串或带引号的字符串(可能包含转义引号),那么您可以使用正则表达式:
([^",]*|"(\\"|[^"])*"),
你可以这样使用:
WITH matches ( id, csv, start_pos, comma_pos, idx, num_matches ) AS (
SELECT id,
csv,
1,
REGEXP_INSTR( csv, '([^",]*|"(\\"|[^"])*"),', 1, 1, 1, NULL ) - 1,
1,
REGEXP_COUNT( csv, '([^",]*|"(\\"|[^"])*"),' )
FROM test_data
UNION ALL
SELECT id,
csv,
REGEXP_INSTR( csv, '([^",]*|"(\\"|[^"])*"),', 1, idx + 1, 0, NULL ),
REGEXP_INSTR( csv, '([^",]*|"(\\"|[^"])*"),', 1, idx + 1, 1, NULL ) - 1,
idx + 1,
num_matches
FROM matches
WHERE idx < num_matches
)
SELECT id,
idx,
start_pos,
comma_pos,
SUBSTR( csv, start_pos, comma_pos - start_pos ) AS value
FROM matches
所以对于您的测试数据:
CREATE TABLE test_data ( id, csv ) AS
SELECT 1, ',,,,"8000000,B767-200","B767-200","Boeing 767-200","ACFT",,,,,,,,,,,,,,,,,,,,,,,,,,' FROM DUAL
哪个输出:
身份证 | IDX | START_POS | COMMA_POS |价值
-: | --: | --------: | --------: | :-----------------
1 | 1 | 1 | 1 | 空
1 | 2 | 2 | 2 | 空
1 | 3 | 3 | 3 | 空
1 | 4 | 4 | 4 | 空
1 | 5 | 5 | 23 | “8000000,B767-200”
1 | 6 | 24 | 34 | “B767-200”
1 | 7 | 35 | 51 | “波音 767-200”
1 | 8 | 52 | 58 | “ACFT”
1 | 9 | 59 | 59 | 空
1 | 10 | 60 | 60 | 空
1 | 11 | 61 | 61 | 空
1 | 12 | 62 | 62 | 空
1 | 13 | 63 | 63 | 空
1 | 14 | 64 | 64 | 空
1 | 15 | 65 | 65 | 空
1 | 16 | 66 | 66 | 空
1 | 17 | 67 | 67 | 空
1 | 18 | 68 | 68 | 空
1 | 19 | 69 | 69 | 空
1 | 20 | 70 | 70 | 空
1 | 21 | 71 | 71 | 空
1 | 22 | 72 | 72 | 空
1 | 23 | 73 | 73 | 空
1 | 24 | 74 | 74 | 空
1 | 25 | 75 | 75 | 空
1 | 26 | 76 | 76 | 空
1 | 27 | 77 | 77 | 空
1 | 28 | 78 | 78 | 空
1 | 29 | 79 | 79 | 空
1 | 30 | 80 | 80 | 空
1 | 31 | 81 | 81 | 空
1 | 32 | 82 | 82 | 空
1 | 33 | 83 | 83 | 空
db小提琴here
(注意:你想匹配逗号,这个正则表达式完全符合你的要求;它不匹配逗号分隔列表中的任何最终值,因为没有终止逗号。如果你想做然后使用正则表达式([^",]*|"(\\"|[^"])*")(,|$)db<>fiddle。)
如果你想在程序中使用它:
CREATE PROCEDURE extract_csv_value(
i_csv IN VARCHAR2,
i_index IN INTEGER,
o_value OUT VARCHAR2
)
IS
BEGIN
o_value := REGEXP_SUBSTR( i_csv, '([^",]*|"(\\"|[^"])*")(,|$)', 1, i_index, NULL, 1 );
IF SUBSTR( o_value, 1, 1 ) = '"' THEN
o_value := REPLACE( SUBSTR( o_value, 2, LENGTH( o_value ) - 2 ), '\"', '"' );
END IF;
END;
/
然后:
DECLARE
csv VARCHAR2(4000) := ',,,,"8000000,B767-200","B767-200","Boeing 767-200","ACFT",,,,,,,,,,,,,,,,,,,,,,,,,,';
value VARCHAR2(100);
BEGIN
FOR i IN 1 .. 10 LOOP
extract_csv_value( csv, i, value );
DBMS_OUTPUT.PUT_LINE( LPAD( i, 2, ' ' ) || ' ' || value );
END LOOP;
END;
/
输出:
1
2
3
4
5 8000000,B767-200
6 B767-200
7 架波音 767-200
8 ACFT
9
10
db小提琴here