在plsql中对游标变量名施加了什么限制?

时间:2017-06-06 21:11:27

标签: variables plsql cursor naming-conventions shadowing

我已经在sql developer中执行了以下简单的匿名块,期望从​​" FOO"中删除x行数。但是我最终得到了意想不到的结果,反过来又删除了整行。

DECLARE
  type pkarray IS VARRAY(3) OF RAW(16);
  ids pkarray;      
BEGIN  
  ids := pkarray('guid_value1','guid_value2','guid_value3');          
  FOR i in 1 .. 3 LOOP  
    FOR foo IN (SELECT FOO_ID FROM FOO WHERE BAR_ID = UPPER(ids(i))) LOOP                  
           DELETE FROM FOO WHERE FOO_ID = foo.FOO_ID;                  
    END LOOP;        
  END LOOP;      
END;

然而,当我更改了curor变量&f;"对于#34; abc"这样的程序,程序通过删除x行来正常工作。我提前知道的数字x。

我想了解原因。我很感激您的意见。

1 个答案:

答案 0 :(得分:0)

由于PL / SQL对标识符不区分大小写,因此fooFOO是等价的。让我们重现部分代码,为了清晰起见,以小写形式设置变量名称:

 FOR foo /*1*/ IN (SELECT foo_id FROM foo WHERE bar_id = UPPER(ids(i))) LOOP                  
     DELETE FROM foo /*2*/ WHERE foo_id = foo.foo_id;                  
 END LOOP;

我们在这里处理名字阴影。编译器评估此表达式时

DELETE FROM foo WHERE foo_id = foo.foo_id;

它看到所需的标识符foofoo_id是已知的(在表定义的上下文中)。因此,不需要在语法树中寻求更高的用于定义所使用的名称。换句话说,第一个foo(循环变量)被表名阴影,不用于编译删除查询,这与

相同
DELETE FROM foo WHERE foo_id = foo_id;

及其过滤条件适用于除foo_id之外的所有NULL,这会导致删除整行。

幸运的是,naming conventions可以一劳永逸地解决这个问题:在PL / SQL块中使用带有特殊前缀等的名称,保护您的代码免受与模式对象名称的意外交叉。