Sé que esto ha sido respondido hasta cierto punto con PHP y MYSQL, pero me preguntaba si alguien podría enseñarme el enfoque más simple para dividir una cadena (delimitada por comas) en varias filas en Oracle 10g (preferiblemente) y 11g.
La tabla es la siguiente:
Name | Project | Error
108 test Err1, Err2, Err3
109 test2 Err1
Quiero crear lo siguiente:
Name | Project | Error
108 Test Err1
108 Test Err2
108 Test Err3
109 Test2 Err1
He visto algunas soluciones potenciales alrededor de la pila, sin embargo, solo representaron una sola columna (que es la cadena delimitada por comas). Cualquier ayuda será muy apreciada.
REGEXP
,XMLTABLE
yMODEL
, consulte Dividir cadenas delimitadas por comas en una tabla con Oracle SQLRespuestas:
Esta puede ser una forma mejorada (también con regexp y connect by):
EDITAR : Aquí hay una explicación simple (como en, "no en profundidad") de la consulta.
length (regexp_replace(t.error, '[^,]+')) + 1
usaregexp_replace
para borrar cualquier cosa que no sea el delimitador (coma en este caso) ylength +1
para obtener cuántos elementos (errores) hay.El
select level from dual connect by level <= (...)
utiliza un consulta jerárquica para crear una columna con un número creciente de partidos encontró, desde 1 hasta el número total de errores.Avance:
table(cast(multiset(.....) as sys.OdciNumberList))
hace algunos tipos de oráculo.cast(multiset(.....)) as sys.OdciNumberList
transforma múltiples colecciones (uno de recogida para cada fila en el conjunto de datos original) en una sola colección de números, OdciNumberList.table()
función transforma una colección en un conjunto de resultados.FROM
sin una combinación crea una combinación cruzada entre su conjunto de datos y el conjunto múltiple. Como resultado, una fila en el conjunto de datos con 4 coincidencias se repetirá 4 veces (con un número creciente en la columna denominada "column_value").Avance:
trim(regexp_substr(t.error, '[^,]+', 1, levels.column_value))
usacolumn_value
como parámetro nth_appearance / ocurrence pararegexp_substr
.t.name, t.project
como ejemplo) para una fácil visualización.Algunas referencias a documentos de Oracle:
fuente
'[^,]+'
para analizar cadenas no devuelve el elemento correcto si hay un elemento nulo en la lista. Consulte aquí para obtener más información: stackoverflow.com/questions/31464275/…regexp_count(t.error, ',')
lugar delength (regexp_replace(t.error, '[^,]+'))
, lo que puede traer otra mejora de rendimientolas expresiones regulares son algo maravilloso :)
fuente
Name
s están conectadas, lo que se puede ver si eliminadistinct
. Desafortunadamente, agregarand Name = prior Name
a laconnect by
cláusula causaORA-01436: CONNECT BY loop in user data
.ORA-01436
error agregandoAND name = PRIOR name
(o cualquiera que sea la clave principal) yAND PRIOR SYS_GUID() IS NOT NULL
Hay una gran diferencia entre los dos siguientes:
Si no restringe las filas, la cláusula CONNECT BY producirá varias filas y no dará el resultado deseado.
Además de las expresiones regulares , se utilizan algunas otras alternativas:
Preparar
Usando XMLTABLE :
Usando la cláusula MODEL :
fuente
('"' || REPLACE(text, ',', '","') || '"')
haberlos y no se pueden quitar los corchetes? Los documentos de Oracle ([ docs.oracle.com/database/121/SQLRF/functions268.htm ) no me quedan claros. ¿EsXQuery_string
?Un par de ejemplos más de lo mismo:
Además, puede usar DBMS_UTILITY.comma_to_table & table_to_comma: http://www.oracle-base.com/articles/9i/useful-procedures-and-functions-9i.php#DBMS_UTILITY.comma_to_table
fuente
comma_to_table()
solo funciona con tokens que se ajustan a las convenciones de nomenclatura de objetos de base de datos de Oracle. Lanzará una cuerda como,'123,456,789'
por ejemplo.Me gustaría proponer un enfoque diferente utilizando una función de tabla PIPELINED. Es algo similar a la técnica de XMLTABLE, excepto que está proporcionando su propia función personalizada para dividir la cadena de caracteres:
Resultados:
El problema con este tipo de enfoque es que, a menudo, el optimizador no conocerá la cardinalidad de la función de tabla y tendrá que adivinar. Esto podría ser potencialmente perjudicial para sus planes de ejecución, por lo que esta solución se puede ampliar para proporcionar estadísticas de ejecución para el optimizador.
Puede ver esta estimación del optimizador ejecutando un EXPLICAR PLAN en la consulta anterior:
Aunque la colección tiene solo 3 valores, el optimizador estimó 8168 filas para ella (valor predeterminado). Esto puede parecer irrelevante al principio, pero puede ser suficiente para que el optimizador decida un plan subóptimo.
La solución es utilizar las extensiones del optimizador para proporcionar estadísticas para la colección:
Probando el plan de ejecución resultante:
Como puede ver, la cardinalidad en el plan anterior ya no es el valor estimado de 8196. Todavía no es correcto porque estamos pasando una columna en lugar de una cadena literal a la función.
Sería necesario hacer algunos ajustes en el código de función para dar una estimación más cercana en este caso particular, pero creo que el concepto general se explica bastante aquí.
La función str2tbl utilizada en esta respuesta fue desarrollada originalmente por Tom Kyte: https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:110612348061
El concepto de asociar estadísticas con tipos de objetos se puede explorar más a fondo leyendo este artículo: http://www.oracle-developer.net/display.php?id=427
La técnica descrita aquí funciona en 10g +.
fuente
REGEXP_COUNT no se agregó hasta Oracle 11i. Aquí hay una solución Oracle 10g, adoptada de la solución de Art.
fuente
A partir de Oracle 12c, puede usar
JSON_TABLE
yJSON_ARRAY
:Y consulta:
Salida:
db <> demostración de violín
fuente
Aquí hay una implementación alternativa que usa XMLTABLE que permite la conversión a diferentes tipos de datos:
... o si sus cadenas delimitadas se almacenan en una o más filas de una tabla:
fuente
Me gustaría agregar otro método. Este usa consultas recursivas, algo que no he visto en las otras respuestas. Es compatible con Oracle desde 11gR2.
Es bastante flexible con el carácter de división. Simplemente cámbielo en las
INSTR
llamadas.fuente
Sin usar connect by o regexp :
fuente
Tuve el mismo problema y xmltable me ayudó:
SELECT id, recortar (COLUMN_VALUE) texto de t, xmltable (('"' || REPLACE (text, ',', '", "') || '"'))
fuente
En Oracle 11g y versiones posteriores, puede usar una subconsulta recursiva y funciones de cadena simples (que pueden ser más rápidas que las expresiones regulares y las subconsultas jerárquicas correlacionadas):
Configuración de Oracle :
Consulta :
Salida :
db <> violín aquí
fuente
había usado la función DBMS_UTILITY.comma_to _table en realidad está funcionando el código de la siguiente manera
había usado mi propia tabla y nombres de columna
fuente
comma_to_table()
solo funciona con tokens que se ajustan a las convenciones de nomenclatura de objetos de base de datos de Oracle. Lanzará una cuerda como,'123,456,789'
por ejemplo.