กำจัดรายการที่ซ้ำกันใน ListAgg (Oracle)


44

ก่อนหน้า Oracle 11.2 ฉันใช้ฟังก์ชันการรวมแบบกำหนดเองเพื่อต่อคอลัมน์เข้ากับแถว 11.2 เพิ่มLISTAGGฟังก์ชั่นดังนั้นฉันพยายามจะใช้มันแทน ปัญหาของฉันคือฉันต้องกำจัดรายการที่ซ้ำกันในผลลัพธ์และดูเหมือนจะไม่สามารถทำได้

นี่คือตัวอย่าง

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

สิ่งที่ฉันต้องการเห็นคือ:

      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

นี่คือlistaggเวอร์ชันที่ใกล้เคียงกัน แต่ไม่ได้กำจัดสิ่งที่ซ้ำกัน

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

ฉันมีวิธีแก้ไข แต่มันแย่กว่าการใช้ฟังก์ชั่นรวมแบบกำหนดเองต่อไป


ควรorder by nullจะเป็นorder by Num2หรือฉันการสับสน?
แจ็คดักลาส

@Jack - มันไม่ต่างกับการกำจัดซ้ำ ขึ้นอยู่กับการใช้งานของคุณมันอาจเป็นที่ต้องการ
Leigh Riffel

ถอนหายใจ LISTAGGยังSTRAGGSTRAGG(DISTINCT ...)
คงขาด

ในที่สุดก็เป็นไปได้: LISTAGG DISTINCT
lad2025

คำตอบ:


32

คุณสามารถใช้นิพจน์ทั่วไปและregexp_replaceลบรายการที่ซ้ำกันหลังจากเชื่อมต่อกันด้วยlistagg:

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

สิ่งนี้อาจเป็นเรื่องที่น่าสนใจมากขึ้นถ้ารสชาติ regex ของ Oracle รองรับกลุ่ม lookahead หรือกลุ่มที่ไม่ได้จับภาพแต่ก็ไม่เป็นเช่นนั้น

อย่างไรก็ตามวิธีนี้จะหลีกเลี่ยงการสแกนต้นฉบับมากกว่าหนึ่งครั้ง

DBFiddle ที่นี่


โปรดทราบว่าสำหรับเทคนิค REGEX_REPLACE นี้เพื่อใช้ในการลบรายการที่ซ้ำกันค่าที่ซ้ำกันจะต้องอยู่ติดกันในสตริงที่รวม
Baodad

2
นั่นคือสิ่งที่ORDER BY Num2ประสบความสำเร็จไม่ใช่ (ดูที่นี่ ) หรือคุณแค่พยายามชี้ให้เห็นว่าคุณต้องการ ORDER BY เพื่อให้ทำงาน
Jack Douglas

13

เท่าที่ผมสามารถมองเห็นกับสเปคภาษามีอยู่ในปัจจุบันนี้เป็นที่สั้นที่สุดเพื่อให้บรรลุสิ่งที่คุณต้องการถ้า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;

สิ่งที่เป็นวิธีการแก้ปัญหาของคุณที่เลวร้ายยิ่งกว่าการแก้ปัญหารวมที่กำหนดเอง ?


ใช้งานได้ แต่ต้องสแกนตารางเต็มสองแผ่น
Leigh Riffel

เมื่อคุณมีตารางเล็ก ๆ ที่คุณต้องรวม (<100000 แถว) ประสิทธิภาพนั้นดีเกินกว่าที่ยอมรับได้สำหรับการดึงข้อมูลอย่างง่าย นี่เป็นทางเลือกของฉันหลังจากผ่านการทดสอบไปได้เกือบหนึ่งชั่วโมง!
Mathieu Dumoulin

สิ่งนี้จะทำงานเมื่อรายการที่ซ้ำกันจะทำให้ค่ากลางมากกว่า 4,000 อักขระ ทำให้ปลอดภัยกว่าregexpโซลูชัน
Gordon Linoff

8

สร้างฟังก์ชันการรวมแบบกำหนดเองเพื่อทำสิ่งนี้

