Doppelte Einträge in ListAgg (Oracle) entfernen


44

Vor Oracle 11.2 habe ich eine benutzerdefinierte Aggregatfunktion verwendet, um eine Spalte in eine Zeile zu verketten. 11.2 Die LISTAGGFunktion wurde hinzugefügt , daher versuche ich, sie stattdessen zu verwenden. Mein Problem ist, dass ich doppelte Ergebnisse eliminieren muss und dies anscheinend nicht kann.

Hier ist ein Beispiel.

CREATE TABLE ListAggTest AS (
  SELECT rownum Num1, DECODE(rownum,1,'2',to_char(rownum)) Num2 FROM dual 
     CONNECT BY rownum<=6
  );
SELECT * FROM ListAggTest;
      NUM1 NUM2
---------- ---------------------
         1 2
         2 2                    << Duplicate 2
         3 3
         4 4
         5 5
         6 6

Was ich sehen möchte ist folgendes:

      NUM1 NUM2S
---------- --------------------
         1 2-3-4-5-6
         2 2-3-4-5-6
         3 2-3-4-5-6
         4 2-3-4-5-6
         5 2-3-4-5-6
         6 2-3-4-5-6

Hier ist eine listaggVersion, die in der Nähe liegt, aber keine Duplikate beseitigt.

SELECT Num1, listagg(Num2,'-') WITHIN GROUP (ORDER BY NULL) OVER () Num2s 
FROM ListAggTest;

Ich habe eine Lösung, aber es ist schlimmer, als weiterhin die benutzerdefinierte Aggregatfunktion zu verwenden.


Sollte ich verwirrt order by nullsein order by Num2oder werde ich verwirrt?
Jack Douglas

@Jack - Es macht keinen Unterschied, ob Duplikate entfernt werden. Abhängig von Ihrer Verwendung kann dies wünschenswert sein.
Leigh Riffel

Seufzer LISTAGG bleibt hinter Tom Kytes zurückSTRAGG , mit dem es so einfach ist wieSTRAGG(DISTINCT ...)
Baodad

Endlich ist es möglich: LISTAGG DISTINCT
lad2025

Antworten:


32

Sie können reguläre Ausdrücke verwenden und regexp_replacedie Duplikate nach der Verkettung entfernen mit listagg:

SELECT Num1, 
       RTRIM(
         REGEXP_REPLACE(
           (listagg(Num2,'-') WITHIN GROUP (ORDER BY Num2) OVER ()), 
           '([^-]*)(-\1)+($|-)', 
           '\1\3'),
         '-') Num2s 
FROM ListAggTest;

Dies könnte aufgeräumter sein, wenn die reguläre Ausprägung von Oracle Lookahead- oder Nicht-Capturing-Gruppen unterstützt, dies jedoch nicht .

Bei dieser Lösung wird jedoch vermieden, dass die Quelle mehrmals gescannt wird.

DBFiddle hier


Damit diese REGEX_REPLACE-Technik zum Entfernen von Duplikaten verwendet werden kann, müssen sich alle Duplikatwerte in der aggregierten Zeichenfolge nebeneinander befinden.
Baodad

2
Das ist , was ORDER BY Num2erreicht ist es nicht (siehe hier ). Oder möchten Sie nur darauf hinweisen, dass Sie das ORDER BY benötigen, damit es funktioniert?
Jack Douglas

13

Soweit ich sehen kann, ist dies mit der derzeit verfügbaren Sprachspezifikation die kürzeste, um das zu erreichen, was Sie wollen, wenn es erledigt werden muss listagg.

select distinct
       a.Num1, 
       b.num2s
  from listaggtest a cross join (
       select listagg(num2d, '-') within group (order by num2d) num2s 
       from (
         select distinct Num2 num2d from listaggtest
       )
      ) b;

Welche Lösung war schlechter als die benutzerdefinierte Gesamtlösung ?


