bulk collect
子句会批量检索结果,即一次性将结果集绑定到一个集合变量中,并从 SQL引擎发送到 PL/SQL引擎。bulk collect into
的目标对象必须是 集合类型关键字 | 解释 | 链接 |
---|---|---|
forall | 用于增强 PL/SQL 引擎到 SQL 引擎的交换 | PL/SQL foall 详解 |
bulk collect | 用于增强 SQL 引擎到 PL/SQL 引擎的交换 |
基础数据准备:
CREATE TABLE stu_info AS (
id number(3),
name varchar2(30),
sex varchar(2)
);
INSERT INTO stu_info(ID, NAME, sex) VALUES(1, '瑶瑶', '女');
INSERT INTO stu_info(ID, NAME, sex) VALUES(2, '优优', '男');
INSERT INTO stu_info(ID, NAME, sex) VALUES(3, '倩倩', '女');
COMMIT;
DECLARE
-- 定义记录类型
TYPE stu_info_record IS RECORD(
id stu_info.id%TYPE,
NAME stu_info.name%TYPE,
sex stu_info.sex%TYPE);
-- 定义基于记录类型的嵌套表
TYPE stu_info_table IS TABLE OF stu_info_record;
-- 声明变量
v_stu_info_table stu_info_table;
BEGIN
-- 使用 bulk collect 将所得的结果集一次绑定到记录记录变量中
SELECT si.id, si.name, si.sex
BULK COLLECT
INTO v_stu_info_table
FROM stu_info si;
-- 输出验证
FOR i IN v_stu_info_table.first .. v_stu_info_table.last LOOP
dbms_output.put_line('id: ' || v_stu_info_table(i).id || ', name: ' || v_stu_info_table(i).name ||
', sex: ' || v_stu_info_table(i).sex);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(SQLCODE || ', ' || SQLERRM);
END;
输出结果:
id: 1, name: 瑶瑶, sex: 女
id: 2, name: 优优, sex: 男
id: 3, name: 倩倩, sex: 女
语法:
fetch ... bulk collect into ... [limit row_number]
limit
子句来限制一次提取的数据量。DECLARE
-- 定义记录类型
TYPE stu_info_record IS RECORD(
id stu_info.id%TYPE,
NAME stu_info.name%TYPE,
sex stu_info.sex%TYPE);
-- 定义基于记录类型的嵌套表
TYPE stu_info_table IS TABLE OF stu_info_record;
-- 声明变量
v_stu_info_table stu_info_table;
-- 声明游标
CURSOR cur_stu_info IS
SELECT si.id, si.name, si.sex FROM stu_info si;
-- 定义变量来记录 fetch 的次数
v_fetch_count PLS_INTEGER := 0;
BEGIN
-- 开启游标
OPEN cur_stu_info;
LOOP
-- fetch 时使用 bulk collect 子句
FETCH cur_stu_info BULK COLLECT
INTO v_stu_info_table LIMIT 2; -- 数据有限,仅做测试,一般限制 500 左右
EXIT WHEN v_stu_info_table.count = 0; -- 注意此时游标退出使用了 xx.count,而不是 xx%notfound
v_fetch_count := v_fetch_count + 1;
-- 输出验证
FOR i IN v_stu_info_table.first .. v_stu_info_table.last LOOP
dbms_output.put_line('id: ' || v_stu_info_table(i).id ||
', name: ' || v_stu_info_table(i).name ||
', sex: ' || v_stu_info_table(i).sex);
END LOOP;
END LOOP;
-- 关闭游标
CLOSE cur_stu_info;
dbms_output.put_line('总共获取的次数:' || v_fetch_count);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(SQLCODE || ', ' || SQLERRM);
-- 异常时,也要关闭游标
IF cur_stu_info%ISOPEN THEN
CLOSE cur_stu_info;
END IF;
END;
输出结果:
id: 1, name: 瑶瑶, sex: 女
id: 2, name: 优优, sex: 男
id: 3, name: 倩倩, sex: 女
总共获取的次数:2 -- 总共 3 条记录,第一次获取 2 条(limit 2), 第二次获取 1 条
insert、update、delete
时,可使用 returning
子句来批量绑定。DECLARE
-- 定义记录类型
TYPE stu_info_record IS RECORD(
id stu_info.id%TYPE,
NAME stu_info.name%TYPE,
sex stu_info.sex%TYPE);
-- 定义基于记录类型的嵌套表
TYPE stu_info_table IS TABLE OF stu_info_record;
-- 声明变量
v_stu_info_table stu_info_table;
BEGIN
-- delete 语句,insert,update 同理
DELETE FROM stu_info si
WHERE si.sex = '女'
RETURNING si.id, si.name, si.sex BULK COLLECT INTO v_stu_info_table;
dbms_output.put_line('删除了 ' || SQL%ROWCOUNT || ' 行记录');
COMMIT;
-- 输出验证
IF v_stu_info_table.count > 0 THEN
FOR i IN v_stu_info_table.first .. v_stu_info_table.last LOOP
dbms_output.put_line('id: ' || v_stu_info_table(i).id ||
', name: ' || v_stu_info_table(i).name ||
', sex: ' || v_stu_info_table(i).sex);
END LOOP;
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(SQLCODE || ', ' || SQLERRM);
END;
输出结果:
删除了 2 行记录
id: 1, name: 瑶瑶, sex: 女
id: 3, name: 倩倩, sex: 女
需求:将 stu_info 中的数据同步至 stu_info_temp
基础数据准备:
TRUNCATE TABLE stu_info ;
INSERT INTO stu_info(ID, NAME, sex) VALUES(1, '瑶瑶', '女');
INSERT INTO stu_info(ID, NAME, sex) VALUES(2, '优优', '男');
INSERT INTO stu_info(ID, NAME, sex) VALUES(3, '倩倩', '女');
COMMIT;
-- 测试表
CREATE TABLE stu_info_temp AS SELECT * from stu_info WHERE 1 = 2;
实战:
DECLARE
-- 声明游标
CURSOR cur_stu_info IS
SELECT si.id, si.name, si.sex FROM stu_info si;
-- 定义基于游标类型的嵌套表 (也可用 RECORD 替换,只是写法会稍微麻烦点)
TYPE stu_info_table IS TABLE OF cur_stu_info%ROWTYPE;
-- 声明变量
v_stu_info_table stu_info_table;
BEGIN
-- 开启游标
OPEN cur_stu_info;
LOOP
-- fetch 时使用 bulk collect 子句
FETCH cur_stu_info BULK COLLECT
INTO v_stu_info_table LIMIT 2; -- 数据有限,仅做测试,一般限制 500 左右
EXIT WHEN v_stu_info_table.count = 0; -- 注意此时游标退出使用了 xx.count,而不是 xx%notfound
-- 批量插入
FORALL i IN 1 .. v_stu_info_table.count
-- INSERT INTO stu_info_temp (id, NAME, sex) VALUES v_stu_info (i); -- ORA-00947: 没有足够的值
INSERT INTO
(SELECT sit.id, sit.name, sit.sex FROM stu_info_temp sit)
VALUES v_stu_info_table
(i);
END LOOP;
-- 关闭游标
CLOSE cur_stu_info;
-- 提交数据
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(dbms_utility.format_error_backtrace);
dbms_output.put_line(SQLCODE || ', ' || SQLERRM);
-- 异常时,也要关闭游标
IF cur_stu_info%ISOPEN THEN
CLOSE cur_stu_info;
END IF;
END;