ฐานข้อมูล Oracle มีฟังก์ชันการรวมที่กำหนดไว้ล่วงหน้าจำนวนมากเช่น MAX, MIN, SUM สำหรับการดำเนินการกับชุดของระเบียน ฟังก์ชันการรวมที่กำหนดไว้ล่วงหน้าเหล่านี้สามารถใช้ได้กับข้อมูลสเกลาร์เท่านั้น อย่างไรก็ตามคุณสามารถสร้างการใช้งานที่กำหนดเองของคุณสำหรับฟังก์ชั่นเหล่านี้หรือกำหนดฟังก์ชั่นรวมใหม่ทั้งหมดเพื่อใช้กับข้อมูลที่ซับซ้อนเช่นกับข้อมูลมัลติมีเดียที่เก็บไว้โดยใช้ประเภทวัตถุชนิดทึบแสงและ LOBs

ฟังก์ชันการรวมที่ผู้ใช้กำหนดถูกใช้ในคำสั่ง SQL DML เช่นเดียวกับการรวมภายในฐานข้อมูล Oracle เมื่อฟังก์ชั่นดังกล่าวได้รับการลงทะเบียนกับเซิร์ฟเวอร์แล้วฐานข้อมูลจะเรียกใช้รูทีนการรวมที่คุณให้ไว้แทนการใช้งานเนทีฟ

มวลรวมที่ผู้ใช้กำหนดสามารถใช้กับข้อมูลสเกลาร์ได้เช่นกัน ตัวอย่างเช่นมันอาจจะคุ้มค่าที่จะใช้ฟังก์ชั่นรวมพิเศษสำหรับการทำงานกับข้อมูลสถิติที่ซับซ้อนที่เกี่ยวข้องกับการใช้งานทางการเงินหรือทางวิทยาศาสตร์

มวลรวมที่ผู้ใช้กำหนดเป็นคุณสมบัติของ Extensibility Framework คุณใช้พวกเขาโดยใช้ ODCIAggregate งานประจำของอินเทอร์เฟซ


8

แม้ว่านี่จะเป็นโพสต์เก่าที่มีคำตอบที่ยอมรับ แต่ฉันคิดว่าฟังก์ชั่นการวิเคราะห์ LAG () ทำงานได้ดีในกรณีนี้และเป็นที่น่าสังเกต:

  • LAG () ลบค่าที่ซ้ำกันในคอลัมน์ num2 ด้วยค่าใช้จ่ายน้อยที่สุด
  • ไม่จำเป็นต้องใช้นิพจน์ทั่วไปที่ไม่สำคัญเพื่อกรองผลลัพธ์
  • สแกนเต็มตารางเพียงครั้งเดียว (ราคา = 4 ในตารางตัวอย่างง่ายๆ)

นี่คือรหัสที่เสนอ:

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;

ผลลัพธ์ด้านล่างเป็นสิ่งที่ OP ต้องการ:

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

นี่คือวิธีแก้ไขปัญหาซึ่งในความคิดของฉันไม่ดีเท่ากับการใช้ฟังก์ชันการรวมแบบกำหนดเองซึ่งมีอยู่แล้ว

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

ใช้ WMSYS.WM_Concat แทน

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

หมายเหตุ: ฟังก์ชั่นนี้ไม่มีเอกสารและไม่สนับสนุน ดูhttps://forums.oracle.com/forums/message.jspa?messageID=4372641#4372641


6
หากคุณโทรหาฝ่ายสนับสนุนของ Oracle และคุณกำลังใช้wm_concat(แม้ว่าคุณจะเถียงwm_concatว่าไม่ได้เป็นสาเหตุของปัญหา) พวกเขามีเหตุผลที่จะปฏิเสธที่จะให้ความช่วยเหลือเพราะมันไม่มีเอกสารและไม่ได้รับการสนับสนุน - ไม่ใช่กรณีถ้าคุณใช้การรวมแบบกำหนดเองหรืออื่น ๆ คุณสมบัติที่รองรับ
แจ็คดักลาส

5

คุณยังสามารถใช้คำสั่งการรวบรวมแล้วเขียนฟังก์ชั่น pl / sql ที่กำหนดเองที่แปลงคอลเลกชันเป็นสตริง

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

