Wyeliminuj duplikaty w ListAgg (Oracle)


44

Przed wersją Oracle 11.2 korzystałem z niestandardowej funkcji agregującej, aby połączyć kolumnę w wiersz. 11.2 Dodano LISTAGGfunkcję, więc staram się jej użyć. Mój problem polega na tym, że muszę wyeliminować duplikaty wyników i wydaje się, że nie jestem w stanie tego zrobić.

Oto przykład.

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

Chcę to zobaczyć:

      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

Oto listaggwersja, która jest bliska, ale nie eliminuje duplikatów.

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

Mam rozwiązanie, ale jest to gorsze niż dalsze korzystanie z niestandardowej funkcji agregującej.


Powinien order by nullbyć, order by Num2czy się mylę?
Jack Douglas,

@Jack - To nie ma znaczenia dla duplikatu eliminacji. W zależności od zastosowania może być pożądane.
Leigh Riffel,

westchnienie LISTAGG wciąż nie spełnia STRAGGSTRAGG(DISTINCT ...)
wymagań

Wreszcie jest to możliwe: LISTAGG DISTINCT
lad2025

Odpowiedzi:


32

Możesz użyć wyrażeń regularnych i regexp_replaceusunąć duplikaty po połączeniu z listagg:

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

Może to być ładniejsze, jeśli smak wyrażenia regularnego Oracle wspierał patrzenie w przód lub grupy nie przechwytywania, ale tak nie jest .

Jednak to rozwiązanie pozwala uniknąć skanowania źródła więcej niż raz.

DBFiddle tutaj


Zauważ, że aby ta technika REGEX_REPLACE działała w usuwaniu duplikatów, wszystkie wartości duplikatów muszą znajdować się obok siebie w zagregowanym ciągu.
Baodad

2
To, co ORDER BY Num2osiąga, nie jest (zobacz tutaj ). Czy po prostu próbujesz wskazać, że potrzebujesz ORDER BY, aby działał?
Jack Douglas,

13

O ile mi wiadomo , przy obecnie dostępnej specyfikacji języka jest to najkrótszy czas na osiągnięcie tego, co chcesz, jeśli trzeba to zrobić 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;

Jakie było Twoje rozwiązanie gorsze od niestandardowego rozwiązania agregującego ?


To działa, ale musi wykonać dwa pełne skanowanie tabeli.
Leigh Riffel,

Gdy masz małą tabelę, którą musisz agregować (<100000 wierszy), wydajność jest bardziej niż akceptowalna dla prostego wyszukiwania. Takie było moje rozwiązanie po prawie godzinie testowania każdej możliwej drogi!
Mathieu Dumoulin,

Działa to również wtedy, gdy duplikaty umieściłyby wartość pośrednią na ponad 4000 znaków. Dzięki temu jest bezpieczniejszy niż regexprozwiązanie.
Gordon Linoff,

8

Utwórz w tym celu niestandardową funkcję agregującą .

Baza danych Oracle udostępnia szereg predefiniowanych funkcji agregujących, takich jak MAX, MIN, SUM, do wykonywania operacji na zestawie rekordów. Te predefiniowane funkcje agregujące mogą być używane tylko z danymi skalarnymi. Można jednak tworzyć własne niestandardowe implementacje tych funkcji lub definiować zupełnie nowe funkcje agregujące, aby używać ich ze złożonymi danymi - na przykład z danymi multimedialnymi przechowywanymi przy użyciu typów obiektów, typów nieprzezroczystych i obiektów LOB.

Funkcje agregujące zdefiniowane przez użytkownika są używane w instrukcjach SQL DML, podobnie jak wbudowane agregaty bazy danych Oracle. Po zarejestrowaniu takich funkcji na serwerze baza danych po prostu wywołuje podane przez Ciebie procedury agregacji zamiast natywnych.

Agregaty zdefiniowane przez użytkownika mogą być również używane z danymi skalarnymi. Na przykład warto wdrożyć specjalne funkcje agregujące do pracy ze złożonymi danymi statystycznymi związanymi z aplikacjami finansowymi lub naukowymi.

