相关文章推荐
买醉的仙人球  ·  sqlcmd 实用工具 - SQL ...·  7 月前    · 
伤情的热水瓶  ·  pymysql insert into ...·  1 年前    · 
失落的苹果  ·  10 种超好用的 MyBatis ...·  1 年前    · 

金仓数据库 KingbaseES PL/SQL 过程语言参考手册(17. B PL/SQL名称解析)

数据猿 2022-08-23
73

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;