Dies funktioniert, aber es müssen zwei vollständige Tabellenscans durchgeführt werden.
Leigh Riffel

Wenn Sie eine kleine Tabelle haben, die Sie aggregieren müssen (<100000 Zeilen), ist die Leistung für einen einfachen Abruf mehr als akzeptabel. Dies war die Lösung meiner Wahl, nachdem ich fast eine Stunde lang alle möglichen Möglichkeiten ausprobiert hatte!
Mathieu Dumoulin

Dies funktioniert auch, wenn bei Duplikaten der Zwischenwert über 4000 Zeichen liegt. Das macht es sicherer als die regexpLösung.
Gordon Linoff

8

Erstellen Sie dazu eine benutzerdefinierte Aggregatfunktion .

Die Oracle-Datenbank bietet eine Reihe vordefinierter Aggregatfunktionen wie MAX, MIN, SUM, um Operationen an einer Reihe von Datensätzen auszuführen. Diese vordefinierten Aggregatfunktionen können nur mit skalaren Daten verwendet werden. Sie können jedoch Ihre eigenen benutzerdefinierten Implementierungen dieser Funktionen erstellen oder ganz neue Aggregatfunktionen definieren, die für komplexe Daten verwendet werden, z. B. für Multimediadaten, die mit Objekttypen, undurchsichtigen Typen und LOBs gespeichert werden.

Benutzerdefinierte Aggregatfunktionen werden in SQL-DML-Anweisungen genau wie die in die Oracle-Datenbank integrierten Aggregate verwendet. Sobald solche Funktionen beim Server registriert sind, ruft die Datenbank einfach die Aggregationsroutinen auf, die Sie anstelle der nativen Routinen angegeben haben.

Benutzerdefinierte Aggregate können auch mit skalaren Daten verwendet werden. Beispielsweise kann es sinnvoll sein, spezielle Aggregatfunktionen für die Arbeit mit komplexen statistischen Daten zu implementieren, die mit finanziellen oder wissenschaftlichen Anwendungen verbunden sind.

Benutzerdefinierte Aggregate sind eine Funktion des Extensibility Framework. Sie implementieren sie mit ODCIAggregate-Schnittstellenroutinen.


8

Obwohl dies ein alter Beitrag mit einer akzeptierten Antwort ist, denke ich, dass die LAG () - Analysefunktion in diesem Fall gut funktioniert und bemerkenswert ist:

  • LAG () entfernt doppelte Werte in Spalte 2 mit minimalem Aufwand
  • Es ist kein nicht trivialer regulärer Ausdruck zum Filtern der Ergebnisse erforderlich
  • Nur ein vollständiger Tabellenscan (Kosten = 4 für einfache Beispieltabelle)

Hier ist der vorgeschlagene Code:

with nums as (
SELECT 
    num1, 
    num2, 
    decode( lag(num2) over (partition by null order by num2), --get last num2, if any
            --if last num2 is same as this num2, then make it null
            num2, null, 
            num2) newnum2
  FROM ListAggTest
) 
select 
  num1, 
  --listagg ignores NULL values, so duplicates are ignored
  listagg( newnum2,'-') WITHIN GROUP (ORDER BY Num2) OVER () num2s
  from nums;

Die folgenden Ergebnisse scheinen den Wünschen des OP zu entsprechen:

NUM1  NUM2S       
1   2-3-4-5-6
2   2-3-4-5-6
3   2-3-4-5-6
4   2-3-4-5-6
5   2-3-4-5-6
6   2-3-4-5-6 

7

Hier war meine Lösung für das Problem, das meiner Meinung nach nicht so gut ist wie die Verwendung unserer bereits vorhandenen benutzerdefinierten Aggregatfunktion.

SELECT Num1, listagg(Num2,'-') WITHIN GROUP (ORDER BY NULL) OVER () Num2s FROM (
  SELECT Num1, DECODE(ROW_NUMBER() OVER (PARTITION BY Num2 ORDER BY NULL),
     1,Num2,NULL) Num2 FROM ListAggTest
);

