1

我正在尝试整理一些 PL/SQL 代码,尝试测试性能。能够做到这一点将使我们减少对数据库的调用,但我不确定如何填充我创建的返回类型。这是一个设计不佳的表结构,它展示了我想要完成的工作。

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 语句来填充返回的类型?在这里“批量收集”是正确的方法吗?我发现这个页面是一个很好的起点。

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 函数中更改什么来实现这一点?

4

1 回答 1

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

别名可能不是必需的,这是我自动做的以减少打字。

于 2012-07-15T14:45:48.103 回答