Eliminera det avgränsade innehållet först, räkna efteråt:
regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, ','
)
Kapslingen av regexp_replace
anrop är tyvärr nödvändiga för att hantera på varandra följande citatavgränsade fält korrekt:eventuellt separerande kommatecken förbrukas av regexp-mönstret och kommer därför inte att tas med i den efterföljande matchningen.
Oracles regexen stöder inte lookahead-operatören, vilket skulle vara det naturliga sättet att hantera denna situation.
Med tanke på prestandaträffen för regexp_...-anrop kan det vara bättre att använda
length(i.data_record) - length ( replace ( regexp_replace ( i.data_record, '(^|,)"[^"]*"(,|$)', '\1\2' ),',','' ) )
Varning
Denna lösning hanterar inte dcitat inom fältvärden, som vanligtvis representeras som ""
eller \"
.
Det förra fallet kan hanteras elegant:Istället för att tolka en ""
inuti ett citatavgränsat fält, betrakta hela fältinnehållet som en sammanställning av 1 eller flera citatteparerade strängar som inte innehåller citattecken. Även om du inte skulle följa den här vägen vid bearbetning av data (alla citat skulle gå förlorade), kan du använda detta perspektiv för att räkna:
regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, ','
)
Testfall
-- 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;