5

Verwenden Sie stattdessen WMSYS.WM_Concat.

SELECT Num1, Replace(Wm_Concat(DISTINCT Num2) OVER (), ',', '-')
FROM ListAggTest;

Hinweis: Diese Funktion ist nicht dokumentiert und wird nicht unterstützt. Siehe https://forums.oracle.com/forums/message.jspa?messageID=4372641#4372641 .


6
Wenn Sie den Oracle-Support anrufen und das Problem verwenden wm_concat(auch wenn Sie argumentieren, dass dies wm_concatnicht das Problem selbst ist) , kann dies zu einer Ablehnung der Hilfe führen, da es nicht dokumentiert und nicht unterstützt wird. Dies ist nicht der Fall, wenn Sie ein benutzerdefiniertes Aggregat oder ein anderes Aggregat verwenden Unterstützte Funktion.
Jack Douglas

5

Sie können auch eine collect-Anweisung verwenden und dann eine benutzerdefinierte pl / sql-Funktion schreiben, die die Auflistung in eine Zeichenfolge konvertiert.

CREATE TYPE varchar2_ntt AS TABLE OF VARCHAR2(4000);
CREATE TYPE varchar2_ntt AS TABLE OF VARCHAR2(4000);

select cast(collect(distinct num2 order by num2) as varchar2_ntt) 
from listaggtest

