sql >> Base de Datos >  >> RDS >> Oracle

Cómo contar las ocurrencias del separador en una cadena excluyendo las que están entre comillas

Eliminar el contenido delimitado primero, contar después:

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

El anidamiento de regexp_replace Desafortunadamente, las llamadas son necesarias para manejar campos consecutivos delimitados por comillas correctamente:cualquier coma de separación es consumida por el patrón de expresión regular y, por lo tanto, no se tendrá en cuenta para la coincidencia posterior.

Las expresiones regulares de Oracle no admiten el operador de anticipación, que sería la forma natural de manejar esta situación.

Dado el impacto en el rendimiento de las llamadas regexp_..., es mejor que uses

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

Advertencia

Esta solución no maneja dquotes dentro de los valores de campo, que generalmente se representan como "" o \" .

El primer caso se puede manejar con elegancia:en lugar de interpretar un "" dentro de un campo delimitado por comillas, considere todo el contenido del campo como una yuxtaposición de 1 o más cadenas delimitadas por comillas que no contienen comillas. Si bien no seguiría esta ruta al procesar los datos (se perderían todas las comillas), puede emplear esta perspectiva por el simple hecho de contar:

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

Casos de prueba

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