SQL Query para concatenar valores de la columna de varias filas en Oracle
-
11-10-2019 - |
Pregunta
¿Sería posible construir SQL para valores de columna de concatenar varias filas?
El siguiente es un ejemplo:
Tabla A
PID A B C
Tabla B
PID SEQ Desc A 1 Have A 2 a nice A 3 day. B 1 Nice Work. C 1 Yes C 2 we can C 3 do C 4 this work!
Salida del SQL debe ser -
PID Desc A Have a nice day. B Nice Work. C Yes we can do this work!
Así que, básicamente, la columna de la descripción a cabo la mesa de venta es una concatenación de los valores de la Tabla B SEQ?
Cualquier ayuda con el SQL?
Solución
Hay algunas maneras dependiendo de la versión que tiene - véase la documentación de Oracle href="http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php" rel="noreferrer"> . Uno muy común es usar LISTAGG
:
SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;
A continuación, se unen para A
para escoger el pids
desea.
Nota:. Fuera de la caja, LISTAGG
sólo funciona correctamente con columnas VARCHAR2
Otros consejos
También hay una función XMLAGG
, que funciona en las versiones anteriores a la 11.2. Debido WM_CONCAT
es indocumentado y sin apoyo por parte de Oracle , se recomienda no usarlo en el sistema de producción.
Con XMLAGG
puede hacer lo siguiente:
SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result"
FROM employee_names
Lo que esto hace es
- puso a los valores de la columna
ename
la (concatenado con una coma) de la tablaemployee_names
en un elemento XML (con la etiqueta E) - extraer el texto de este
- agregar el xml (concatenarlo)
- llamar al "Resultado" resultante columna
Con la cláusula tipo SQL:
SQL> select pid
2 , ltrim(sentence) sentence
3 from ( select pid
4 , seq
5 , sentence
6 from b
7 model
8 partition by (pid)
9 dimension by (seq)
10 measures (descr,cast(null as varchar2(100)) as sentence)
11 ( sentence[any] order by seq desc
12 = descr[cv()] || ' ' || sentence[cv()+1]
13 )
14 )
15 where seq = 1
16 /
P SENTENCE
- ---------------------------------------------------------------------------
A Have a nice day
B Nice Work.
C Yes we can do this work!
3 rows selected.
aquí . Y si sigue el enlace a la red OTN-hilo se encuentra un poco más, incluyendo una comparación de rendimiento.
La LISTAGG función analítica se introdujo en Oracle 11g Release 2 , por lo que es muy fácil de cadenas de agregado. Si está utilizando 11g versión 2, es recomendable utilizar esta función para la agregación de cadenas. Por favor, consulte a continuación URL para obtener más información sobre la concatenación de cadenas.
http://www.oracle-base.com/articles/misc/ StringAggregationTechniques.php
Como la mayoría de las respuestas sugieren, LISTAGG
es la opción obvia. Sin embargo, un aspecto molesto con LISTAGG
es que si la longitud total de cadena concatenada supera 4000 caracteres (límite para VARCHAR2
en SQL), el siguiente error se lanza, que es difícil de manejar en las versiones de Oracle hasta 12.1
ORA-01489: resultado de la concatenación de cadenas es demasiado largo
Una nueva característica añadida en 12cR2 es la cláusula ON OVERFLOW
de LISTAGG
.
La consulta que incluye esta cláusula se vería así:
SELECT pid, LISTAGG(Desc, ' ' on overflow truncate) WITHIN GROUP (ORDER BY seq) AS desc
FROM B GROUP BY pid;
Lo anterior restringe la salida a 4000 caracteres pero no arrojará el error ORA-01489
.
Estas son algunas de las opciones adicionales de la cláusula ON OVERFLOW
:
-
ON OVERFLOW TRUNCATE 'Contd..'
: Esto mostrará en'Contd..'
el final de la cadena (por defecto es...
) -
ON OVERFLOW TRUNCATE ''
: Esto mostrará los 4000 caracteres sin cualquier cadena de terminación. -
ON OVERFLOW TRUNCATE WITH COUNT
: Esto mostrará el total de número de caracteres al final después de los caracteres de terminación. Por ejemplo: - '...(5512)
' -
ON OVERFLOW ERROR
: Si usted espera que elLISTAGG
a fallar con elORA-01489
de error (que es de todos modos por defecto).
Para aquellos que deben resolver este problema utilizando Oracle 9i (o anterior), es probable que necesite para su uso SYS_CONNECT_BY_PATH, ya LISTAGG no está disponible.
Para responder a la OP, la siguiente consulta mostrará el PID de la Tabla A y concatenar todas las columnas de la Tabla B DESC:
SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
FROM (
SELECT a.pid, seq, description
FROM table_a a, table_b b
WHERE a.pid = b.pid(+)
)
)
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;
También puede haber casos en los que las claves y valores están todos contenidos en una tabla. La siguiente consulta se puede utilizar donde no hay la Tabla A, y sólo la Tabla B existe:
SELECT pid, SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
SELECT ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid, seq) rnum, pid, description
FROM (
SELECT pid, seq, description
FROM table_b
)
)
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1 AND PRIOR pid = pid
GROUP BY pid
ORDER BY pid;
Todos los valores puede reordenarse como deseado. descripciones concatenados individuales pueden ser reordenadas en la partición cláusula, y la lista de PIDs pueden ser reordenadas en el fallo final por cláusula.
Como alternativa:. puede haber ocasiones en las que desea concatenar todos los valores de una tabla entera en una sola fila
La idea clave aquí es el uso de un valor artificial para el conjunto de las descripciones que se concatena.
En la siguiente consulta, se utiliza la constante de cadena '1', pero cualquier valor funcionará:
SELECT SUBSTR (MAX (SYS_CONNECT_BY_PATH (description, ', ')), 3) all_descriptions
FROM (
SELECT ROW_NUMBER () OVER (PARTITION BY unique_id ORDER BY pid, seq) rnum, description
FROM (
SELECT '1' unique_id, b.pid, b.seq, b.description
FROM table_b b
)
)
START WITH rnum = 1
CONNECT BY PRIOR rnum = rnum - 1;
Individual concatena descripciones pueden ser reordenadas en la partición cláusula.
Varias otras respuestas en esta página también han mencionado esta referencia muy útil: https://oracle-base.com/articles/misc/string-aggregation-techniques
-
LISTAGG ofrece el mejor rendimiento si la clasificación es imprescindible (00: 00: 05,85)
SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description FROM B GROUP BY pid;
-
entrega recoja el mejor rendimiento si no se necesita de clasificación (00: 00: 02.90):
SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;
-
recopilada con pedido es poco más lento (00: 00: 07.08):
SELECT pid, TO_STRING(CAST(COLLECT(Desc ORDER BY Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;
Todas las otras técnicas fueron más lentas.
Antes de ejecutar una consulta de selección, ejecute lo siguiente:
SET SERVEROUT ON SIZE 6000
SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER"
FROM SUPPLIERS;
I utilizando el LISTAGG pero regresan esta cadena de cadena persa!
mi consulta:
SELECT
listagg(DESCRIPTION,' , ') within group (order by DESCRIPTION)
FROM
B_CEREMONY
resultado:
'A7'1 , ,4F
Por favor, ayúdame.
wow esta solución se trabajó:
SELECT listagg(convert(DESCRIPTION, 'UTF8', 'AL16UTF16'),' , ') within group
(order by DESCRIPTION)
FROM B_CEREMONY;
Prueba este código:
SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
FROM FIELD_MASTER
WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';
En el seleccionar el lugar donde desea que su concatenación, llamar a una función de SQL.
Por ejemplo:
select PID, dbo.MyConcat(PID)
from TableA;
A continuación, para la función de SQL:
Function MyConcat(@PID varchar(10))
returns varchar(1000)
as
begin
declare @x varchar(1000);
select @x = isnull(@x +',', @x, @x +',') + Desc
from TableB
where PID = @PID;
return @x;
end
La sintaxis de la función de cabecera podría estar equivocado, pero el principio funciona.