Sie können distinctund order byin einer collectKlausel verwenden, aber wenn kombiniert distinct, funktioniert das nicht ab 11.2.0.2 :(

Problemumgehung kann eine Unterauswahl sein:

select collect(num2 order by num2) 
from 
( 
    select distinct num2 
    from listaggtest
)

Ich verstehe nicht, wie eine benutzerdefinierte PL / SQL-Funktion besser wäre als eine benutzerdefinierte Aggregatfunktion. Das resultierende SQL ist für letztere sicherlich einfacher. Da dieses Problem bei 11.2.0.2 auftrat, fügte die Unterauswahl einen zusätzlichen Scan hinzu, den ich zu vermeiden versuchte.
Leigh Riffel

Ich würde sagen, eine PL / SQL-Funktion mit dem Namen ONCE zum Konvertieren der Auflistung in einen String könnte besser sein als die tausendfach aufgerufene Aggregatfunktion. Ich denke, dies würde die Kontextwechsel stark reduzieren.
Nico

Ihre Theorie hört sich gut an und war einer der Gründe, warum ich die benutzerdefinierte Aggregatfunktion vermieden und eine integrierte Aggregatfunktion wie LISTAGG vorgezogen habe. Wenn Sie einige Zeitvergleiche durchführen möchten, interessieren mich die Ergebnisse.
Leigh Riffel

2

Ich habe diese Lösung erstellt, bevor ich auf ListAgg gestoßen bin, aber es gibt immer noch Gelegenheiten, z. B. dieses Problem mit doppelten Werten. Dann ist dieses Tool nützlich. Die folgende Version enthält 4 Argumente, mit denen Sie die Ergebnisse steuern können.

Erläuterung CLOBlist verwendet den Konstruktor CLOBlistParam als Parameter. CLOBlistParam hat 4 Argumente

string VARCHAR2(4000) - The variable to be aggregated
delimiter VARCHAR2(100) - The delimiting string
initiator VARCHAR2(100) - An initial string added before the first value only.
no_dup VARCHAR2(1) - A flag. Duplicates are suppressed if this is Y

Anwendungsbeispiel

--vertical list of comma separated values, no duplicates.
SELECT CLOBlist(CLOBlistParam(column_name,chr(10)||',','','Y')) FROM user_tab_columns
--simple csv
SELECT CLOBlist(CLOBlistParam(table_name,',','','N')) FROM user_tables

Der Link zu Gist ist unten.

https://gist.github.com/peter-genesys/d203bfb3d88d5a5664a86ea6ee34eeca] 1


-- Program  : CLOBlist 
-- Name     : CLOB list 
-- Author   : Peter Burgess
-- Purpose  : CLOB list aggregation function for SQL
-- RETURNS CLOB - to allow for more than 4000 chars to be returned by SQL
-- NEW type CLOBlistParam  - allows for definition of the delimiter, and initiator of sequence
------------------------------------------------------------------
--This is an aggregating function for use in SQL.
--It takes the argument and creates a comma delimited list of each instance.

WHENEVER SQLERROR CONTINUE
DROP TYPE CLOBlistImpl;
WHENEVER SQLERROR EXIT FAILURE ROLLBACK

create or replace type CLOBlistParam as object(
  string    VARCHAR2(4000)
 ,delimiter VARCHAR2(100)  
 ,initiator VARCHAR2(100)  
 ,no_dup    VARCHAR2(1)    )
/
show error

--Creating CLOBlist()
--Implement the type CLOBlistImpl to contain the ODCIAggregate routines.
create or replace type CLOBlistImpl as object
(
  g_list CLOB, -- progressive concatenation
  static function ODCIAggregateInitialize(sctx IN OUT CLOBlistImpl)
    return number,
  member function ODCIAggregateIterate(self  IN OUT CLOBlistImpl
                                     , value IN     CLOBlistParam) return number,
  member function ODCIAggregateTerminate(self        IN  CLOBlistImpl
                                       , returnValue OUT CLOB
                                       , flags       IN  number) return number,
  member function ODCIAggregateMerge(self IN OUT CLOBlistImpl
                                   , ctx2 IN     CLOBlistImpl) return number
)
/
show error


--Implement the type body for CLOBlistImpl.
create or replace type body CLOBlistImpl is
static function ODCIAggregateInitialize(sctx IN OUT CLOBlistImpl)
return number is
begin

  sctx := CLOBlistImpl(TO_CHAR(NULL));
  return ODCIConst.Success;
end;

member function ODCIAggregateIterate(self  IN OUT CLOBlistImpl
                                   , value IN     CLOBlistParam) return number is
begin

   IF self.g_list IS NULL THEN
     self.g_list := value.initiator||value.string;
   ELSIF value.no_dup = 'Y' AND
         value.delimiter||self.g_list||value.delimiter LIKE '%'||value.delimiter||value.string||value.delimiter||'%' 
         THEN
     --Do not include duplicate value    
     NULL;
  ELSE
     self.g_list := self.g_list||value.delimiter||value.string;
   END IF;

  return ODCIConst.Success;
end;

member function ODCIAggregateTerminate(self        IN  CLOBlistImpl
                                     , returnValue OUT CLOB
                                     , flags       IN  number) return number is
begin
  returnValue := self.g_list;
  return ODCIConst.Success;
end;

member function ODCIAggregateMerge(self IN OUT CLOBlistImpl
                                 , ctx2 IN     CLOBlistImpl) return number is
begin

  self.g_list := LTRIM( self.g_list||','||ctx2.g_list,',');

  return ODCIConst.Success;
end;
end;
/
show error

--Using CLOBlist() to create a vertical list of comma separated values

--  SELECT CLOBlist(CLOBlistParam(product_code,chr(10)||',','','Y'))
--  FROM   account


--DROP FUNCTION CLOBlist
--/

PROMPT Create the user-defined aggregate.
CREATE OR REPLACE FUNCTION CLOBlist (input CLOBlistParam) RETURN CLOB
PARALLEL_ENABLE AGGREGATE USING CLOBlistImpl;
/
show error

1

Ich weiß, dass es irgendwann nach dem ursprünglichen Posting ist, aber dies war der erste Punkt, an dem ich nach Googeln nach einer Antwort auf dasselbe Problem gesucht habe und dachte, jemand anderes, der hier gelandet ist, könnte sich freuen, eine prägnante Antwort zu finden, die nicht auf übermäßig komplizierten Abfragen beruht oder Regexes.

So erhalten Sie das gewünschte Ergebnis:

with nums as (
  select distinct num2 distinct_nums
  from listaggtest
  order by num2
) select num1,
         (select listagg(distinct_nums, '-') within group (order by 1) from nums) nums2list 
         from listaggtest;

1

Meine Idee ist es, eine gespeicherte Funktion wie folgt zu implementieren:

CREATE TYPE LISTAGG_DISTINCT_PARAMS AS OBJECT (ELEMENTO VARCHAR2(2000), SEPARATORE VARCHAR2(10));

CREATE TYPE T_LISTA_ELEMENTI AS TABLE OF VARCHAR2(2000);

CREATE TYPE T_LISTAGG_DISTINCT AS OBJECT (

    LISTA_ELEMENTI T_LISTA_ELEMENTI,
        SEPARATORE VARCHAR2(10),

    STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX  IN OUT            T_LISTAGG_DISTINCT) 
                    RETURN NUMBER,

    MEMBER FUNCTION ODCIAGGREGATEITERATE   (SELF  IN OUT            T_LISTAGG_DISTINCT, 
                                            VALUE IN                    LISTAGG_DISTINCT_PARAMS ) 
                    RETURN NUMBER,

    MEMBER FUNCTION ODCIAGGREGATETERMINATE (SELF         IN     T_LISTAGG_DISTINCT,
                                            RETURN_VALUE OUT    VARCHAR2, 
                                            FLAGS        IN     NUMBER      )
                    RETURN NUMBER,

    MEMBER FUNCTION ODCIAGGREGATEMERGE       (SELF               IN OUT T_LISTAGG_DISTINCT,
                                                                                        CTX2                 IN         T_LISTAGG_DISTINCT    )
                    RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY T_LISTAGG_DISTINCT IS 

    STATIC FUNCTION ODCIAGGREGATEINITIALIZE(SCTX IN OUT T_LISTAGG_DISTINCT) RETURN NUMBER IS 
    BEGIN
                SCTX := T_LISTAGG_DISTINCT(T_LISTA_ELEMENTI() , ',');
        RETURN ODCICONST.SUCCESS;
    END;

    MEMBER FUNCTION ODCIAGGREGATEITERATE(SELF IN OUT T_LISTAGG_DISTINCT, VALUE IN LISTAGG_DISTINCT_PARAMS) RETURN NUMBER IS
    BEGIN

                IF VALUE.ELEMENTO IS NOT NULL THEN
                        SELF.LISTA_ELEMENTI.EXTEND;
                        SELF.LISTA_ELEMENTI(SELF.LISTA_ELEMENTI.LAST) := TO_CHAR(VALUE.ELEMENTO);
                        SELF.LISTA_ELEMENTI:= SELF.LISTA_ELEMENTI MULTISET UNION DISTINCT SELF.LISTA_ELEMENTI;
                        SELF.SEPARATORE := VALUE.SEPARATORE;
                END IF;
        RETURN ODCICONST.SUCCESS;
    END;

    MEMBER FUNCTION ODCIAGGREGATETERMINATE(SELF IN T_LISTAGG_DISTINCT, RETURN_VALUE OUT VARCHAR2, FLAGS IN NUMBER) RETURN NUMBER IS
      STRINGA_OUTPUT            CLOB:='';
            LISTA_OUTPUT                T_LISTA_ELEMENTI;
            TERMINATORE                 VARCHAR2(3):='...';
            LUNGHEZZA_MAX           NUMBER:=4000;
    BEGIN

                IF SELF.LISTA_ELEMENTI.EXISTS(1) THEN -- se esiste almeno un elemento nella lista

                        -- inizializza una nuova lista di appoggio
                        LISTA_OUTPUT := T_LISTA_ELEMENTI();

                        -- riversamento dei soli elementi in DISTINCT
                        LISTA_OUTPUT := SELF.LISTA_ELEMENTI MULTISET UNION DISTINCT SELF.LISTA_ELEMENTI;

                        -- ordinamento degli elementi
                        SELECT CAST(MULTISET(SELECT * FROM TABLE(LISTA_OUTPUT) ORDER BY 1 ) AS T_LISTA_ELEMENTI ) INTO LISTA_OUTPUT FROM DUAL;

                        -- concatenazione in una stringa                        
                        FOR I IN LISTA_OUTPUT.FIRST .. LISTA_OUTPUT.LAST - 1
                        LOOP
                            STRINGA_OUTPUT := STRINGA_OUTPUT || LISTA_OUTPUT(I) || SELF.SEPARATORE;
                        END LOOP;
                        STRINGA_OUTPUT := STRINGA_OUTPUT || LISTA_OUTPUT(LISTA_OUTPUT.LAST);

                        -- se la stringa supera la dimensione massima impostata, tronca e termina con un terminatore
                        IF LENGTH(STRINGA_OUTPUT) > LUNGHEZZA_MAX THEN
                                    RETURN_VALUE := SUBSTR(STRINGA_OUTPUT, 0, LUNGHEZZA_MAX - LENGTH(TERMINATORE)) || TERMINATORE;
                        ELSE
                                    RETURN_VALUE:=STRINGA_OUTPUT;
                        END IF;

                ELSE -- se non esiste nessun elemento, restituisci NULL

                        RETURN_VALUE := NULL;

                END IF;

        RETURN ODCICONST.SUCCESS;
    END;

    MEMBER FUNCTION ODCIAGGREGATEMERGE(SELF IN OUT T_LISTAGG_DISTINCT, CTX2 IN T_LISTAGG_DISTINCT) RETURN NUMBER IS
    BEGIN
        RETURN ODCICONST.SUCCESS;
    END;

END; -- fine corpo

CREATE
FUNCTION LISTAGG_DISTINCT (INPUT LISTAGG_DISTINCT_PARAMS) RETURN VARCHAR2
    PARALLEL_ENABLE AGGREGATE USING T_LISTAGG_DISTINCT;

// Example
SELECT LISTAGG_DISTINCT(LISTAGG_DISTINCT_PARAMS(OWNER, ', ')) AS LISTA_OWNER
FROM SYS.ALL_OBJECTS;

Es tut mir leid, aber in einigen Fällen (für einen sehr großen Satz) könnte Oracle diesen Fehler zurückgeben:

Object or Collection value was too large. The size of the value
might have exceeded 30k in a SORT context, or the size might be
too big for available memory.

aber ich denke das ist ein guter startpunkt;)


