2011-01-13 24 views
104

Sarebbe possibile costruire SQL per concatenare i valori delle colonne da più righe?Query SQL per concatenare i valori delle colonne da più righe in Oracle

Quello che segue è un esempio:

Tabella A

 
PID 
A 
B 
C 

Tabella 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! 

uscita del SQL dovrebbe essere -

 
PID Desc 
A  Have a nice day. 
B  Nice Work. 
C  Yes we can do this work! 

Quindi, in pratica il Desc colonna per fuori put table è una concatenazione dei valori SEQ dalla Tabella B?

Qualsiasi aiuto con SQL?

+0

veda ad esempio: http://halisway.blogspot.com/2006/08/oracle-groupconcat-updated-again.html – Andomar

+0

Si prega di guardare [questa soluzione] (https://stackoverflow.com/a/19348687/2459039). Ti sarà utile. –

risposta

156

Ci sono alcuni modi in base alla versione in uso: vedere oracle documentation on string aggregation techniques. Un molto comune è quello di utilizzare LISTAGG:

SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description 
FROM B GROUP BY pid; 

poi unirsi a A di scegliere la pids che si desidera.

Nota: Out of the box, LISTAGG funziona correttamente solo con VARCHAR2 colonne.

+2

utilizzando wm_concat() per Oracle 10g concatena il testo in ordine crescente del numero di sequenza delimitato da virgole, possiamo rendere decrescente delimitato da qualcos'altro? – jagamot

-3

Oppure la funzione Oracle STRAGG (colonna).

devo dire, questo tipo di lavorazione è molto limitata ... se si supera la larghezza del campo o la larghezza del display ...

10

Con modello di clausola 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. 

ho scritto su questo here. E se segui il link al thread OTN ne troverai di più, incluso un confronto delle prestazioni.

14

C'è anche una funzione XMLAGG, che funziona su versioni precedenti alla 11.2. Poiché WM_CONCAT è undocumented and unsupported by Oracle, si consiglia di non utilizzarlo nel sistema di produzione.

Con XMLAGG è possibile effettuare le seguenti operazioni:

SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result" 
FROM employee_names 

Quello che fa è

  • messo i valori della colonna ename (concatenato con una virgola) dalla tabella employee_names in un elemento XML (con etichetta E)
  • estrarre il testo di questo
  • aggregare il xml (concatenarlo)
  • chiamata la colonna risultante "Risultato"
2

Prima di eseguire una query di selezione, eseguire questo:

SET SERVEROUT ON SIZE 6000

SELECT XMLAGG(XMLELEMENT(E,SUPLR_SUPLR_ID||',')).EXTRACT('//text()') "SUPPLIER" 
FROM SUPPLIERS; 
-1

provare questo codice:

SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames" 
    FROM FIELD_MASTER 
    WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA'; 
0

Il l'uso di LISTAGG è il più pratico e offre le migliori prestazioni con on e eccezione, quando l'ordine non è necessario. Maggiori dettagli qui: http://www.oracle-developer.net/display.php?id=515

+1

Sarebbe utile elaborare la tua risposta. –

+0

John, non volevo ripetere l'articolo, ma in breve questi sono i risultati: 1. LISTAGG offre le migliori prestazioni se l'ordinamento è obbligatorio (00: 00: 05.85) 2. COLLECT offre le migliori prestazioni se l'ordinamento non è necessario (00: 00: 02.90): SELECT pid, TO_STRING (CAST (COLLECT (Desc) AS varchar2_ntt)) AS Vals DA B GROUP BY pid; 3. Raccogliere con l'ordinazione è po 'più lento (00: 00: 07.08): SELEZIONA pid, to_string (CAST (Collect (Asc ORDER BY Asc) AS varchar2_ntt)) AS Vals DA B GROUP BY pid; Tutte le altre tecniche erano più lente. – Misho

+1

È possibile modificare la risposta per includere informazioni pertinenti. –

-2

Nella selezione in cui si desidera la concatenazione, chiamare una funzione SQL.

Ad esempio:

select PID, dbo.MyConcat(PID) 
    from TableA; 

Poi per la funzione SQL: sintassi Header

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 funzione potrebbe essere sbagliato, ma il principio funziona.

+0

Questo non è valido per Oracle –

1

Per coloro che devono risolvere questo problema utilizzando Oracle 9i (o versioni precedenti), sarà probabilmente necessario utilizzare SYS_CONNECT_BY_PATH, poiché LISTAGG non è disponibile.

Per rispondere alla OP, la seguente query visualizzerà il PID dalla Tabella A e concatenare tutte le colonne DESC da Tabella B:

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; 

Ci possono anche essere casi in cui chiavi e valori sono tutti contenuti in un unico tavolo. La seguente query può essere utilizzata dove non c'è tabella A, e solo Tabella B esiste:

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; 

Tutti i valori possono essere riordinate come desiderato. Le singole descrizioni concatenate possono essere riordinate nella clausola PARTITION BY e l'elenco dei PID può essere riordinato nella clausola finale ORDER BY.


alternativa: ci possono essere momenti in cui si desidera concatenare tutti i valori di un'intera tabella in una riga.

L'idea chiave qui è usare un valore artificiale per il gruppo di descrizioni da concatenare.

Nella query seguente, la stringa costante '1' è usato, ma qualsiasi valore funzionerà:

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; 

Persona descrizioni concatenati possono essere riordinate in PARTITION BY.

Diverse altre risposte in questa pagina hanno anche parlato di questo riferimento estremamente utile: https://oracle-base.com/articles/misc/string-aggregation-techniques

0

ho utilizzando il LISTAGG ma restituire questa stringa per stringa persiano!

la mia domanda:

SELECT 
listagg(DESCRIPTION,' , ') within group (order by DESCRIPTION) 
FROM 
B_CEREMONY 

risultato:

'A7'1 , ,4F 

Ti prego, aiutami.

wow questa soluzione è lavorato:

SELECT listagg(convert(DESCRIPTION, 'UTF8', 'AL16UTF16'),' , ') within group 
(order by DESCRIPTION) 
FROM B_CEREMONY; 
0

Come la maggior parte delle risposte suggeriscono, LISTAGG è l'opzione ovvia. Tuttavia, un aspetto fastidioso con LISTAGG è che se la lunghezza totale della stringa concatenata supera 4000 caratteri (limite per VARCHAR2 in SQL), l'errore sotto viene generata, che è difficile da gestire in versioni Oracle fino 12,1

ORA -01.489: risultato della concatenazione di stringhe è troppo lunga

Una nuova funzionalità aggiunta nel 12cR2 è la clausola di ON OVERFLOWLISTAGG. La query tra cui questa clausola sarà simile:

SELECT pid, LISTAGG(Desc, ' ' on overflow truncate) WITHIN GROUP (ORDER BY seq) AS desc 
FROM B GROUP BY pid; 

È possibile che questo limiterà l'uscita a 4000 caratteri, ma non gettare l'errore ORA-01489.

Queste sono alcune delle opzioni aggiuntive di ON OVERFLOW clausola:

  • ON OVERFLOW TRUNCATE 'Contd..': Questo visualizzerà 'Contd..' alla fine della stringa (di default è ...)
  • ON OVERFLOW TRUNCATE '': Questo visualizzerà i 4000 caratteri senza alcuna stringa di terminazione.
  • ON OVERFLOW TRUNCATE WITH COUNT: questo visualizza il numero totale di caratteri alla fine dopo i caratteri di terminazione. Ad esempio: - '...(5512)'
  • ON OVERFLOW ERROR: Se si prevede la LISTAGG di fallire con l'errore ORA-01489 (che è di default in ogni caso).
0

11g e superiore: Uso listagg:

SELECT 
    col1, 
    LISTAGG(col2, ', ') WITHIN GROUP (ORDER BY col2) "names" 
FROM table_x 
GROUP BY col1 

10g e inferiore: Un metodo è quello di utilizzare una funzione:

CREATE OR REPLACE FUNCTION get_comma_separated_value (input_val in number) 
    RETURN VARCHAR2 
IS 
    return_text VARCHAR2(10000) := NULL; 
BEGIN 
    FOR x IN (SELECT col2 FROM table_name WHERE col1 = input_val) LOOP 
    return_text := return_text || ',' || x.col2 ; 
    END LOOP; 
    RETURN LTRIM(return_text, ','); 
END; 
/

Per utilizzare la funzione:

select col1, get_comma_separated_value(col1) from table_name 

Nota: C'è una funzione (non supportata) WM_CONCAT disponibile su alcune versioni precedenti di Oracle, che potrebbero essere d'aiuto: vedere here for details.

In MySQL:

SELECT col1, GROUP_CONCAT(col2) FROM table_name GROUP BY col1 
Problemi correlati