Agregaty zdefiniowane przez użytkownika są cechą Extensibility Framework. Wdrażasz je za pomocą procedur interfejsu ODCIAggregate.


8

Chociaż jest to stary post z zaakceptowaną odpowiedzią, myślę, że funkcja analityczna LAG () działa dobrze w tym przypadku i jest godna uwagi:

  • LAG () usuwa zduplikowane wartości w kolumnie num2 przy minimalnym koszcie
  • Nie potrzeba trywialnego wyrażenia regularnego do filtrowania wyników
  • Tylko jeden pełny skan tabeli (koszt = 4 na prostej tabeli przykładowej)

Oto proponowany kod:

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;

Poniższe wyniki wydają się być zgodne z oczekiwaniami PO:

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

Oto moje rozwiązanie problemu, który moim zdaniem nie jest tak przyjemny, jak użycie naszej niestandardowej funkcji agregującej, która już istnieje.

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

Zamiast tego użyj WMSYS.WM_Concat.

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

Uwaga: Ta funkcja jest nieudokumentowana i nie jest obsługiwana. Zobacz https://forums.oracle.com/forums/message.jspa?messageID=4372641#4372641 .


6
Jeśli zadzwonisz do działu wsparcia Oracle i używasz wm_concat(nawet jeśli argumentujesz, że wm_concatsam nie powoduje problemu) , mieliby podstawy do odmowy udzielenia pomocy, ponieważ jest to nieudokumentowane i nieobsługiwane - nie w przypadku korzystania z niestandardowego agregatu lub innego obsługiwana funkcja.
Jack Douglas,

5

Możesz także użyć instrukcji Collect, a następnie napisać niestandardową funkcję pl / sql, która konwertuje kolekcję na ciąg znaków.

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

Można używać distincti order byw collectklauzuli ale jeśli połączyła distinctnie będzie działać jak od 11.2.0.2 :(

Obejściem może być podselekcja:

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

Nie widzę, w jaki sposób niestandardowa funkcja pl / sql byłaby lepsza niż niestandardowa funkcja agregująca. Wynikowy SQL jest z pewnością prostszy dla tych drugich. Ponieważ ten problem dotyczył wersji 11.2.0.2, podselekcja dodałaby dodatkowy skan, którego próbowałem uniknąć.
Leigh Riffel,

Powiedziałbym, że funkcja PL / SQL o nazwie ONCE do konwersji kolekcji na ciąg może być lepsza niż funkcja agregująca wywoływana tysiące razy. Myślę, że to znacznie zmniejszy przełączniki kontekstu.
Nico,

Twoja teoria brzmi dobrze i był jednym z powodów, dla których starałem się unikać niestandardowej funkcji agregującej i wolałem wbudowaną funkcję agregującą, taką jak LISTAGG. Jeśli chcesz dokonać porównań czasowych, byłbym zainteresowany wynikami.
Leigh Riffel,

2

Stworzyłem to rozwiązanie, zanim zetknąłem się z ListAgg, ale wciąż zdarzają się takie sytuacje, jak na przykład problem zduplikowanej wartości, wtedy to narzędzie jest przydatne. Poniższa wersja zawiera 4 argumenty, które dają ci kontrolę nad wynikami.

Objaśnienie CLOBlist przyjmuje jako parametr parametr CLOBlistParam contructor. CLOBlistParam ma 4 argumenty

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

Przykładowe użycie

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

Link do Gist znajduje się poniżej.

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

Wiem, że to było kiedyś po opublikowaniu, ale było to pierwsze miejsce, które znalazłem po Googlingu, aby uzyskać odpowiedź na ten sam problem i pomyślałem, że ktoś, kto tu wylądował, może z przyjemnością znaleźć zwięzłą odpowiedź, która nie opiera się na zbyt skomplikowanych zapytaniach lub wyrażenia regularne.

To da pożądany rezultat:

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

Moim pomysłem jest zaimplementowanie takiej funkcji przechowywanej:

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;

Przykro mi, ale w niektórych przypadkach (dla bardzo dużego zestawu) Oracle może zwrócić ten błąd:

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.

ale myślę, że to dobry początek;)


