PL/SQL中依赖变量的游标为何能正常运行?
关于PL/SQL动态游标运行原理的疑问
示例代码
DECLARE PIDM NUMBER(8); CLM_TEST_SCORE NUMBER(5); CURSOR C_STUDENT IS select PIDM from SOSC.DW_ALL_COLLECTOR order by PIDM; CURSOR C_CLM_SCORES IS select max(to_number(SORTEST_TEST_SCORE)) from SATURN.SORTEST where SORTEST_PIDM = pidm; BEGIN OPEN C_STUDENT; LOOP CLM_TEST_SCORE := ''; FETCH c_Student INTO pidm; EXIT WHEN c_Student%notfound; OPEN C_CLM_SCORES; FETCH C_CLM_SCORES INTO CLM_TEST_SCORE; CLOSE C_CLM_SCORES; insert into some_table (CLM_TEST_SCORE) values (CLM_TEST_SCORE); END LOOP; END;
疑问
我注意到C_CLM_SCORES游标中引用的pidm是第2行声明的PIDM变量,这意味着游标对应的查询会随着循环每次迭代中pidm的当前值变化。但我之前理解游标是“执行中的查询”,底层查询不应该在每次循环时改变,可这段代码实际能正常运行,想了解它的运行原理是什么?
解答
你遇到的是PL/SQL中静态游标引用PL/SQL变量的典型场景,核心原理如下:
C_CLM_SCORES属于静态游标,它的查询文本结构是固定的,但WHERE子句引用了PL/SQL块内的PIDM变量。- 游标并非在定义阶段就执行查询,而是每次调用
OPEN时才会触发查询的执行准备:此时Oracle会读取PIDM变量的当前有效值,将其作为绑定变量代入查询条件,生成对应的执行计划(符合条件时会复用共享池中的执行计划),随后执行查询获取结果。 - 你之前的误解混淆了“游标定义”和“游标执行时机”:游标定义只是固定了查询的框架,而每次打开时会动态注入变量的当前值,因此每次循环中查询的过滤条件会随
PIDM的变化而变化,代码自然能正常运行。
额外提一句:这种写法虽然可行,但效率较低——每次循环都要打开、关闭游标,会带来不必要的上下文切换开销。更优的写法是使用参数化游标(定义时显式传入参数),或者直接用关联查询一次性完成数据处理,避免嵌套游标操作。比如参数化游标可以这么写:
CURSOR C_CLM_SCORES(p_pidm NUMBER) IS select max(to_number(SORTEST_TEST_SCORE)) from SATURN.SORTEST where SORTEST_PIDM = p_pidm; -- 打开时传入参数 OPEN C_CLM_SCORES(pidm);
内容的提问来源于stack exchange,提问作者Jakob Lovern
相关产品推荐
相关产品推荐

