SqlDemo
SET SERVEROUTPUT ON
DECLARE
VERSION_NO_MAX INT;
TYPE tb_table_type IS TABLE OF TABLE_NAME%rowtype; -- 目标表 类型
tb_table tb_table_type; -- 目标表 集合
CURSOR temp_cursor IS -- 需要添加的数据
SELECT * FROM TABLE_NAME
WHERE VERSION_NO = VERSION_NO_MAX;
BEGIN
dbms_output.put_line('VERSION_NO_MAX = ' || VERSION_NO_MAX);
-- 获取最大版本号
SELECT NVL(MAX(VERSION_NO), 0) + 0 INTO VERSION_NO_MAX
FROM TABLE_NAME;
dbms_output.put_line('VERSION_NO_MAX = ' || VERSION_NO_MAX);
-- 逻辑
OPEN temp_cursor;
LOOP
-- 从 游标 中取出指定长度数据放到 内存中
FETCH temp_cursor BULK COLLECT INTO tb_table LIMIT 10000;
dbms_output.put_line('COUNT = ' || tb_table.COUNT);
-- 如果没有数据则退出
EXIT WHEN temp_cursor%notfound;
END LOOP;
CLOSE temp_cursor;
END;
1. 游标定义阶段:只解析 SQL 结构
当 PL/SQL 解析器处理CURSOR temp_cursor IS ...语句时:
1.只进行语法检查和 SQL 结构解析
2.不会立即执行 SQL 语句
3.变量 VERSION_NO_MAX 在此时只是一个占位符,解析器知道它是一个变量,但不关心其值
2. 游标打开阶段:绑定变量值
当执行OPEN temp_cursor时,PL/SQL 会:
1.编译 SQL 语句
2.将变量VERSION_NO_MAX的值绑定到 SQL 中
3.此时VERSION_NO_MAX已经被赋值,所以绑定的是正确的值
3. 变量作用域与值传递
1.变量在 DECLARE 块中声明,在 BEGIN 块中赋值
2.游标定义中引用的变量,实际使用的是打开游标时该变量的当前值
3.这类似于动态 SQL 中的绑定变量机制
4. 游标执行计划与变量值
数据库执行游标 SQL 时:
1.会根据绑定的变量值生成执行计划
2.变量值的变化不会影响 SQL 的语法结构,只是改变查询条件
5.游标工作流程示意图
1. 解析阶段:
CURSOR temp_cursor IS SELECT * FROM table WHERE VERSION_NO = :bind_var;
(将VERSION_NO_MAX识别为绑定变量:bind_var)
2. BEGIN块执行:
VERSION_NO_MAX = NULL; -- 初始值
VERSION_NO_MAX = 100; -- 查询后赋值
3. 打开游标时:
执行SQL: SELECT * FROM table WHERE VERSION_NO = 100;
(将变量值100绑定到:bind_var)
6.这种写法的潜在风险
1.变量未初始化警告:PL/SQL 编译器会提示 "Variable"VERSION_NO_MAX"might not have been initialized"
2.逻辑可读性问题:先使用后赋值不符合常规编程习惯,可能让其他开发者困惑
3.意外 NULL 值风险:如果查询结果为空,VERSION_NO_MAX会被赋值为 0,但初始输出时可能显示 NULL
7.最佳实践写法
SET SERVEROUTPUT ON
DECLARE
VERSION_NO_MAX INT;
TYPE tb_table_type IS TABLE OF TABLE_NAME%rowtype; -- 目标表 类型
tb_table tb_table_type; -- 目标表 集合
CURSOR temp_cursor(ITEM_VERSION_NO INT) IS -- 需要添加的数据
SELECT * FROM TABLE_NAME
WHERE VERSION_NO = ITEM_VERSION_NO;
BEGIN
dbms_output.put_line('VERSION_NO_MAX = ' || VERSION_NO_MAX);
-- 获取最大版本号
SELECT NVL(MAX(VERSION_NO), 0) + 0 INTO VERSION_NO_MAX
FROM TABLE_NAME;
dbms_output.put_line('VERSION_NO_MAX = ' || VERSION_NO_MAX);
-- 逻辑
OPEN temp_cursor(VERSION_NO_MAX);
LOOP
-- 从 游标 中取出指定长度数据放到 内存中
FETCH temp_cursor BULK COLLECT INTO tb_table LIMIT 10000;
dbms_output.put_line('COUNT = ' || tb_table.COUNT);
-- 如果没有数据则退出
EXIT WHEN temp_cursor%notfound;
END LOOP;
CLOSE temp_cursor;
END;
7.1.这种写法的好处
1.符合 "先赋值后使用" 的编程习惯
2.明确游标参数,提高代码可读性
3.避免变量未初始化的警告
4.更清晰地表达游标的查询条件依赖关系
总结
PL/SQL 游标之所以能在变量先使用后赋值的情况下正常工作,是因为:
1.游标定义时只解析 SQL 结构,不执行也不关心变量值
2.游标打开时才会绑定变量的当前值
3.这本质上是一种绑定变量的机制,与动态 SQL 的工作原理类似