0

I have the following plsql block

declare 
    TYPE t_mds_ids IS TABLE OF mds.id%TYPE;
    l_mds_ids t_mds_ids;
    l_mds_parents t_mds_parents;
begin
    SELECT id BULK COLLECT INTO l_mds_ids FROM mds;
    FORALL indx IN l_mds_ids.FIRST .. l_mds_ids.LAST
        select l_mds_ids(indx), ch.id_employee_parent
        into l_mds_parents
        FROM hierarchy_all ch
        CONNECT BY ch.id_employee = prior ch.id_employee_parent
        START WITH ch.id_employee = l_mds_ids(indx);
    EXECUTE IMMEDIATE 'truncate table mds_hierarchy_all';
    insert into mds_hierarchy_all
    select * from l_mds_parents;
end;

t_mds_parents declared as

create or replace type r_mds_parents as object (
  id_mds number(5,0),
  id_employee number(5,0)
);
/

create or replace type t_mds_parents as table of r_mds_parents;
/

And I get an exception ORA-00947: not enough values

I really need to put the resultset of multiple rows into variable of TABLE TYPE on each iteration of FORALL loop. I can't use BULK COLLECT into l_mds_parents as it's restricted inside of FORALL. Is there only solution to use temporary table instead of table variable?

MaterialGirl
  • 363
  • 2
  • 10
  • 22
  • Plese, provide description of table mds_hierarchy_all. It looks like table mds_hierarchy_all doesn't have same count of columns like l_mds_parents – MichalSv Feb 21 '20 at 11:45

1 Answers1

0

I don't think you can do this with forall. You could use nested loops:

declare 
    TYPE t_mds_ids IS TABLE OF mds.id%TYPE;
    l_mds_ids t_mds_ids;
    l_mds_parents t_mds_parents;
begin
    SELECT id BULK COLLECT INTO l_mds_ids FROM mds;
    l_mds_parents := NEW t_mds_parents();
    FOR indx IN l_mds_ids.FIRST .. l_mds_ids.LAST LOOP
        FOR rec IN (
            select l_mds_ids(indx) as id_employee, ch.id_employee_parent
            FROM hierarchy_all ch
            CONNECT BY ch.id_employee = prior ch.id_employee_parent
            START WITH ch.id_employee = l_mds_ids(indx)
            ) LOOP
                l_mds_parents.extend();
                l_mds_parents(l_mds_parents.COUNT)
                    := NEW r_mds_parents (rec.id_employee, rec.id_employee_parent);
        END LOOP;
    END LOOP;
    EXECUTE IMMEDIATE 'truncate table mds_hierarchy_all';
    insert into mds_hierarchy_all
    select * from table(l_mds_parents);
end;
/

But you don't need to use PL/SQL at all; use a single hierarchical query, or probably more simply here, recursive subquery factoring:

insert into mds_hierarchy_all /* (id_mds, id_employee) -- better to list columns */
with rcte (id_mds, id_employee) as (
  select m.id, ha.id_employee_parent
  from mds m
  join hierarchy_all ha on ha.id_employee = m.id
  union all
  select r.id_mds, ha.id_employee_parent
  from rcte r
  join hierarchy_all ha on ha.id_employee = r.id_employee
)
select * from rcte;

db<>fiddle with some made-up data.

Alex Poole
  • 183,384
  • 11
  • 179
  • 318