Najpierw usuń oddzieloną zawartość, a potem policz:
regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, ','
)
Zagnieżdżenie regexp_replace
Wywołania są niestety niezbędne do poprawnej obsługi kolejnych pól oddzielonych cudzysłowami:każdy przecinek oddzielający jest zużywany przez wzorzec wyrażenia regularnego, a zatem nie zostanie uwzględniony w kolejnym dopasowaniu.
Regexeny Oracle nie obsługują operatora lookahead, co byłoby naturalnym sposobem radzenia sobie z tą sytuacją.
Biorąc pod uwagę wydajność wywołań regexp_..., lepiej byłoby użyć
length(i.data_record) - length ( replace ( regexp_replace ( i.data_record, '(^|,)"[^"]*"(,|$)', '\1\2' ),',','' ) )
Zastrzeżenie
To rozwiązanie nie obsługuje dquotes w wartościach pól, które są zwykle reprezentowane jako ""
lub \"
.
Pierwsza sprawa może być obsługiwana elegancko:Zamiast interpretować ""
wewnątrz pola rozdzielonego cudzysłowami, rozważ całą zawartość pola jako zestawienie jednego lub więcej ciągów oddzielonych cudzysłowami, które nie zawierają dquote. Chociaż nie podążałbyś tą ścieżką podczas przetwarzania danych (wszystkie dquote zostałyby utracone), możesz wykorzystać tę perspektywę w celu liczenia:
regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, ','
)
Przypadki testowe
-- works
select regexp_count ( regexp_replace ( regexp_replace ( '1,"data,and more so","more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
select regexp_count ( regexp_replace ( regexp_replace ( '1,"data,and more so",2,"more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
select regexp_count ( regexp_replace ( regexp_replace ( '1,"""data"",and more so",2,"more data,and even more so"', '(^|,)("[^"]*")+(,|$)', '\1\3' ), '(^|,)("[^"]*")+(,|$)', '\1\3' ), ',' ) from dual;
-- fails
select regexp_count ( regexp_replace ( '1,"data,and more so","more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;
select regexp_count ( regexp_replace ( '1,"data,and more so",2,"more data,and even more so"', '(^|,)"[^"]*"(,|$)', '\1\2' ), ',' ) from dual;