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;