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
какие выходы:
ID | IDX | START_POS | COMMA_POS | VALUE
-: | --: | --------: | --------: | :-----------------
1 | 1 | 1 | 1 | <em>null</em>
1 | 2 | 2 | 2 | <em>null</em>
1 | 3 | 3 | 3 | <em>null</em>
1 | 4 | 4 | 4 | <em>null</em>
1 | 5 | 5 | 23 | "8000000,B767-200"
1 | 6 | 24 | 34 | "B767-200"
1 | 7 | 35 | 51 | "Boeing 767-200"
1 | 8 | 52 | 58 | "ACFT"
1 | 9 | 59 | 59 | <em>null</em>
1 | 10 | 60 | 60 | <em>null</em>
1 | 11 | 61 | 61 | <em>null</em>
1 | 12 | 62 | 62 | <em>null</em>
1 | 13 | 63 | 63 | <em>null</em>
1 | 14 | 64 | 64 | <em>null</em>
1 | 15 | 65 | 65 | <em>null</em>
1 | 16 | 66 | 66 | <em>null</em>
1 | 17 | 67 | 67 | <em>null</em>
1 | 18 | 68 | 68 | <em>null</em>
1 | 19 | 69 | 69 | <em>null</em>
1 | 20 | 70 | 70 | <em>null</em>
1 | 21 | 71 | 71 | <em>null</em>
1 | 22 | 72 | 72 | <em>null</em>
1 | 23 | 73 | 73 | <em>null</em>
1 | 24 | 74 | 74 | <em>null</em>
1 | 25 | 75 | 75 | <em>null</em>
1 | 26 | 76 | 76 | <em>null</em>
1 | 27 | 77 | 77 | <em>null</em>
1 | 28 | 78 | 78 | <em>null</em>
1 | 29 | 79 | 79 | <em>null</em>
1 | 30 | 80 | 80 | <em>null</em>
1 | 31 | 81 | 81 | <em>null</em>
1 | 32 | 82 | 82 | <em>null</em>
1 | 33 | 83 | 83 | <em>null</em>
дБ <> скрипка здесь
(Примечание: вы хотели сопоставьте запятые, и это регулярное выражение выполняет именно то, что вы запрашиваете, оно не соответствует ни одному конечному значению в списке, разделенном запятыми, так как нет запятой в конце. Если вы хотите это сделать, используйте регулярное выражение ([^",]*|"(\\"|[^"])*")(,|$)
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 Boeing 767-200
8 ACFT
9
10
db <> скрипка здесь