คุณสามารถใช้distinctและorder byในcollectประโยค แต่ถ้ารวมกันdistinctจะไม่ทำงาน ณ 11.2.0.2 :(

วิธีแก้ปัญหาอาจเป็นการเลือกย่อย:

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

ฉันล้มเหลวที่จะดูว่าฟังก์ชั่น pl / sql ที่กำหนดเองจะดีกว่าฟังก์ชั่นรวมที่กำหนดเองได้อย่างไร SQL ที่เกิดขึ้นนั้นง่ายกว่าสำหรับหลัง เนื่องจากปัญหานี้เกิดขึ้นในวันที่ 11.2.0.2 การเลือกย่อยจะเพิ่มการสแกนเพิ่มเติมซึ่งฉันพยายามหลีกเลี่ยง
Leigh Riffel

ฉันจะบอกว่าฟังก์ชั่น PL / SQL ที่เรียกว่า ONCE เพื่อแปลงชุดเป็นสตริงอาจดีกว่าฟังก์ชั่นรวมที่เรียกว่าหลายพันครั้ง ฉันคิดว่าสิ่งนี้จะลดการสลับบริบทมาก
Nico

ทฤษฎีของคุณฟังดูดีและเป็นเหตุผลหนึ่งที่ฉันพยายามหลีกเลี่ยงฟังก์ชันการรวมแบบกำหนดเองและชอบการรวมฟังก์ชันแบบรวมเช่น LISTAGG หากคุณต้องการเปรียบเทียบเวลาฉันจะสนใจผลลัพธ์
Leigh Riffel

2

ฉันสร้างโซลูชันนี้ก่อนที่จะพบ ListAgg แต่ยังมีโอกาสเช่นปัญหาค่าซ้ำซ้อนเครื่องมือนี้มีประโยชน์ รุ่นด้านล่างมี 4 ข้อโต้แย้งเพื่อให้คุณควบคุมผลลัพธ์ได้

CLOBlist ใช้ตัวสร้าง CLOBlistParam เป็นพารามิเตอร์ CLOBlistParam มี 4 ข้อโต้แย้ง

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

ตัวอย่างการใช้งาน

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

ลิงก์ไปยังส่วนสำคัญอยู่ด้านล่าง

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

ฉันรู้ว่าบางครั้งหลังจากการโพสต์ดั้งเดิม แต่นี่เป็นจุดแรกที่ฉันพบหลังจาก Googling สำหรับคำตอบของปัญหาเดียวกันและคิดว่ามีคนอื่นที่ลงจอดที่นี่อาจมีความสุขที่จะพบคำตอบสั้น ๆ ที่ไม่ต้องใช้คำค้นหาที่ซับซ้อนมากเกินไป หรือ regexes

สิ่งนี้จะให้ผลลัพธ์ที่คุณต้องการ:

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

ความคิดของฉันคือการใช้ฟังก์ชั่นที่เก็บไว้เช่นนี้:

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;

ฉันขอโทษ แต่ในบางกรณี (สำหรับชุดใหญ่มาก) Oracle อาจส่งคืนข้อผิดพลาดนี้:

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.

แต่ฉันคิดว่านี่เป็นจุดเริ่มต้นที่ดี;)


โปรดทราบว่า OP มีLISTAGGฟังก์ชันที่กำหนดเองแล้ว พวกเขาพยายามอย่างชัดเจนเพื่อดูว่าพวกเขาสามารถหาวิธีที่มีประสิทธิภาพในการทำสิ่งนี้โดยใช้LISTAGGฟังก์ชั่นในตัวที่มีอยู่ในรุ่น 11.2
RDFozz

0

ลองอันนี้:

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

ปัญหาเกี่ยวกับวิธีแก้ไขปัญหาอื่น ๆ ที่เป็นไปได้คือไม่มีความสัมพันธ์ระหว่างผลลัพธ์สำหรับคอลัมน์ 1 และคอลัมน์ 2 เมื่อต้องการแก้ไขปัญหานี้แบบสอบถามภายในจะสร้างความสัมพันธ์นี้แล้วลบรายการที่ซ้ำกันออกจากชุดผลลัพธ์นั้น เมื่อคุณทำ listagg ชุดผลลัพธ์จะเรียบร้อยแล้ว ปัญหามีมากขึ้นเกี่ยวกับการรับข้อมูลในรูปแบบที่ใช้งานได้


1
คุณอาจต้องการเพิ่มคำอธิบายเกี่ยวกับวิธีการทำงาน
jkavalik

ขอบคุณสำหรับคำตอบและยินดีต้อนรับสู่เว็บไซต์ มันอาจจะมีประโยชน์มากกว่านี้ถ้าคุณสามารถอธิบายได้ว่าทำไมมันถึงใช้ได้ดีและมันจะช่วยได้อย่างไร
Tom V

