PLSQL中的光标变量名称所施加了什么



我在SQL开发人员中的简单匿名块中执行了执行,期望将x行从" foo"中删除。但是表我最终取得了意外的结果,从而删除了整行。

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;

但是,当我更改光标变量'foo;对于" ABC"之类的其他内容,该程序通过删除x行数来正确地工作。我提前知道的数字x。

由于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;

及其过滤条件对于除 NULL以外的所有foo_id都是正确的,什么导致删除整个行。


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

最新更新