122 Stimmen

Wie kann ich in Oracle mehrere Zeilen zu einer kommagetrennten Liste zusammenfassen?

Ich habe eine einfache Frage:

select * from countries

mit den folgenden Ergebnissen:

country_name
------------
Albania
Andorra
Antigua
.....

Ich möchte die Ergebnisse in einer Zeile zurückgeben, also etwa so:

Albania, Andorra, Antigua, ...

Natürlich kann ich eine PL/SQL-Funktion schreiben, um die Aufgabe zu erledigen (das habe ich bereits in Oracle 10g getan), aber gibt es eine schönere, vorzugsweise nicht Oracle-spezifische Lösung (oder vielleicht eine integrierte Funktion) für diese Aufgabe?

Ich würde es im Allgemeinen verwenden, um mehrere Zeilen in einer Unterabfrage zu vermeiden, d. h. wenn eine Person mehr als eine Staatsangehörigkeit hat, möchte ich nicht, dass sie in der Liste doppelt vorkommt.

Meine Frage bezieht sich auf eine ähnliche Frage auf SQL-Server 2005 .

UPDATE : Meine Funktion sieht folgendermaßen aus:

CREATE OR REPLACE FUNCTION APPEND_FIELD (sqlstr in varchar2, sep in varchar2 ) return varchar2 is
ret varchar2(4000) := '';
TYPE cur_typ IS REF CURSOR;
rec cur_typ;
field varchar2(4000);
begin
     OPEN rec FOR sqlstr;
     LOOP
         FETCH rec INTO field;
         EXIT WHEN rec%NOTFOUND;
         ret := ret || field || sep;
     END LOOP;
     if length(ret) = 0 then
          RETURN '';
     else
          RETURN substr(ret,1,length(ret)-length(sep));
     end if;
end;

135voto

JoshL Punkte 10418

El WM_CONCAT Funktion (falls in Ihrer Datenbank enthalten, vor Oracle 11.2) oder LISTAGG (ab Oracle 11.2) sollte den Trick gut machen. So erhalten Sie beispielsweise eine kommagetrennte Liste der Tabellennamen in Ihrem Schema:

select listagg(table_name, ', ') within group (order by table_name) 
  from user_tables;

o

select wm_concat(table_name) 
  from user_tables;

Weitere Details/Optionen

Link zur Dokumentation

0 Stimmen

Dieser Befehl ist schneller als der von @Decci.7 bereitgestellte +1 und ich mag einfache Einzeiler :D

8 Stimmen

Beachten Sie, dass Oracle nicht empfiehlt, die WM_CONCAT da sie undokumentiert ist und nicht unterstützt wird: WMSYS.WM_CONCAT sollte nicht für Kundenanwendungen verwendet werden, da es sich um eine interne Funktion handelt (Doc ID 1336219.1)

11 Stimmen

WM_CONCAT wurde in 12c gestrichen. Jeder, der diese undokumentierte Funktion verwendet, wird beim Upgrade eine Überraschung erleben.

102voto

Daniel Emge Punkte 1497

Hier ist ein einfacher Weg ohne stragg oder die Erstellung einer Funktion.

create table countries ( country_name varchar2 (100));

insert into countries values ('Albania');

insert into countries values ('Andorra');

insert into countries values ('Antigua');

SELECT SUBSTR (SYS_CONNECT_BY_PATH (country_name , ','), 2) csv
      FROM (SELECT country_name , ROW_NUMBER () OVER (ORDER BY country_name ) rn,
                   COUNT (*) OVER () cnt
              FROM countries)
     WHERE rn = cnt
START WITH rn = 1
CONNECT BY rn = PRIOR rn + 1;

CSV                                                                             
--------------------------
Albania,Andorra,Antigua                                                         

1 row selected.

Wie bereits von anderen erwähnt, können Sie, wenn Sie mit 11g R2 oder höher arbeiten, jetzt listagg verwenden, was viel einfacher ist.

select listagg(country_name,', ') within group(order by country_name) csv
  from countries;

CSV                                                                             
--------------------------
Albania, Andorra, Antigua

1 row selected.

0 Stimmen

Nette kurze Lösung, aber ein paar Tippfehler haben sie beeinträchtigt. Diese Zeile sollte lauten: FROM (SELECT land_name , ROW_NUMBER () OVER (ORDER BY country_name ) rn,

3 Stimmen

Der Vorschlag von JoshL, die Funktion LISTAGG zu verwenden, ist für alle, die 11.2 oder neuer verwenden, sehr zu empfehlen.

3 Stimmen

Vergewissern Sie sich nur, dass Ihre verketteten Ergebnisse die maximale VARCHAR2-Länge Ihrer Oracle-Datenbank nicht überschreiten (höchstwahrscheinlich 4000 Bytes), da Sie sonst in ORA-01489 result of string concatenation is too long .

21voto

Makatun Punkte 787

Für Oracle können Sie verwenden LISTAGG

7 Stimmen

In Oracle 11.2, wie JoshL hervorhob.

3 Stimmen

Link ist defekt.

0 Stimmen

Behobener Link. Danke

20voto

Decci.7 Punkte 201

Sie können dies auch verwenden:

SELECT RTRIM (
          XMLAGG (XMLELEMENT (e, country_name || ',')).EXTRACT ('//text()'),
          ',')
          country_name
  FROM countries;

0 Stimmen

Danke! Dies funktioniert in Oracle 10g.

20voto

Gaya3 Punkte 199

Können Sie diese Abfrage versuchen.

select listagg(country_name,',') within group (order by country_name) cnt 
from countries;

0 Stimmen

Listagg wurde in Oracle 11g Release 2 eingeführt.

1 Stimmen

Dies würde nicht funktionieren, wenn es zu viele Spalten gibt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X