Link to home
Start Free TrialLog in
Avatar of bobcaputo
bobcaputo

asked on

Select from Oracle Collection

I understand that to create a collection that allows sql selects on it that it must be created outside of a pl/sql block. Is there a way to create this collection in a package and still allow select from SQL?
Avatar of Sean Stuber
Sean Stuber

actually the collection could be populated from within a table function which is pl/sql and used from sql
for example...
CREATE OR REPLACE TYPE  VCARRAY AS TABLE OF VARCHAR2(4000);

CREATE OR REPLACE FUNCTION str2tbl(p_string IN VARCHAR2, p_delimiter IN VARCHAR2 := ',')
        RETURN vcarray PIPELINED
    AS
        v_length   NUMBER := LENGTH(p_string);
        v_start    NUMBER := 1;
        v_index    NUMBER;
    BEGIN
        WHILE(v_start <= v_length)
        LOOP
            v_index    := INSTR(p_string, p_delimiter, v_start);

            IF v_index = 0
            THEN
                PIPE ROW(SUBSTR(p_string, v_start));
                v_start    := v_length + 1;
            ELSE
                PIPE ROW(SUBSTR(p_string, v_start, v_index - v_start));
                v_start    := v_index + 1;
            END IF;
        END LOOP;

        RETURN;
    END str2tbl;

select * from table(str2tbl('a,b,c'))

Open in new window

Avatar of bobcaputo

ASKER

My goal was to have everything in a package. This shows vcarray created as a sql line item. Also I am using a composit collection.  Notice in my code the commeted out statements I need to perform in sql. I want to encaplulate everything in a package so there are no outside actions to perform.

Here is my code.

create or replace procedure sample as

/*
These statements were executed in SQL
prior to compiling this procecure.

create or replace type r_rec as object
(
    employee_id   number,
    first_name   varchar2(20),
    job_id     varchar2(10)
);

create or replace type t_rec as table of r_rec;

*/

cnt NUMBER;

dat_rec t_rec;

-- Declare a collection (array) of 1 column.
-- Index is the subscript.
-- Binary integer is the numeric data type.
TYPE doc_id IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
v_doc_id doc_id;

BEGIN
        
    dat_rec := t_rec();
    dbms_output.PUT_LINE('Here 1 dat_rec : ' || dat_rec.count);
    
    select employee_id BULK COLLECT INTO v_doc_id from hr.employees;
    dbms_output.PUT_LINE('Here 2 v_doc : ' || v_doc_id.count);
    
    FOR i IN v_doc_id.FIRST..v_doc_id.LAST LOOP
        dbms_output.PUT_LINE('Here 3 i = : ' || i);
        dat_rec.extend;
        dat_rec(i) := r_rec(null,null,null);
        dbms_output.PUT_LINE('Here 4 dat_rec = : ' || dat_rec.count);
        select 
                employee_id, 
                first_name, 
                job_id 
        into
                dat_rec(i).employee_id,
                dat_rec(i).first_name,
                dat_rec(i).job_id      
        from 
                hr.employees
        where 
                employee_id = v_doc_id(i);
                
        select count(*) into cnt from table(dat_rec);
        dbms_output.PUT_LINE('Here 5 : ' || cnt);
        dbms_output.PUT_LINE('Here 6 : ' || dat_rec.Count);
    END LOOP;
end;
END;

Open in new window

Hi sdstuber,

There may be a misunderstanding of my question or I didn't phrase properly. Its not so much the population of the collection but the creation. I want to create the collection in a package so its more portable and only one thing needs to be executed.

Thanks much for your help,
Bob
ASKER CERTIFIED SOLUTION
Avatar of Sean Stuber
Sean Stuber

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
a restriction with using these implicit types is the records aren't really "objects"

so you can't invoke a constructor for them.

for example:

    testtype.r_rec(employee_id, first_name, job_id)

is illegal because there is no t_rec function or t_rec object,  which is why I manually built the r_rec record