Zauważ, że OP miał już własną LISTAGGfunkcję niestandardową ; wyraźnie próbowali sprawdzić, czy mogą znaleźć skuteczny sposób, aby to zrobić za pomocą wbudowanej LISTAGGfunkcji dostępnej od wersji 11.2.
RDFozz

0

Spróbuj tego:

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

Problem z innymi możliwymi rozwiązaniami polega na tym, że nie ma korelacji między wynikami dla kolumny 1 i kolumny 2. Aby obejść ten problem, wewnętrzne zapytanie tworzy tę korelację, a następnie usuwa duplikaty z tego zestawu wyników. Po wykonaniu listagg zestaw wyników jest już czysty. problem miał więcej wspólnego z uzyskaniem danych w użytecznym formacie.


1
Możesz dodać wyjaśnienie, jak to działa.
jkavalik

Dziękujemy za odpowiedź i witamy na stronie. Może być jeszcze bardziej pomocny, jeśli możesz opisać, dlaczego to działa i jak mogłoby to pomóc.
Tom V

Próbowałem zaktualizować odpowiedź, ale nadal występuje błąd. --- Problem z innymi możliwymi rozwiązaniami polega na tym, że nie ma korelacji między wynikami dla kolumny 1 i kolumny 2. Aby obejść ten problem, wewnętrzne zapytanie tworzy tę korelację, a następnie usuwa duplikaty z tego zestawu wyników. Po wykonaniu listagg zestaw wyników jest już czysty. problem miał więcej wspólnego z uzyskaniem danych w użytecznym formacie.
Kevin

-2

SQL został zaprojektowany jako prosty język, bardzo zbliżony do angielskiego. Dlaczego więc nie napiszesz tego po angielsku?

  1. wyeliminuj duplikaty na num2 i użyj listagg jako funkcji agregującej - nie analitycznej, aby obliczyć konkat na łańcuchu
  2. dołącz do oryginału, jak chcesz jeden wiersz wyników dla jednego wejścia

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


Dziękuję za odpowiedź. To rozwiązanie wymaga dwóch pełnych skanów tabeli, ale co ważniejsze, nie zwraca poprawnych wyników.
Leigh Riffel,

Przepraszam za to, że wkleiłem starszą i niepoprawną wersję.
Štefan 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(+);

Zwraca to prawidłowe wyniki dla podanych danych, ale ma błędne założenie. Num1 i Num2 nie są ze sobą powiązane. Num1 może równie dobrze być Char1 zawierającym wartości a, e, i, o, u, y. Bez względu na to, rozwiązanie to wymaga dwóch pełnych skanów tabeli, co przekreśla cały cel użycia funkcji agregującej. Jeśli rozwiązanie pozwoliło na dwa skanowanie tabeli, byłoby to preferowane (przy przykładowych danych ma niższy koszt niż cokolwiek innego). SELECT Num1, ( SELECT LISTAGG(Num2) WITHIN GROUP (ORDER BY Num2) FROM (SELECT distinct Num2 FROM listAggTest) ) Num2 FROM ListAggTest;
Leigh Riffel

-2

Najbardziej skutecznym rozwiązaniem jest wewnętrzne WYBIERZ w GROUP BY, ponieważ DISTINCT i wyrażenia regularne są powolne jak diabli.

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

To rozwiązanie jest dość proste - najpierw otrzymujesz wszystkie unikalne kombinacje num1 i num2 (wewnętrzny WYBÓR), a następnie ciąg wszystkich num2 pogrupowanych według num1.


To zapytanie nie zwraca żądanych wyników. Zwraca te same wyniki co SELECT * FROM ListAggTest;.
Leigh Riffel,

W jego obronie, był prawdopodobnie wskazywał na to rozwiązanie z innego problemu stackoverflow oznaczonego duplikat, że to rozwiązanie ma poprawkę. to jest rozwiązanie, które chciałem. Wydaje się, że muszę przyjąć inne założenia, aby opublikować własne zdanie, dlatego zostawię to pytanie w spokoju z tym komentarzem.
Gerard ONeill
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.