Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Como contar ocorrências de separador em string excluindo aquelas entre aspas


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;