如何在具有多个连接的 Pl/SQL 中编写对象类型作为输出参数的存储过程

How to write store procedure with object type as out parameter in Pl/SQL with multiple joins

我正在尝试使用以下示例用例和表编写存储过程,

员工<br> Emp_id Emp_Name 1 乔恩 2马克 3 结婚

部门<br> Emp_Id Dept_Id 1个 2乙 3C 1乙 二维

Assets Emp_Id Asset_Name 1 AA 1 BB 2 CC 2 DD 4 EE 4 FF

关系

可以将一名员工添加到多个部门。 例如 Emp 1 添加到 A 和 B 部门。

一名员工可以拥有多项资产 例如 Emp 1 欠资产 AA 和 BB。

员工和资产之间没有外键约束。 所以 Assets 可以有 EmpId,这在 Employee Table 中是不可用的。 例如 Emp 4

期望的输出

EmployeeInfo Emd_Id Emp_Name Array of Dept_Id[] Array of Assets[]

员工 ID 1 的期望结果

Emd_Id :1 Emp_Name :Jhon Array of Dept_Id[] :[A,B] Array of Assets[] :[AA,BB]

员工 ID 4 的期望结果

Emd_Id :4 Emp_Name :null -- As no entry in Employee table. Array of Dept_Id[] :null Array of Assets[] :[EE,FF]

所以想为this.Please写一个存储过程建议解决这个问题。 这可以通过多个游标或对象类型输出变量来实现吗?

存储过程我试过如下,

CREATE OR REPLACE PROCEDURE PRC_TEST( employeeInfo OUT SYS_REFCURSOR) IS BEGIN OPEN employeeInfo FOR SELECT e.EMP_ID ,e.EMP_NAME, d.DEPT_ID, a.ASSET_NAME FROM EMPLOYEE e, DEPARTMENT d, ASSETS a WHERE e.EMP_ID = d.EMP_ID AND e.EMP_ID = a.EMP_ID; END; 提前致谢

最好创建包定义和包体。您的包裹定义如下所示:

CREATE OR REPLACE PACKAGE EmployeeInfo AS

TYPE departament_type IS TABLE OF VARCHAR2(100);
TYPE assets_type      IS TABLE OF VARCHAR2(100);

PROCEDURE get_employee_info ( Emp_Id_col      IN OUT NUMBER
                             ,Emp_Name_col       OUT VARCHAR2
                             ,departament_tbl    OUT DEPARTAMENT_TYPE
                             ,assets_tbl         OUT ASSETS_TYPE);

END EmployeeInfo;

然后你的包体将匹配你的定义,它是程序将要实施的地方:

CREATE OR REPLACE PACKAGE BODY EmployeeInfo AS

PROCEDURE get_employee_info ( Emp_Id_col      IN OUT NUMBER
                             ,Emp_Name_col       OUT VARCHAR2
                             ,departament_tbl    OUT DEPARTAMENT_TYPE
                             ,assets_tbl         OUT ASSETS_TYPE)
IS 
BEGIN

BEGIN
  SELECT Emp_Name
  INTO   Emp_Name_col
  FROM   Employee
  WHERE  Emp_Id = Emp_Id_col;
EXCEPTION
  WHEN NO_DATA_FOUND THEN  
    RETURN;
END;  

departament_tbl := DEPARTAMENT_TYPE();

FOR dep_rec IN (SELECT *
                FROM   Department
                WHERE  Emp_id = Emp_Id_col) LOOP 
  departament_tbl.extend;
  departament_tbl(departament_tbl.COUNT) := dep_rec.Dep_Id;
END LOOP;

assets_tbl := ASSETS_TYPE();

FOR asset_rec IN (SELECT *
                  FROM   Assets
                  WHERE  Emp_Id = Emp_Id_col) LOOP 
  assets_tbl.extend;
  assets_tbl(assets_tbl.COUNT) := asset_rec.Asset_Name;
END LOOP;

