Oracle
 sql >> Database >  >> RDS >> Oracle

Come contare le occorrenze del separatore nella stringa escludendo quelle tra virgolette

Elimina prima il contenuto delimitato, poi conta:

regexp_count (
    regexp_replace (
        regexp_replace (
            i.data_record
          , '(^|,)"[^"]*"(,|$)'
          , '\1\2'
        )
      , '(^|,)"[^"]*"(,|$)'
      , '\1\2'
    )
  , ',' 
) 

La nidificazione di regexp_replace call è purtroppo necessario per gestire correttamente i campi consecutivi delimitati da virgolette:qualsiasi virgola di separazione viene utilizzata dal pattern regexp e quindi non verrà presa in considerazione per la corrispondenza successiva.

Le espressioni regolari di Oracle non supportano l'operatore lookahead, il che sarebbe il modo naturale per gestire questa situazione.

Dato il colpo di prestazioni delle chiamate regexp_... potresti fare meglio a usare

length(i.data_record) - length ( replace ( regexp_replace ( i.data_record, '(^|,)"[^"]*"(,|$)', '\1\2' ),',','' ) )

Avvertimento

Questa soluzione non gestisce le virgolette all'interno dei valori dei campi, che di solito sono rappresentati come "" o \" .

Il primo caso può essere gestito in modo elegante:invece di interpretare un "" all'interno di un campo delimitato da virgolette, considera l'intero contenuto del campo come una giustapposizione di 1 o più stringhe delimitate da virgolette che non contengono virgolette. Anche se non seguiresti questo percorso nell'elaborazione dei dati (tutte le virgolette andrebbero perse), puoi utilizzare questa prospettiva per il conteggio:

regexp_count (
    regexp_replace (
        regexp_replace (
            i.data_record
          , '(^|,)("[^"]*")+(,|$)'  -- changed
          , '\1\3'                  -- changed
        )
      , '(^|,)("[^"]*")+(,|$)'   -- changed
      , '\1\3'                   -- changed
    )
  , ',' 
) 

Casi di prova

-- 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;