ฉันพยายามอัปเดตคำตอบแล้ว แต่ยังคงมีข้อผิดพลาดอยู่ --- ปัญหาเกี่ยวกับการแก้ปัญหาที่เป็นไปได้อื่น ๆ คือไม่มีความสัมพันธ์ระหว่างผลลัพธ์สำหรับคอลัมน์ 1 และ 2 คอลัมน์เมื่อต้องการแก้ไขปัญหานี้แบบสอบถามภายในสร้างความสัมพันธ์นี้แล้วลบรายการที่ซ้ำกันออกจากชุดผลลัพธ์นั้น เมื่อคุณทำ listagg ชุดผลลัพธ์จะสะอาดเรียบร้อยแล้ว ปัญหามีมากขึ้นเกี่ยวกับการรับข้อมูลในรูปแบบที่ใช้งานได้
เควิน

-2

SQL ได้รับการออกแบบเป็นภาษาที่ง่ายใกล้กับภาษาอังกฤษมาก ดังนั้นทำไมคุณไม่เขียนมันเป็นภาษาอังกฤษ?

  1. กำจัดรายการที่ซ้ำกันใน num2 และใช้ listagg เป็นฟังก์ชันการรวม - ไม่ใช่การวิเคราะห์เพื่อคำนวณ concat บนสตริง
  2. เข้าร่วมกับต้นฉบับตามที่คุณต้องการหนึ่งแถวผลลัพธ์สำหรับหนึ่งอินพุต

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


ขอขอบคุณสำหรับการตอบสนองของคุณ. วิธีนี้ต้องใช้การสแกนเต็มตารางสองครั้ง แต่ที่สำคัญกว่านั้นไม่ได้ผลลัพธ์ที่ถูกต้อง
Leigh Riffel

ขออภัยที่ฉันวางรุ่นเก่าและไม่ถูกต้อง
Š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(+);

สิ่งนี้จะส่งคืนผลลัพธ์ที่ถูกต้องสำหรับข้อมูลที่ให้ แต่มีข้อสันนิษฐานที่ไม่ถูกต้อง Num1 และ Num2 ไม่เกี่ยวข้องกัน Num1 อาจเป็น Char1 ที่มีค่า a, e, i, o, u, y โซลูชั่นนี้ต้องใช้การสแกนแบบเต็มรูปแบบสองตารางเพื่อเอาชนะจุดประสงค์ทั้งหมดของการใช้ฟังก์ชันการรวม หากโซลูชันอนุญาตให้สแกนสองตารางได้จะต้องใช้วิธีนี้ (ด้วยข้อมูลตัวอย่างซึ่งมีค่าใช้จ่ายต่ำกว่าสิ่งอื่นใด) SELECT Num1, ( SELECT LISTAGG(Num2) WITHIN GROUP (ORDER BY Num2) FROM (SELECT distinct Num2 FROM listAggTest) ) Num2 FROM ListAggTest;
Leigh Riffel

-2

โซลูชันที่มีประสิทธิภาพมากที่สุดคือเลือกภายในด้วย GROUP BY เนื่องจาก DISTINCT และนิพจน์ทั่วไปช้าเหมือนนรก

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

วิธีการแก้ปัญหานี้ค่อนข้างง่าย - ขั้นแรกคุณจะได้รับชุดค่าผสมที่เป็นเอกลักษณ์ทั้งหมดของ num1 และ num2 (Inner SELECT) จากนั้นคุณจะได้รับสตริงของ num2 ทั้งหมดที่จัดกลุ่มตาม num1


แบบสอบถามนี้ไม่ส่งคืนผลลัพธ์ที่ร้องขอ SELECT * FROM ListAggTest;ก็จะส่งกลับผลเช่นเดียวกับ
Leigh Riffel

ในการป้องกันของเขาเขาอาจชี้ไปที่วิธีการแก้ปัญหานี้จากปัญหา stackoverflow อื่นที่ทำเครื่องหมายซ้ำว่าวิธีนี้จะแก้ไข นั่นคือทางออกที่ฉันต้องการ ดูเหมือนว่าฉันจะต้องใช้สมมติฐานที่แตกต่างกันในการโพสต์ของฉันเองและดังนั้นฉันจะทิ้งคำถามนี้ไว้กับความคิดเห็นนี้เพียงลำพัง
เจอราร์ดโอนีล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.