17. B PL/SQL名称解析
本附录解释 PL/SQL名称解析;也就是说,PL/SQL 编译器如何解析对标识符的模糊引用。
如果您在其编译单元中更改标识符(即如果您添加、重命名或删除标识符),则明确的标识符引用可能会变得不明确。
注意
存储的 PL/SQL 单元的AUTHID属性会影响该单元在运行时发出的 SQL 语句的名称解析。有关详细信息,请参阅“ 调用者的权限和定义者的权限(AUTHID 属性) ”。
17.1. 限定名称和点符号
当一个命名项属于另一个命名项时,您可以(有时必须)使用点表示法用“父”项的名称来限定“子”项的名称。例如:
引用 |
名称限定 |
语法 |
---|---|---|
记录的字段 |
记录名称 |
record_name.field_name |
集合方法 |
集合名称 |
collection_name.method |
伪列CURRVAL |
序列名称 |
sequence_name.CURRVAL |
伪列NEXTVAL |
序列名称 |
sequence_name.NEXTVAL |
如果在命名的 PL/SQL 单元中声明了一个标识符,您可以使用该单元的名称(块、子程序或包)来限定其简单名称(其声明中的名称),使用以下语法:
unit_name.simple_identifier_name
如果标识符不可见,则必须限定其名称(请参阅“标识符的范围和可见性”)。
如果标识符属于另一个模式,则必须使用模式名称限定其名称,使用以下语法:
schema_name.package_name
一个简单的名称可以用多个名称来限定,如:ref: ` 示例 B-1`所示。
可能有歧义的限定名称的一些示例是: - 函数返回值的字段或属性,例如:
func_name().field_name func_name().attribute_name
-
另一个架构拥有的架构对象,例如:
schema_name.table_name schema_name.procedure_name() schema_name.type_name.member_name()
另一个用户拥有的包对象,例如:
schema_name.package_name.procedure_name() schema_name.package_name.record_name.field_name
包含 ADT 的记录,例如:
record_name.field_name.attribute_name record_name.field_name.member_name ()
示例 B-1 限定名称
\set SQLTERM / CREATE OR REPLACE PACKAGE pkg1 AUTHID DEFINER AS num NUMBER; TYPE rt IS RECORD (a NUMBER); var1 rt; TYPE ct IS TABLE OF rt INDEX BY PLS_INTEGER; var2 ct; FUNCTION f1 (a1 NUMBER) RETURN rt; FUNCTION f2 (a2 NUMBER) RETURN ct; END pkg1; CREATE OR REPLACE PACKAGE BODY pkg1 AS FUNCTION f1 (a1 NUMBER) RETURN rt IS n NUMBER; BEGIN n := num; -- 不合格的变量名 n := pkg1.num; -- 包名限定的变量名 n := pkg1.f1.a1; -- 函数名限定的参数名,由包名限定 n := var1.a; -- 变量名后跟字段名 n := pkg1.var1.a; -- 包名限定的变量名后跟组件名称 var1.a := a1; RETURN var1; END f1; FUNCTION f2 (a2 NUMBER) RETURN ct IS v_rt rt; v_ct ct; BEGIN v_rt.a := a2; v_ct(1) := v_rt; RETURN v_ct; END f2; END pkg1;
17.2. 列名优先级
如果 SQL 语句引用的名称既属于列又属于局部变量或形参,则列名优先。
警告
当变量或参数名称被解释为列名称时,可能会无意中删除、更改或插入数据。
在:ref: ` 示例 B-2`中,名称 name 既属于局部变量又属于列(名称不区分大小写)。因此,在 WHERE 子句中,对 name 的两个引用都解析为列,并且所有行都被删除。
:ref: ` 示例 B-3`通过给变量一个不同的名称 来解决:ref: ` 示例 B-2`中的问题。
在:ref: ` 示例 B-4`中,函数 dept_name 有一个形式参数和一个局部变量,其名称是表 DEPARTMENTS 的列的名称。参数和变量名用函数名限定,以区别于列名。
示例 B-2 解释为列名的变量名导致意外结果
DROP TABLE IF EXISTS student; CREATE TABLE student (id int PRIMARY KEY, name text, score number); insert into student values (1, 'xx', 99); CREATE TABLE stu_name AS SELECT name FROM student; \set SQLTERM / DECLARE name TEXT := 'xa'; BEGIN DELETE FROM student WHERE name = name; RAISE NOTICE 'Deleted % rows', SQL%ROWCOUNT;
结果:
NOTICE: Deleted 1 rows
示例 B-3使用不同的变量名称 修复示例 B-2
insert into student values (1, 'xx', 99); \set SQLTERM / DECLARE v_name TEXT := 'xa'; BEGIN DELETE FROM student WHERE name = v_name; RAISE NOTICE 'Deleted % rows', SQL%ROWCOUNT;
结果:
NOTICE: Deleted 0 rows
示例 B-4 名称解析的子程序名称
\set SQLTERM / DECLARE FUNCTION stu_name (id IN NUMBER) RETURN student.name%TYPE AS DECLARE v_name student.name%TYPE; BEGIN SELECT name INTO v_name FROM student WHERE id = stu_name.id; RETURN v_name; END stu_name; BEGIN FOR item IN ( SELECT id FROM student) LOOP RAISE NOTICE 'Student: %', stu_name(item.id); END LOOP;