Oracle 之 bulk collect 的用法
2008-03-14 10:44
344 查看
通过bulk collect减少loop处理的开销
采用bulk collect可以将查询结果一次性地加载到collections中。
而不是通过cursor一条一条地处理。
可以在select into,fetch into,returning into语句使用bulk collect。
注意在使用bulk collect时,所有的into变量都必须是collections.
举几个简单的例子:
--在select into语句中使用bulk collect
DECLARE
TYPE sallist IS TABLE OF emp.sal%TYPE;
sals sallist;
BEGIN
-- Limit the number of rows to 100.
SELECT sal
BULK COLLECT INTO sals
FROM emp
WHERE ROWNUM <= 100;
-- Retrieve 10% (approximately) of the rows in the table.
SELECT sal BULK COLLECT INTO sals FROM emp SAMPLE 10;
END;
--在fetch into中使用bulk collect
DECLARE
TYPE deptrectab IS TABLE OF dept%ROWTYPE;
dept_recs deptrectab;
CURSOR c1
IS
SELECT deptno, dname, loc
FROM dept
WHERE deptno > 10;
BEGIN
OPEN c1;
FETCH c1
BULK COLLECT INTO dept_recs;
END;
在returning into中使用bulk collect
CREATE TABLE emp2 AS SELECT * FROM employees;
DECLARE
TYPE numlist IS TABLE OF employees.employee_id%TYPE;
enums numlist;
TYPE namelist IS TABLE OF employees.last_name%TYPE;
names namelist;
BEGIN
DELETE FROM emp2
WHERE department_id = 30
RETURNING employee_id, last_name
BULK COLLECT INTO enums, names;
DBMS_OUTPUT.put_line ('Deleted ' || SQL%ROWCOUNT || ' rows:');
FOR i IN enums.FIRST .. enums.LAST
LOOP
DBMS_OUTPUT.put_line ('Employee #' || enums (i) || ': ' || names (i));
END LOOP;
END;
/
DROP TABLE emp2;
这里有一个很好的例子
CREATE OR REPLACE PACKAGE comp_analysis
IS
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
RETURN BOOLEAN;
END comp_analysis;
/
CREATE OR REPLACE PACKAGE BODY comp_analysis
IS
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
RETURN BOOLEAN
IS
BEGIN
RETURN MOD (id_in, 2) = 0;
END;
END comp_analysis;
/
CREATE OR REPLACE PROCEDURE give_raises_in_department1 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
CURSOR emp_cur
IS
SELECT employee_id, salary, hire_date
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
emp_rec emp_cur%ROWTYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur
INTO emp_rec;
EXIT WHEN emp_cur%NOTFOUND;
IF comp_analysis.is_eligible (emp_rec.employee_id)
THEN
UPDATE lots_of_employees
SET salary = newsal
WHERE employee_id = emp_rec.employee_id;
ELSE
INSERT INTO employee_history
(employee_id, salary
, hire_date, activity
)
VALUES (emp_rec.employee_id, emp_rec.salary
, emp_rec.hire_date, 'RAISE DENIED'
);
END IF;
END LOOP;
END give_raises_in_department1;
/
SHO ERR
REM
REM Pre-10g create multiple copies of collection
REM for different purposes.
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department2 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
approved_employee_ids employee_aat;
denied_employee_ids employee_aat;
denied_salaries salary_aat;
denied_hire_dates hire_date_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees (indx))
THEN
approved_employee_ids (indx) := employees (indx);
ELSE
denied_employee_ids (indx) := employees (indx);
denied_salaries (indx) := salaries (indx);
denied_hire_dates (indx) := hire_dates (indx);
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN denied_employee_ids.FIRST .. denied_employee_ids.LAST
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (denied_employee_ids (indx)
, denied_salaries (indx)
, denied_hire_dates (indx), 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN approved_employee_ids.FIRST .. approved_employee_ids.LAST
UPDATE lots_of_employees
SET salary = newsal
WHERE employee_id = approved_employee_ids (indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department2;
/
SHO ERR
REM
REM 10g usage of INDICES OF
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department3 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
TYPE guide_aat IS TABLE OF BOOLEAN
INDEX BY PLS_INTEGER;
approved_list guide_aat;
denied_list guide_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees(indx))
THEN
approved_list (indx) := TRUE;
ELSE
denied_list (indx) := TRUE;
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN INDICES OF denied_list
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (employees (indx)
, salaries (indx)
, hire_dates (indx)
, 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN INDICES OF approved_list
UPDATE lots_of_employees
SET salary = newsal
, hire_date = hire_dates(indx)
WHERE employee_id = employees(indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department3;
/
SHO ERR
REM
REM 10g usage of VALUES OF
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department4 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
TYPE guide_aat IS TABLE OF PLS_INTEGER
INDEX BY PLS_INTEGER;
approved_list guide_aat;
denied_list guide_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees(indx))
THEN
approved_list (indx) := indx;
ELSE
denied_list (indx) := indx;
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN VALUES OF denied_list
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (employees (indx)
, salaries (indx)
, hire_dates (indx)
, 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN VALUES OF approved_list
UPDATE lots_of_employees
SET salary = newsal
, hire_date = hire_dates(indx)
WHERE employee_id = employees(indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department4;
/
SHO ERR
SET TIMING ON
BEGIN
give_raises_in_department1 (NULL, 1000);
END;
/
BEGIN
give_raises_in_department2 (NULL, 1000);
END;
/
BEGIN
give_raises_in_department3 (NULL, 1000);
END;
/
采用bulk collect可以将查询结果一次性地加载到collections中。
而不是通过cursor一条一条地处理。
可以在select into,fetch into,returning into语句使用bulk collect。
注意在使用bulk collect时,所有的into变量都必须是collections.
举几个简单的例子:
--在select into语句中使用bulk collect
DECLARE
TYPE sallist IS TABLE OF emp.sal%TYPE;
sals sallist;
BEGIN
-- Limit the number of rows to 100.
SELECT sal
BULK COLLECT INTO sals
FROM emp
WHERE ROWNUM <= 100;
-- Retrieve 10% (approximately) of the rows in the table.
SELECT sal BULK COLLECT INTO sals FROM emp SAMPLE 10;
END;
--在fetch into中使用bulk collect
DECLARE
TYPE deptrectab IS TABLE OF dept%ROWTYPE;
dept_recs deptrectab;
CURSOR c1
IS
SELECT deptno, dname, loc
FROM dept
WHERE deptno > 10;
BEGIN
OPEN c1;
FETCH c1
BULK COLLECT INTO dept_recs;
END;
在returning into中使用bulk collect
CREATE TABLE emp2 AS SELECT * FROM employees;
DECLARE
TYPE numlist IS TABLE OF employees.employee_id%TYPE;
enums numlist;
TYPE namelist IS TABLE OF employees.last_name%TYPE;
names namelist;
BEGIN
DELETE FROM emp2
WHERE department_id = 30
RETURNING employee_id, last_name
BULK COLLECT INTO enums, names;
DBMS_OUTPUT.put_line ('Deleted ' || SQL%ROWCOUNT || ' rows:');
FOR i IN enums.FIRST .. enums.LAST
LOOP
DBMS_OUTPUT.put_line ('Employee #' || enums (i) || ': ' || names (i));
END LOOP;
END;
/
DROP TABLE emp2;
这里有一个很好的例子
CREATE OR REPLACE PACKAGE comp_analysis
IS
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
RETURN BOOLEAN;
END comp_analysis;
/
CREATE OR REPLACE PACKAGE BODY comp_analysis
IS
FUNCTION is_eligible (id_in IN lots_of_employees.employee_id%TYPE)
RETURN BOOLEAN
IS
BEGIN
RETURN MOD (id_in, 2) = 0;
END;
END comp_analysis;
/
CREATE OR REPLACE PROCEDURE give_raises_in_department1 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
CURSOR emp_cur
IS
SELECT employee_id, salary, hire_date
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
emp_rec emp_cur%ROWTYPE;
BEGIN
OPEN emp_cur;
LOOP
FETCH emp_cur
INTO emp_rec;
EXIT WHEN emp_cur%NOTFOUND;
IF comp_analysis.is_eligible (emp_rec.employee_id)
THEN
UPDATE lots_of_employees
SET salary = newsal
WHERE employee_id = emp_rec.employee_id;
ELSE
INSERT INTO employee_history
(employee_id, salary
, hire_date, activity
)
VALUES (emp_rec.employee_id, emp_rec.salary
, emp_rec.hire_date, 'RAISE DENIED'
);
END IF;
END LOOP;
END give_raises_in_department1;
/
SHO ERR
REM
REM Pre-10g create multiple copies of collection
REM for different purposes.
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department2 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
approved_employee_ids employee_aat;
denied_employee_ids employee_aat;
denied_salaries salary_aat;
denied_hire_dates hire_date_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees (indx))
THEN
approved_employee_ids (indx) := employees (indx);
ELSE
denied_employee_ids (indx) := employees (indx);
denied_salaries (indx) := salaries (indx);
denied_hire_dates (indx) := hire_dates (indx);
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN denied_employee_ids.FIRST .. denied_employee_ids.LAST
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (denied_employee_ids (indx)
, denied_salaries (indx)
, denied_hire_dates (indx), 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN approved_employee_ids.FIRST .. approved_employee_ids.LAST
UPDATE lots_of_employees
SET salary = newsal
WHERE employee_id = approved_employee_ids (indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department2;
/
SHO ERR
REM
REM 10g usage of INDICES OF
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department3 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
TYPE guide_aat IS TABLE OF BOOLEAN
INDEX BY PLS_INTEGER;
approved_list guide_aat;
denied_list guide_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees(indx))
THEN
approved_list (indx) := TRUE;
ELSE
denied_list (indx) := TRUE;
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN INDICES OF denied_list
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (employees (indx)
, salaries (indx)
, hire_dates (indx)
, 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN INDICES OF approved_list
UPDATE lots_of_employees
SET salary = newsal
, hire_date = hire_dates(indx)
WHERE employee_id = employees(indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department3;
/
SHO ERR
REM
REM 10g usage of VALUES OF
REM
CREATE OR REPLACE PROCEDURE give_raises_in_department4 (
dept_in IN lots_of_employees.department_id%TYPE
, newsal IN lots_of_employees.salary%TYPE
)
IS
TYPE employee_aat IS TABLE OF lots_of_employees.employee_id%TYPE
INDEX BY PLS_INTEGER;
TYPE salary_aat IS TABLE OF lots_of_employees.salary%TYPE
INDEX BY PLS_INTEGER;
TYPE hire_date_aat IS TABLE OF lots_of_employees.hire_date%TYPE
INDEX BY PLS_INTEGER;
employee_ids employee_aat;
salaries salary_aat;
hire_dates hire_date_aat;
TYPE guide_aat IS TABLE OF PLS_INTEGER
INDEX BY PLS_INTEGER;
approved_list guide_aat;
denied_list guide_aat;
PROCEDURE retrieve_employee_info
IS
BEGIN
SELECT employee_id, salary, hire_date
BULK COLLECT INTO employee_ids, salaries, hire_dates
FROM lots_of_employees
WHERE (department_id = dept_in OR dept_IN IS NULL);
END;
PROCEDURE partition_by_eligibility
IS
BEGIN
FOR indx IN employee_ids.FIRST .. employee_ids.LAST
LOOP
IF comp_analysis.is_eligible (employees(indx))
THEN
approved_list (indx) := indx;
ELSE
denied_list (indx) := indx;
END IF;
END LOOP;
END;
PROCEDURE add_to_history
IS
BEGIN
FORALL indx IN VALUES OF denied_list
INSERT INTO employee_history
(employee_id
, salary
, hire_date, activity
)
VALUES (employees (indx)
, salaries (indx)
, hire_dates (indx)
, 'RAISE DENIED'
);
END;
PROCEDURE give_the_raise
IS
BEGIN
FORALL indx IN VALUES OF approved_list
UPDATE lots_of_employees
SET salary = newsal
, hire_date = hire_dates(indx)
WHERE employee_id = employees(indx);
END;
BEGIN
retrieve_employee_info;
partition_by_eligibility;
add_to_history;
give_the_raise;
END give_raises_in_department4;
/
SHO ERR
SET TIMING ON
BEGIN
give_raises_in_department1 (NULL, 1000);
END;
/
BEGIN
give_raises_in_department2 (NULL, 1000);
END;
/
BEGIN
give_raises_in_department3 (NULL, 1000);
END;
/
相关文章推荐
- oracle学习总结三(bulk collect用法)
- oracle pl/sql(bulk collect用法)
- Oracle 之 bulk collect 的用法
- Oracle 的 bulk collect 和 forall 用法
- oracle中bulk collect用法
- Oracle 的 bulk collect用法——批量查询
- oracle学习总结三(bulk collect用法)
- Oracle 的 bulk collect用法——批量增删改
- Oracle 之 bulk collect 的用法
- Oracle中coalesce函数的用法
- Oracle Hint的用法
- Oracle group by 及相关函数用法实例详解
- Oracle基础 -- SQL *Plus基本用法
- oracle学习之bulk collect用法
- Oracle分析函数二——函数用法
- oracle的rownum与having用法 去除重复 在重复情况用rownum
- 创建表结构相同的表,表结构相同的表之间复制数据,Oracle 中 insert into XXX select from 的用法
- C#中操作Oracle时的SQL语句参数的用法
- oracle中substr函数的用法
- Oracle临时表的几种用法及意义