我已经在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。
我想了解原因。我很感激您的意见。
答案 0 :(得分:0)
由于PL / SQL对标识符不区分大小写,因此foo
和FOO
是等价的。让我们重现部分代码,为了清晰起见,以小写形式设置变量名称:
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;
它看到所需的标识符foo
和foo_id
是已知的(在表定义的上下文中)。因此,不需要在语法树中寻求更高的用于定义所使用的名称。换句话说,第一个foo
(循环变量)被表名阴影,不用于编译删除查询,这与
DELETE FROM foo WHERE foo_id = foo_id;
及其过滤条件适用于除foo_id
之外的所有NULL
,这会导致删除整行。
幸运的是,naming conventions可以一劳永逸地解决这个问题:在PL / SQL块中使用带有特殊前缀等的名称,保护您的代码免受与模式对象名称的意外交叉。