如何使用单个 SQL 查询使用封装的对象类型或集合类型填充 PL/SQL 对象类型
How to populate a PL/SQL Object Type with encapsulated Object Types or Collection Types using a single SQL Query
我目前正在使用父对象类型中的嵌套对象类型和集合类型设置数据模型,并且需要一种方法来填充对象类型,包括使用单个 SQL 查询的子对象。
作为使用 HR 模式的示例,我创建了一个示例数据结构。目标是获取所有部门的集合,其中包含在该部门工作的员工列表。
使用 Oracle SQL 数据库 12.1 我已经创建了数据结构:
CREATE OR REPLACE TYPE employee_ot AS OBJECT (
employee_id NUMBER,
first_name VARCHAR2(100),
last_name VARCHAR2(100)
)
create or replace TYPE EMPLOYEE_CT AS TABLE OF employee_ot;
create or replace TYPE DEPARTMENT_OT AS OBJECT
(
department_id number,
employees employee_ct
)
create or replace TYPE DEPARTMENT_CT AS TABLE OF DEPARTMENT_OT;
简单地填充 employee_ct 作品使用:
DECLARE
v_employee_ct employee_ct;
BEGIN
SELECT
employee_ot(employee_id,first_name,last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view;
dbms_output.put_line(v_employee_ct.count);
FOR employee_index IN v_employee_ct.first..v_employee_ct.last LOOP
dbms_output.put_line(v_employee_ct(employee_index).employee_id
|| ' '
|| v_employee_ct(employee_index).first_name
|| ' '
|| v_employee_ct(employee_index).last_name);
END LOOP;
END;
当我尝试使用类似查询填充 department_ct 时,出现错误:
DECLARE
v_department_ct department_ct;
BEGIN
select department_ot(ev1.department_id,
(SELECT
employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view ev2
where ev2.department_id = ev1.department_id))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
END;
PL/SQL: ORA-01744: inappropriate INTO
删除第二个 bulk collect into 子句我得到:
DECLARE
v_department_ct department_ct;
BEGIN
select department_ot(ev1.department_id,
(SELECT
employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
FROM
emp_details_view ev2
where ev2.department_id = ev1.department_id))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
END;
PL/SQL: ORA-00932: inconsistent datatypes: expected HR.EMPLOYEE_OT got HR.EMPLOYEE_CT
使用函数获取指定 department_id 的 employee_ct 有效。但是我担心在大数据集上使用时会出现性能问题:
CREATE OR REPLACE FUNCTION get_employees (
department_id_in NUMBER
) RETURN employee_ct AS
v_employee_ct employee_ct;
BEGIN
v_employee_ct := employee_ct ();
SELECT
employee_ot(employee_id,first_name,last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view
WHERE
department_id = department_id_in;
RETURN v_employee_ct;
END get_employees;
DECLARE
v_department_ct department_ct;
BEGIN
SELECT
department_ot(ev1.department_id, (get_employees(ev1.department_id) ) )
BULK COLLECT INTO
v_department_ct
FROM
emp_details_view ev1
GROUP BY
department_id;
FOR department_index IN v_department_ct.first..v_department_ct.last LOOP
DECLARE
v_department_ot department_ot;
BEGIN
v_department_ot := v_department_ct(department_index);
dbms_output.put_line(v_department_ot.department_id || ' ' ||v_department_ot.employees.count);
FOR employee_index IN v_department_ot.employees.first..v_department_ot.employees.last LOOP
DECLARE
v_employee_ot employee_ot;
BEGIN
v_employee_ot := v_department_ot.employees(employee_index);
dbms_output.put_line(v_employee_ot.employee_id
|| ' '
|| v_employee_ot.first_name
|| ' '
|| v_employee_ot.last_name);
END;
END LOOP;
END;
END LOOP;
END;
有没有办法避免使用函数,而是在单个查询中编写封装对象的创建?
您可以使用 multiset
运算符并将数据转换为 employee_ct
。这个代码块对我有用:
declare
v_department_ct department_ct;
begin
select department_ot(ev1.department_id,
cast(multiset(select employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
from emp_details_view ev2
where ev2.department_id = ev1.department_id )
as employee_ct))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
end;
我的测试数据:
create table emp_details_view (department_id, employee_id, first_name, last_name) as (
select 1, 101, 'A', 'A' from dual union all
select 1, 102, 'B', 'B' from dual union all
select 2, 201, 'X', 'X' from dual )
我目前正在使用父对象类型中的嵌套对象类型和集合类型设置数据模型,并且需要一种方法来填充对象类型,包括使用单个 SQL 查询的子对象。
作为使用 HR 模式的示例,我创建了一个示例数据结构。目标是获取所有部门的集合,其中包含在该部门工作的员工列表。
使用 Oracle SQL 数据库 12.1 我已经创建了数据结构:
CREATE OR REPLACE TYPE employee_ot AS OBJECT (
employee_id NUMBER,
first_name VARCHAR2(100),
last_name VARCHAR2(100)
)
create or replace TYPE EMPLOYEE_CT AS TABLE OF employee_ot;
create or replace TYPE DEPARTMENT_OT AS OBJECT
(
department_id number,
employees employee_ct
)
create or replace TYPE DEPARTMENT_CT AS TABLE OF DEPARTMENT_OT;
简单地填充 employee_ct 作品使用:
DECLARE
v_employee_ct employee_ct;
BEGIN
SELECT
employee_ot(employee_id,first_name,last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view;
dbms_output.put_line(v_employee_ct.count);
FOR employee_index IN v_employee_ct.first..v_employee_ct.last LOOP
dbms_output.put_line(v_employee_ct(employee_index).employee_id
|| ' '
|| v_employee_ct(employee_index).first_name
|| ' '
|| v_employee_ct(employee_index).last_name);
END LOOP;
END;
当我尝试使用类似查询填充 department_ct 时,出现错误:
DECLARE
v_department_ct department_ct;
BEGIN
select department_ot(ev1.department_id,
(SELECT
employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view ev2
where ev2.department_id = ev1.department_id))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
END;
PL/SQL: ORA-01744: inappropriate INTO
删除第二个 bulk collect into 子句我得到:
DECLARE
v_department_ct department_ct;
BEGIN
select department_ot(ev1.department_id,
(SELECT
employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
FROM
emp_details_view ev2
where ev2.department_id = ev1.department_id))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
END;
PL/SQL: ORA-00932: inconsistent datatypes: expected HR.EMPLOYEE_OT got HR.EMPLOYEE_CT
使用函数获取指定 department_id 的 employee_ct 有效。但是我担心在大数据集上使用时会出现性能问题:
CREATE OR REPLACE FUNCTION get_employees (
department_id_in NUMBER
) RETURN employee_ct AS
v_employee_ct employee_ct;
BEGIN
v_employee_ct := employee_ct ();
SELECT
employee_ot(employee_id,first_name,last_name)
BULK COLLECT INTO
v_employee_ct
FROM
emp_details_view
WHERE
department_id = department_id_in;
RETURN v_employee_ct;
END get_employees;
DECLARE
v_department_ct department_ct;
BEGIN
SELECT
department_ot(ev1.department_id, (get_employees(ev1.department_id) ) )
BULK COLLECT INTO
v_department_ct
FROM
emp_details_view ev1
GROUP BY
department_id;
FOR department_index IN v_department_ct.first..v_department_ct.last LOOP
DECLARE
v_department_ot department_ot;
BEGIN
v_department_ot := v_department_ct(department_index);
dbms_output.put_line(v_department_ot.department_id || ' ' ||v_department_ot.employees.count);
FOR employee_index IN v_department_ot.employees.first..v_department_ot.employees.last LOOP
DECLARE
v_employee_ot employee_ot;
BEGIN
v_employee_ot := v_department_ot.employees(employee_index);
dbms_output.put_line(v_employee_ot.employee_id
|| ' '
|| v_employee_ot.first_name
|| ' '
|| v_employee_ot.last_name);
END;
END LOOP;
END;
END LOOP;
END;
有没有办法避免使用函数,而是在单个查询中编写封装对象的创建?
您可以使用 multiset
运算符并将数据转换为 employee_ct
。这个代码块对我有用:
declare
v_department_ct department_ct;
begin
select department_ot(ev1.department_id,
cast(multiset(select employee_ot(ev2.employee_id,ev2.first_name, ev2.last_name)
from emp_details_view ev2
where ev2.department_id = ev1.department_id )
as employee_ct))
bulk collect into v_department_ct
from emp_details_view ev1
group by department_id;
end;
我的测试数据:
create table emp_details_view (department_id, employee_id, first_name, last_name) as (
select 1, 101, 'A', 'A' from dual union all
select 1, 102, 'B', 'B' from dual union all
select 2, 201, 'X', 'X' from dual )