Oracle 将结果集放入 FORALL 中的变量中

Posted

技术标签:

【中文标题】Oracle 将结果集放入 FORALL 中的变量中【英文标题】:Oracle put resultset into variable in FORALL 【发布时间】:2020-02-21 10:52:51 【问题描述】:

我有以下 plsql 块

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 声明为

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

我得到一个异常 ORA-00947: not enough values

我确实需要在 FORALL 循环的每次迭代中将多行的结果集放入 TABLE TYPE 的变量中。我不能在 l_mds_parents 中使用 BULK COLLECT,因为它在 FORALL 内部受到限制。 是否只有使用临时表而不是表变量的解决方案?

【问题讨论】:

请提供表 mds_hierarchy_all 的描述。看起来表 mds_hierarchy_all 没有相同的列数,如 l_mds_parents 【参考方案1】:

我认为你不能用forall 做到这一点。您可以使用嵌套循环:

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

但是您根本不需要使用 PL/SQL;使用单个分层查询,或者在这里可能更简单,递归子查询分解:

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 带有一些虚构的数据。

【讨论】:

以上是关于Oracle 将结果集放入 FORALL 中的变量中的主要内容,如果未能解决你的问题,请参考以下文章

SQL存储过程如何将结果放入变量?

BULK 收集和 FORALL 两次插入数据

oracle pl/sql FORALL 语句

FORALL Oracle 中的 IF ELSE 条件

将结果集转换为字符串并放入列表

如何将 SQL 结果放入 VBA 中的变量中