Aggregate distinct values in collections in SQL GROUP BY

前端 未结 1 1631
眼角桃花
眼角桃花 2021-01-24 20:23

I have a table with a collection type in it. I want to SELECT from the table and GROUP BY some column. I want the results for each group to include a

相关标签:
1条回答
  • 2021-01-24 20:57

    Adapted from my answer to another question.

    Oracle Setup:

    CREATE OR REPLACE TYPE VARCHAR2s_Table IS TABLE OF VARCHAR2(100);
    /
    

    Create a user-defined aggregation type:

    CREATE OR REPLACE TYPE Varchar2sTableUnion AS OBJECT(
      list VARCHAR2s_Table,
    
      STATIC FUNCTION ODCIAggregateInitialize(
        ctx         IN OUT Varchar2sTableUnion
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateIterate(
        self        IN OUT Varchar2sTableUnion,
        value       IN     VARCHAR2s_Table
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateTerminate(
        self        IN OUT Varchar2sTableUnion,
        returnValue    OUT VARCHAR2s_Table,
        flags       IN     NUMBER
      ) RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateMerge(
        self        IN OUT Varchar2sTableUnion,
        ctx         IN OUT Varchar2sTableUnion
      ) RETURN NUMBER
    );
    /
    
    CREATE OR REPLACE TYPE BODY Varchar2sTableUnion
    IS
      STATIC FUNCTION ODCIAggregateInitialize(
        ctx         IN OUT Varchar2sTableUnion
      ) RETURN NUMBER
      IS
      BEGIN
        ctx := Varchar2sTableUnion( NULL );
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateIterate(
        self        IN OUT Varchar2sTableUnion,
        value       IN     VARCHAR2s_Table
      ) RETURN NUMBER
      IS
      BEGIN
        IF value IS NULL THEN
          NULL;
        ELSIF self.list IS NULL THEN
          self.list := value;
        ELSE
          self.list := self.list MULTISET UNION DISTINCT value;
        END IF;
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateTerminate(
        self        IN OUT Varchar2sTableUnion,
        returnValue    OUT VARCHAR2s_Table,
        flags       IN     NUMBER
      ) RETURN NUMBER
      IS
      BEGIN
        returnValue := self.list;
        RETURN ODCIConst.SUCCESS;
      END;
    
      MEMBER FUNCTION ODCIAggregateMerge(
        self        IN OUT Varchar2sTableUnion,
        ctx         IN OUT Varchar2sTableUnion
      ) RETURN NUMBER
      IS
      BEGIN
        IF self.list IS NULL THEN
          self.list := ctx.list;
        ELSIF ctx.list IS NULL THEN
          NULL;
        ELSE
          self.list := self.list MULTISET UNION DISTINCT ctx.list;
        END IF;
        RETURN ODCIConst.SUCCESS;
      END;
    END;
    /
    

    Create a user-defined aggregation function:

    CREATE FUNCTION MULTISET_UNION( list VARCHAR2s_Table )
    RETURN VARCHAR2s_Table
    PARALLEL_ENABLE AGGREGATE USING Varchar2sTableUnion;
    /
    

    Query:

    Then you can just use it to perform the aggregation in your query:

    WITH test_data (id, a_list) AS
           (SELECT 1,
                   varchar2s_table ('A', 'B', 'C')
            FROM   DUAL
            UNION ALL
            SELECT 1,
                   varchar2s_table ('C', 'D', 'E')
            FROM   DUAL)
    SELECT id,
           MULTISET_UNION( a_list )
    FROM   test_data
    GROUP BY id
    

    Output:

    ID MULTISET_UNION(A_LIST)
    -- -------------------------------------------
     1 SCHEMA.VARCHAR2S_TABLE('A','B','C','D','E')
    
    0 讨论(0)
提交回复
热议问题