Beachten Sie, dass das OP bereits eine eigene benutzerdefinierte LISTAGGFunktion hatte. Sie versuchten ausdrücklich, mithilfe der integrierten LISTAGGFunktion, die ab Version 11.2 verfügbar ist , eine effiziente Möglichkeit zu finden, dies zu tun .
RDFozz

0

Probier diese:

select num1,listagg(Num2,'-') WITHIN GROUP (ORDER BY NULL) Num2s 
from (
select distinct num1
    ,b.num2
from listaggtest a
    ,(
        select num2
        from listaggtest
    ) b
    order by 1,2
    )
group by num1

Das Problem mit anderen möglichen Lösungen besteht darin, dass es keine Korrelation zwischen den Ergebnissen für Spalte 1 und Spalte 2 gibt. Um dies zu umgehen, erstellt die innere Abfrage diese Korrelation und entfernt dann die Duplikate aus dieser Ergebnismenge. Wenn Sie das Listagg ausführen, ist die Ergebnismenge bereits bereinigt. Das Problem bestand eher darin, die Daten in ein verwendbares Format zu bringen.


1
Vielleicht möchten Sie eine Erklärung hinzufügen, wie es funktioniert.
Jkavalik

Danke für die Antwort und willkommen auf der Seite. Es könnte sogar noch hilfreicher sein, wenn Sie beschreiben könnten, warum dies funktioniert und wie es helfen würde.
Tom V

