Can I dynamically select into an array in DB2?

32 Views Asked by At

I have a stored procedure that counts distinct value for a set of columns to report new values to users if they arise. The inventory of columns is in a table so we can add new values to the check. The procedure loops through this inventory, generates a select statement, uses it to open a cursor, and then fetches results and inserts them into the results table one by one.

My background is Oracle and I'm fairly new with writing procedures in DB2. I'm wondering if there's an approach using arrays that would cut down on some of the steps. I'm working with DB2 11.5 luw, and Oracle Compatibility Turned on, so I have a working example using Oracle Syntax. I have a mostly working DB2 equivalent but haven't figured if there's a way to do the dynamic select into an array. Anybody know if this is possible? ...and any good recommended reading for writing procedures in DB2?

Sample Tables

CREATE TABLE cols (
      tabschema varchar(128)
    , tabname   varchar(128)
    , colname   varchar(128)
)
ORGANIZE BY ROW;

CREATE TABLE cols_values(
      tabschema     varchar(128)
    , tabname       varchar(128)
    , colname       varchar(128)
    , col_value     varchar(200)
    , value_count   integer
)
ORGANIZE BY ROW;

INSERT INTO cols  
VALUES  
      ('SYSCAT', 'TABLES', 'OWNERTYPE')
    , ('SYSCAT', 'TABLES', 'STATUS')
    , ('SYSCAT', 'TABLES', 'TABSCHEMA');

Oracle PL/SQL Version

CREATE OR REPLACE PACKAGE ora_ver
IS
    TYPE result_row_type IS RECORD
    (
          col_value     varchar(200)
        , value_count   integer
    );

    TYPE result_array_type IS TABLE OF result_row_type INDEX BY INTEGER;
    
    PROCEDURE get_cols_values;
END;

CREATE OR REPLACE PACKAGE BODY ora_ver
IS
    PROCEDURE get_cols_values
    IS
        l_sel_stmnt VARCHAR(500);
        l_results result_array_type;
    BEGIN    
        FOR col IN (SELECT * FROM COLS ORDER BY tabschema, tabname, colname)
        LOOP
            l_sel_stmnt := 'SELECT ' || col.colname || ', COUNT(*) FROM ' || col.tabschema || '.' || col.tabname || ' GROUP BY ' || col.colname;

            EXECUTE IMMEDIATE l_sel_stmnt BULK COLLECT INTO l_results;
            FORALL i IN 1..l_results.count 
                INSERT INTO cols_values
                (
                    tabschema
                    , tabname
                    , colname
                    , col_value
                    , value_count
                ) 
                VALUES 
                (
                    col.tabschema
                    , col.tabname
                    , col.colname
                    , l_results(i).col_value
                    , l_results(i).value_count
                );
        END LOOP;
    END get_cols_values;
END ora_ver;

DB2 Version

CREATE OR REPLACE MODULE db2_ver;

ALTER MODULE db2_ver ADD TYPE result_row_type AS ROW 
(
      col_value     varchar(200)
    , value_count   integer
);

ALTER MODULE db2_ver ADD TYPE result_array_type AS result_row_type ARRAY[];

ALTER MODULE db2_ver DROP PROCEDURE get_cols_values ;

ALTER MODULE db2_ver PUBLISH PROCEDURE get_cols_values ()
BEGIN
    DECLARE l_sel_stmnt VARCHAR(500);
    DECLARE l_results result_array_type;

    FOR col AS (SELECT * FROM COLS ORDER BY tabschema, tabname, colname)
    DO
        SET l_sel_stmnt = 'SELECT ' || col.colname || ', COUNT(*) FROM ' || col.tabschema || '.' || col.tabname || ' GROUP BY ' || col.colname;

--      ************************************************************
--      Is there a DB2 equivalent of this? ARRAY_AGG?
--        EXECUTE IMMEDIATE l_sel_stmnt BULK COLLECT INTO l_results;
--      ************************************************************        
        INSERT INTO cols_values
        (
              tabschema
            , tabname
            , colname
            , col_value
            , value_count
        ) 
        SELECT 
              col.tabschema
            , col.tabname
            , col.colname
            , t.col_value
            , t.value_count
        FROM UNNEST(l_results) AS T(col_value, value_count);
        
    END FOR;
END;
0

There are 0 best solutions below