END get_employee_info;

END EmployeeInfo;

现在这里有一个非常简单的存储过程测试脚本:

DECLARE
  Emp_Id_col            NUMBER(10);
  Emp_Name_col          Employee.Emp_Name%TYPE;
  departament_tbl       EMPLOYEEINFO.DEPARTAMENT_TYPE;
  assets_tbl            EMPLOYEEINFO.ASSETS_TYPE;
BEGIN
  Emp_Id_col := 1;
  EMPLOYEEINFO.GET_EMPLOYEE_INFO(Emp_Id_col
                                ,Emp_Name_col
                                ,departament_tbl
                                ,assets_tbl);

  DBMS_OUTPUT.PUT_LINE(Emp_Name_col          || ' - ' ||
                       departament_tbl.COUNT || ' - ' || 
                       assets_tbl.COUNT);

END;

SQL Fiddle

Oracle 11g R2 架构设置:

CREATE TABLE Employee ( Emp_id, Emp_Name ) AS
SELECT 1, 'Jhon' FROM DUAL UNION ALL
SELECT 2, 'Mark' FROM DUAL UNION ALL
SELECT 3, 'Marry' FROM DUAL
/

CREATE TABLE Department ( Emp_Id, Dept_Id ) AS
SELECT 1, 'A' FROM DUAL UNION ALL
SELECT 2, 'B' FROM DUAL UNION ALL
SELECT 3, 'C' FROM DUAL UNION ALL
SELECT 1, 'B' FROM DUAL UNION ALL
SELECT 2, 'D' FROM DUAL
/

CREATE TABLE Assets ( Emp_Id, Asset_Name ) AS
SELECT 1, 'AA' FROM DUAL UNION ALL
SELECT 1, 'BB' FROM DUAL UNION ALL
SELECT 2, 'CC' FROM DUAL UNION ALL
SELECT 2, 'DD' FROM DUAL UNION ALL
SELECT 4, 'EE' FROM DUAL UNION ALL
SELECT 4, 'FF' FROM DUAL
/

CREATE TYPE StringLIst IS TABLE OF VARCHAR2(20)
/

CREATE TYPE Emp_Dept_Assets_Obj AS OBJECT(
  Emp_id   INTEGER,
  Emp_Name VARCHAR2(50),
  Depts    StringList,
  Assets   StringList
)
/

CREATE FUNCTION get_Details(
  i_emp_id  IN  Employee.EMP_ID%TYPE
) RETURN Emp_Dept_Assets_Obj
IS
  o_details Emp_Dept_Assets_Obj;
BEGIN
  o_details := Emp_Dept_Assets_Obj( i_emp_id, NULL, NULL, NULL );

  BEGIN
    SELECT Emp_Name
    INTO   o_details.Emp_Name
    FROM   Employee
    WHERE  emp_id = i_emp_id;
  EXCEPTION
    WHEN NO_DATA_FOUND THEN
      NULL;
  END;

  SELECT dept_id
  BULK COLLECT INTO o_details.Depts
  FROM   Department
  WHERE  emp_id = i_emp_id;

  SELECT asset_name
  BULK COLLECT INTO o_details.Assets
  FROM   Assets
  WHERE  emp_id = i_emp_id;

  RETURN o_details;
END;
/

查询 1:

SELECT d.details.emp_id,
       d.details.emp_name,
       d.details.depts,
       d.details.assets
FROM   (
  SELECT get_Details( LEVEL ) AS details
  FROM   DUAL
  CONNECT BY LEVEL <= 4
) d

Results:

| DETAILS.EMP_ID | DETAILS.EMP_NAME | DETAILS.DEPTS | DETAILS.ASSETS |
|----------------|------------------|---------------|----------------|
|              1 |             Jhon |           A,B |          AA,BB |
|              2 |             Mark |           B,D |          CC,DD |
|              3 |            Marry |             C |                |
|              4 |           (null) |               |          EE,FF |