【发布时间】:2016-07-12 03:18:57
【问题描述】:
我正在使用 Oracle 11g 数据库,发布 11.2.0.3.0 - 64 位生产
我已经编写了以下过程,它使用游标从名为benefit_info 的表中收集成批的benefit_ids(只是NUMBER 类型)。对于每批中的每个benefit_id,我需要获取关联的客户,然后进行各种计算等。到目前为止,我有以下内容:
CREATE OR REPLACE PROCEDURE ben_correct(in_bulk_collect_limit IN PLS_INTEGER DEFAULT 1000)
IS
TYPE ben_identity_rec IS RECORD
(
life_scd_id NUMBER,
benefit_id NUMBER
);
TYPE ben_identity_col IS TABLE OF ben_identity_rec INDEX BY PLS_INTEGER;
life_col ben_identity_col;
ben_id NUMBER;
CURSOR benefit_cur
IS
SELECT benefit_id FROM benefit_info;
TYPE benefit_ids_t IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
benefit_ids benefit_ids_t;
PROCEDURE get_next_set_of_incoming(out_benefit_ids OUT NOCOPY benefit_ids_t)
IS
BEGIN
FETCH benefit_cur
BULK COLLECT INTO out_benefit_ids
LIMIT in_bulk_collect_limit;
END;
BEGIN
OPEN benefit_cur;
LOOP
get_next_set_of_incoming(benefit_ids);
/*
The code below is too slow as each benefit_id is considered
individually. Want to change FOR LOOP into LEFT JOIN of benefit_ids
*/
FOR indx IN 1 .. benefit_ids.count LOOP
ben_id := benefit_ids(indx);
SELECT c.life_scd_id, c.benefit_id
BULK COLLECT INTO life_col
FROM customer c
WHERE c.benefit_id = ben_id;
-- Now do further processing with life_col
END LOOP;
EXIT WHEN benefit_ids.count = 0;
END LOOP;
CLOSE benefit_cur;
END;
/
如上面的代码所示,FOR indx IN 1 .. LOOP 非常慢,尤其是在有数百万个 benefit_id 的情况下。但是,我知道我可以将整个 FOR LOOP 替换为:
SELECT c.life_scd_id, c.benefit_id
BULK COLLECT INTO life_col
FROM customer c
LEFT JOIN table(benefit_ids) b
WHERE b.benefit_id IS NOT NULL;
但是,为了实现这一点,我认为我需要在架构级别声明一个 Object 类型,因为我认为在 SELECT 查询中您可以加入纯表或对象集合。因此,从我删除的过程中
TYPE benefit_ids_t IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
而是在我定义的架构级别
CREATE OR REPLACE TYPE ben_id FORCE AS object
(
benefit_id number
);
CREATE OR REPLACE TYPE benefit_ids_t FORCE AS TABLE OF ben_id;
我修改后的代码基本上变成了:
CREATE OR REPLACE PROCEDURE ben_correct(in_bulk_collect_limit IN PLS_INTEGER DEFAULT 1000)
IS
sql_str VARCHAR2(1000);
TYPE ben_identity_rec IS RECORD
(
life_scd_id NUMBER,
benefit_id NUMBER
);
TYPE ben_identity_col IS TABLE OF ben_identity_rec INDEX BY PLS_INTEGER;
life_col ben_identity_col;
CURSOR benefit_cur
IS
SELECT benefit_id FROM benefit_info;
--- benefit_ids_t has now been declared at schema level
benefit_ids benefit_ids_t;
PROCEDURE get_next_set_of_incoming(out_benefit_ids OUT NOCOPY benefit_ids_t)
IS
BEGIN
FETCH benefit_cur
BULK COLLECT INTO out_benefit_ids
LIMIT in_bulk_collect_limit;
END;
BEGIN
OPEN benefit_cur;
LOOP
get_next_set_of_incoming(benefit_ids);
sql_str := 'SELECT c.life_scd_id, c.benefit_id
FROM customer c
LEFT JOIN table(benefit_ids) b
WHERE b.benefit_id IS NOT NULL';
EXECUTE IMMEDIATE sql_str BULK COLLECT INTO life_col;
-- Now do further processing with life_col
EXIT WHEN benefit_ids.count = 0;
END LOOP;
CLOSE benefit_cur;
END;
/
但是,这会产生 ORA-24344 和 PLS-00386 错误,即在 FETCH 游标和 INTO 变量之间的“OUT_BENEFIT_IDS”处发现类型不匹配。
我有点理解,它抱怨说 benefit_ids_t 现在是一张 ben_id 表,而 ben_id 又是 number 类型的对象,这与数字表不太一样。
我已经尝试了各种尝试来解决这些问题,但我似乎无法完全正确。任何帮助将不胜感激。
此外,欢迎任何需要改进的通用 cmets。
【问题讨论】:
标签: object collections plsql oracle11g