SQL Query per valori di colonna concatenare molteplici righe in Oracle
-
11-10-2019 - |
Domanda
sarebbe possibile costruire SQL per i valori della colonna concatenare da più righe?
Il seguente è 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!
Output del SQL dovrebbe essere -
PID Desc A Have a nice day. B Nice Work. C Yes we can do this work!
Quindi, in pratica la colonna Desc per uscire tavolo put è una concatenazione di valori SEQ dalla Tabella B?
Qualsiasi aiuto con SQL?
Soluzione
Ci sono alcuni modi a seconda di quale versione si ha - vedere la documentazione di Oracle su stringa tecniche di aggregazione . Un molto comune è quello di utilizzare LISTAGG
:
SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description
FROM B GROUP BY pid;
Poi si uniscono per A
di scegliere la pids
che si desidera.
Nota. Fuori dalla scatola, LISTAGG
funziona correttamente solo con colonne VARCHAR2
Altri suggerimenti
C'è anche una funzione XMLAGG
, che funziona su versioni precedenti alla 11.2. Perché WM_CONCAT
è non documentata e non supportata da Oracle , si consiglia di non usarlo in sistema di produzione.
Con XMLAGG
è possibile effettuare le seguenti operazioni:
SELECT XMLAGG(XMLELEMENT(E,ename||',')).EXTRACT('//text()') "Result"
FROM employee_names
Quello che fa è
- inserisce i valori della colonna
ename
(concatenato con una virgola) dalla tabellaemployee_names
in un elemento XML (con etichetta E) - estrarre il testo di questo
- aggregare l'XML (concatenare esso)
- chiamare la colonna "Risultato" risultante
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 qui . E se si segue il link al OTN-filo si trova un po ', tra cui un confronto delle prestazioni.
Il LISTAGG funzione analitica è stata introdotta nel Oracle 11g Release 2 , il che rende molto facile da stringhe di aggregazione. Se si utilizza 11g Release 2 si dovrebbe utilizzare questa funzione per l'aggregazione di stringa. Si prega di fare riferimento al di sotto URL per ulteriori informazioni sulla concatenazione di stringhe.
http://www.oracle-base.com/articles/misc/ StringAggregationTechniques.php
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 i 4000 caratteri (limite per VARCHAR2
in SQL), l'errore viene generato al di sotto, che è difficile da gestire nelle versioni di Oracle fino a 12,1
ORA-01489: risultato della concatenazione di stringhe è troppo lunga
Una nuova funzionalità aggiunta nel 12cR2 è la clausola di ON OVERFLOW
LISTAGG
.
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 getterà l'errore ORA-01489
.
Queste sono alcune delle opzioni aggiuntive di clausola ON OVERFLOW
:
-
ON OVERFLOW TRUNCATE 'Contd..'
: Questo mostrerà'Contd..'
a alla fine della stringa (di default è...
) -
ON OVERFLOW TRUNCATE ''
: Questo mostrerà i 4000 caratteri senza qualsiasi stringa di terminazione. -
ON OVERFLOW TRUNCATE WITH COUNT
: Questo visualizzerà la totale numero di caratteri alla fine dopo i caratteri di terminazione. Ad esempio: - '...(5512)
' -
ON OVERFLOW ERROR
: Se si prevede laLISTAGG
a fallire con il Errore diORA-01489
(che è in ogni caso di default).
Per coloro che devono risolvere questo problema utilizzando Oracle 9i (o precedente), si avrà probabilmente bisogno di usare SYS_CONNECT_BY_PATH, dal momento che LISTAGG non è disponibile.
Per rispondere alla OP, la seguente query visualizzerà il PID dalla Tabella A e concatenare tutte le colonne DESC dalla 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 una tabella. 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 riordinati, se lo desideri. Singole descrizioni concatenati possono essere riordinati nella partizione dalla clausola, e la lista dei PID possono essere riordinati in ORDER BY finale.
In 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, viene utilizzata la stringa costante '1', ma qualsiasi valore funziona:
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;
Individuale concatenato descrizioni possono essere riordinate nella partizione dalla clausola.
Diverse altre risposte in questa pagina hanno anche parlato di questo riferimento estremamente utile: https://oracle-base.com/articles/misc/string-aggregation-techniques
-
LISTAGG offre le migliori prestazioni se l'ordinamento è un must (00: 00: 05.85)
SELECT pid, LISTAGG(Desc, ' ') WITHIN GROUP (ORDER BY seq) AS description FROM B GROUP BY pid;
-
offre la miglior collezione prestazione se l'ordinamento non è necessaria (00: 00: 02.90):
SELECT pid, TO_STRING(CAST(COLLECT(Desc) AS varchar2_ntt)) AS Vals FROM B GROUP BY pid;
-
Raccogli con l'ordinazione è po 'più 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;
Tutte le altre tecniche erano più lenti.
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;
I utilizzando il LISTAGG ma restituire questa stringa per stringa persiano!
la mia domanda:
SELECT
listagg(DESCRIPTION,' , ') within group (order by DESCRIPTION)
FROM
B_CEREMONY
Risultati:
'A7'1 , ,4F
Si prega di aiutare me.
wow questa soluzione è lavorato:
SELECT listagg(convert(DESCRIPTION, 'UTF8', 'AL16UTF16'),' , ') within group
(order by DESCRIPTION)
FROM B_CEREMONY;
Prova questo codice:
SELECT XMLAGG(XMLELEMENT(E,fieldname||',')).EXTRACT('//text()') "FieldNames"
FROM FIELD_MASTER
WHERE FIELD_ID > 10 AND FIELD_AREA != 'NEBRASKA';
Nel selezionare dove si desidera che la concatenazione, chiamare una funzione SQL.
Ad esempio:
select PID, dbo.MyConcat(PID)
from TableA;
Poi per la funzione 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 sintassi Header funzione potrebbe essere sbagliato, ma il principio funziona.