Ich habe versucht, die Antwort zu aktualisieren, aber es bleibt fehlerhaft. --- Das Problem mit anderen möglichen Lösungen ist, dass es keine Korrelation zwischen den Ergebnissen für Spalte 1 und Spalte 2 gibt. Um dies zu umgehen, erstellt die innere Abfrage diese Korrelation und entfernt dann die Duplikate aus dieser Ergebnismenge. Wenn Sie das Listagg ausführen, ist die Ergebnismenge bereits bereinigt. Das Problem bestand eher darin, die Daten in ein verwendbares Format zu bringen.
Kevin

-2

SQL wurde als einfache Sprache entwickelt, sehr nah an Englisch. Warum schreibst du es nicht so wie auf Englisch?

  1. Duplikate auf num2 entfernen & listagg als Aggregatfunktion verwenden - nicht analytisch, um Concat on String zu berechnen
  2. Verbinden Sie sich mit dem Original, da Sie eine Ergebniszeile für eine Eingabe benötigen

select num1, num2s
  from (select num2,
               listagg(num2, '-') within group(order by num2) over() num2s
          from listaggtest
         group by num2
       )
  join listaggtest using (num2);


Danke für Ihre Antwort. Diese Lösung erfordert zwei vollständige Tabellenscans, liefert jedoch vor allem nicht die korrekten Ergebnisse.
Leigh Riffel

