PLSQL批量收集到UDT与1-N表的连接?

时间:2012-07-13 14:09:21

标签: join plsql user-defined-functions user-defined-types

我正在尝试整理一些PL / SQL代码,试图测试性能。能够这样做将允许我们减少对DB的调用,但我不确定如何填充我创建的返回类型。这是一个设计糟糕的表格结构,展示了我正在努力实现的目标。

create table emp_group (
  gid number,
  gname varchar2(10)
);

create table emp (
  empID number,
  gid number,
  empname varchar2(10)
);

create or replace type t_emp_obj as object (
  empID number,
  gid number,
  empname varchar2(10)
);

create or replace type t_emp is table of t_emp_obj;

create or replace type t_group_emp as object
(
  gid number,
  gname varchar2(10),
  g_emps t_emp
);

insert into emp( empID, gid, empName ) values ( 1, 10, 'Rob' );
insert into emp( empID, gid, empName ) values ( 2, 10, 'Ken' );
insert into emp( empID, gid, empName ) values ( 3, 10, 'Dave' );
insert into emp( empID, gid, empName ) values ( 4, 10, 'Ron' );
insert into emp( empID, gid, empName ) values ( 5, 11, 'Joe' );
insert into emp_group( gid, gname ) values (10, 'DDP');
insert into emp_group( gid, gname ) values (11, 'DDD');
commit;


create or replace function f_test1 return t_emp as
  ret t_emp;
begin
  select t_emp_obj(empID, gid, empname) bulk collect into ret from emp;

  return ret;
end;


create or replace function f_test2 return t_group_emp as
  ret t_group_emp;
begin
  select t_group_emp(????) bulk collect into ret
  from emp, emp_group
  where emp.gid = emp_group.gid;

  return ret;
end;

这是一个贯穿它的功能。

set serveroutput on size 10000

declare
  x t_emp;
begin
  x := f_test1;

  for r in (select * from table(cast(x as t_emp))) loop
    dbms_output.put_line(r.empID || ', ' || r.gid || ', ' || r.empname );
  end loop;

end;

我们有两个表,一个是员工列表,另一个是员工组列表。忽略emp_group和emp之间应该有一个连接表的事实,这样一个员工可以属于多个组...演示代码。 8)

我想在一个返回的类型中返回给定组ID的所有员工以及组行。返回的类型是t_group_emp,它有一个emp行表。 f_test2的语法是什么?

1)这可能吗?

2)如何构造select语句来填充返回的类型?在这里“批量收集”正确的方法吗?我发现this page是一个很好的起点。

3)这种表现有多糟糕?一旦我对语法进行了排序,我就可以运行自己的数字,但总的来说,这是一个很好的方法,可以从具有1-N关系的多个表中返回数据吗?

编写应用程序以使用返回的类型很容易,所以我并不担心。

编辑:我们正在使用Oracle 10.3.something ...

编辑:这接近我想要的,但不完全。

create or replace
function f_test2 return t_group as
  ret t_group;
begin
  select t_group_emp( emp_group.gid, emp_group.gname, t_emp( t_emp_obj( emp.empID, emp.gid, emp.empName ))) bulk collect into ret
  from emp, emp_group 
  where emp.gid = emp_group.gid;

  return ret;
end;

和一个贯穿那个的功能......

set serveroutput on size 10000

declare
  x t_group;
begin
  x := f_test2;

  for r in (select * from table(cast(x as t_group))) loop
    dbms_output.put_line( 'group ' || r.gid || ', ' || r.gname  );
    for s in (select * from table(cast(r.g_emps as t_emp))) loop
      dbms_output.put_line( 'emp ' || s.empID || ', ' || s.empname  );
    end loop;  
  end loop;

end;

提供以下输出:

group 10, DDP
emp 1, Rob
group 10, DDP
emp 2, Ken
group 10, DDP
emp 3, Dave
group 10, DDP
emp 4, Ron
group 11, DDD
emp 5, Joe

哪个好,但我希望输出看起来像这样,以显示1-N关系。

group 10, DDP
emp 1, Rob
emp 2, Ken
emp 3, Dave
emp 4, Ron
group 11, DDD
emp 5, Joe

我需要在f_test2函数中更改什么才能实现?

1 个答案:

答案 0 :(得分:1)

首先:我目前无法访问/使用oracle安装。我尝试过SQL Fiddle,但这种问题似乎太复杂了(或者我太愚蠢了,这太可能了:))。所以我无法测试它。

无论如何,你应该能够通过以下方式实现目标:

  select t_group_emp(g.gid, 
                     g.gname, 
                     cast(multiset(select e.empID, 
                                          e.gid, 
                                          e.empname 
                                     from emp e
                                    where e.gid = g.gid
                                  ) as t_emp
                         )
                    )
    from emp_group g

别名可能不是必需的,我会自动减少输入。