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?

¿Fue útil?

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 tabla employee_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

Concatenación

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 el LISTAGG a fallar con el ORA-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

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

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

  3. 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top