Entschuldigung, ich habe eine ältere und falsche Version eingefügt.
Stefan Oravec

-2
SELECT Num1, listagg(Num2,'-') WITHIN GROUP
(ORDER BY num1) OVER () Num2s FROM 
(select distinct num1 from listAggTest) a,
(select distinct num2 from ListAggTest) b
where num1=num2(+);

Dies gibt die korrekten Ergebnisse für die angegebenen Daten zurück, hat jedoch eine falsche Annahme. Num1 und Num2 haben nichts miteinander zu tun. Num1 könnte genauso gut Char1 sein, das die Werte a, e, i, o, u, y enthält. Unabhängig davon erfordert diese Lösung zwei vollständige Durchsuchungen der Tabelle, die den gesamten Zweck der Verwendung der Aggregatfunktion erfüllen. Wenn die Lösung zwei Tabellenscans zulässt, ist dies vorzuziehen (bei den Beispieldaten sind die Kosten niedriger als bei allen anderen). SELECT Num1, ( SELECT LISTAGG(Num2) WITHIN GROUP (ORDER BY Num2) FROM (SELECT distinct Num2 FROM listAggTest) ) Num2 FROM ListAggTest;
Leigh Riffel

-2

Die effektivste Lösung ist inner SELECT mit GROUP BY, da DISTINCT und reguläre Ausdrücke nur langsam sind.

SELECT num1, LISTAGG(num2, '-') WITHIN GROUP (ORDER BY num2) AS num2s
    FROM (SELECT num1, num2
              FROM ListAggTest
              GROUP BY num1, num2)
    GROUP BY num1;

Diese Lösung ist ziemlich einfach: Zuerst erhalten Sie alle eindeutigen Kombinationen von num1 und num2 (inneres SELECT) und dann die Zeichenfolge aller num2, die nach num1 gruppiert sind.


Diese Abfrage gibt die angeforderten Ergebnisse nicht zurück. Es werden die gleichen Ergebnisse wie zurückgegeben SELECT * FROM ListAggTest;.
Leigh Riffel

In seiner Verteidigung, er war wohl zu dieser Lösung aus einem anderen Stackoverflow Problem hingewiesen doppelt markiert , dass diese Lösung funktioniert fix. dass ‚s die Lösung , die ich wollte. Es scheint, dass ich andere Annahmen treffen muss, um meinen eigenen Take zu veröffentlichen, und deshalb lasse ich diese Frage mit diesem Kommentar in Ruhe.
Gerard ONeill
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.