Elimine o conteúdo delimitado primeiro, conte depois:
regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, '(^|,)"[^"]*"(,|$)'
, '\1\2'
)
, ','
)
O aninhamento de
regexp_replace
Infelizmente, as chamadas são necessárias para lidar corretamente com campos delimitados por aspas consecutivos:qualquer vírgula de separação é consumida pelo padrão regexp e, portanto, não será levada em consideração para a correspondência subsequente. O regexen da Oracle não suporta o operador lookahead, que seria a maneira natural de lidar com essa situação.
Dado o impacto no desempenho das chamadas regexp_..., talvez seja melhor usar
length(i.data_record) - length ( replace ( regexp_replace ( i.data_record, '(^|,)"[^"]*"(,|$)', '\1\2' ),',','' ) )
Advertência
Esta solução não lida com dquotes dentro de valores de campo, que geralmente são representados como
""
ou \"
. O primeiro caso pode ser tratado com elegância:Em vez de interpretar um
""
dentro de um campo delimitado por aspas, considere todo o conteúdo do campo como uma justaposição de 1 ou mais strings delimitadas por d aspas que não contêm dquotes. Embora você não siga essa rota no processamento dos dados (todos os dquotes seriam perdidos), você pode empregar essa perspectiva para contar:regexp_count (
regexp_replace (
regexp_replace (
i.data_record
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, '(^|,)("[^"]*")+(,|$)' -- changed
, '\1\3' -- changed
)
, ','
)
Casos de teste
-- 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;