Oracle PL/SQL Programming 第3章:Language Fundamentals 读书笔记

总的目录和进度,请参见开始读 Oracle PL/SQL Programming 第6版

每种语言(无论是人类语言还是计算机语言)都有语法、词汇和字符集。 为了使用该语言进行交流,您必须学习管理其使用的规则。 我们许多人对学习新的计算机语言持谨慎态度。 变化往往令人恐惧,但通常编程语言都非常简单,PL/SQL 也不例外。 在基于字节的语言中进行对话的困难不在于语言本身,而在于我们正在讨论的编译器或计算机。 大多数情况下,编译器都是相当愚蠢的。 他们不是有创造力的众生。 他们没有原创思想的能力。 他们的词汇量非常有限。 编译器只是碰巧以非常非常快的速度思考他们枯燥的想法,而且非常不灵活。

本章涵盖了帮助您与 PL/SQL 编译器进行交互的基本语言规则------PL/SQL 块结构、字符集、词法单元和 PRAGMA 关键字。

PL/SQL Block Structure

在 PL/SQL 中,最小的有意义的代码分组称为块。 块是一个代码单元,为变量声明和异常处理提供执行和范围边界。 PL/SQL 允许您创建匿名块(没有名称的代码块)和命名块,它们可以是包、过程、函数、触发器或对象类型。

PL/SQL 块最多有四个不同的部分,其中只有一个是必须的:

  • 标头:仅用于命名块。 标头确定必须调用命名块或程序的方式。 可选。
  • 声明部分:标识在执行和异常部分中引用的变量、游标和子块。 可选。
  • 执行部分:包含 PL/SQL 运行时引擎将在运行时执行的语句。 必须。
  • 异常部分:处理异常(警告和错误情况)。 可选。
sql 复制代码
标头
IS
	声明部分
BEGIN
	执行部分
EXCEPTION
	异常部分
END;

Anonymous Blocks

当有人希望保持匿名时,该人就不会被透露姓名。 这与 PL/SQL 中的匿名块相同,如下例所示:它完全没有标头部分,而是以 DECLARE 或 BEGIN 开头。 这意味着它不能被任何其他块调用------它没有可供引用的句柄。 相反,匿名块充当执行 PL/SQL 语句的容器,通常包括对过程和函数的调用。 由于匿名块可以有自己的声明和异常部分,因此开发人员经常嵌套匿名块以在较大的程序中提供标识符和异常处理的范围。

sql 复制代码
BEGIN
	DBMS_OUTPUT.PUT_LINE('Hello, World!');
END;

匿名 PL/SQL 块的一般语法如下,中括号表示可选部分:

sql 复制代码
[ DECLARE   ... 声明语句 ... ]
BEGIN   ... 一个或多个执行语句 ...
[ EXCEPTION
   ... 异常处理语句... ]
END;

匿名块执行一系列语句然后终止,因此就像过程一样。 事实上,所有匿名块都是匿名过程。 它们用于各种环境中,其中 PL/SQL 代码要么直接执行,要么包含在该环境中的某个程序中。 常见的例子包括:

  • 数据库触发器

    当某些事件发生时,数据库触发器会执行匿名块。

  • 即席命令或脚本文件

    在 SQL*Plus 或类似的执行环境中,匿名块从手动输入的块或从调用存储程序的脚本运行。 此外,SQL*Plus EXECUTE 命令通过将其参数包含在 BEGIN 和 END 语句之间,将其参数转换为匿名块。

  • 编译3GL(第三代语言)程序

    在 Pro*C 或 OCI 中,匿名块可以作为嵌入对存储程序的调用的方法。

在每种情况下,封闭匿名块的对象(无论是触发器、命令行环境还是已编译的程序)都提供上下文以及可能的程序命名方式。

Named Blocks

虽然匿名 PL/SQL 块是必不可少的,但您编写的大部分代码都将在命名块中。 匿名块和命名块的区别在于标头。 如下所示:

sql 复制代码
-- 过程的标头
PROCEDURE [schema.]name [ ( parameter [, parameter ... ] ) ]
   [AUTHID {DEFINER | CURRENT_USER}]

-- 函数的标头
FUNCTION [schema.]name [ ( parameter [, parameter ... ] ) ]
   RETURN return_datatype
   [AUTHID {DEFINER | CURRENT_USER}]
   [DETERMINISTIC]
   [PARALLEL ENABLE ...]
   [PIPELINED [USING...] | AGGREGATE USING...]

由于 Oracle 允许您从 SQL 语句中调用某些函数,因此函数头包含比过程头更多的可选组件,与 SQL 运行时环境的功能和性能维度相对应。

Nested Blocks

PL/SQL 与 Ada 和 Pascal 共享块结构语言的附加定义,即块可以"嵌套"在其他块内,而且可以多级嵌套。 相比之下,C 语言有块,但标准 C 并不是严格的块结构,因为它的子程序不能嵌套。

您可能听到的有关嵌套块的其他术语包括封闭块、子块; 外围 PL/SQL 块可以称为封闭块或父块。

一般来说,嵌套块的优点是它为您提供了一种控制代码中的范围和可见性的方法。

Scope

在任何编程语言中,术语"范围"是指识别给定标识符所引用的"事物"的方式。 如果某个标识符出现多次,则该语言的作用域规则将定义将使用哪一个。 仔细控制标识符范围不仅会增加对运行时行为的控制,还会减少程序员意外修改错误变量的可能性。

在 PL/SQL 中,变量、异常、模块和一些其他结构对于声明它们的块来说是本地的。 当块停止执行时,您将无法再引用任何这些结构。 可以在过程中的任何位置引用外部块中的元素; 但是,内部块中声明的元素不可用于外部块。

每个 PL/SQL 变量都有一个范围:即可以在其中引用该变量的程序单元(块、子程序或包)的区域。

作者代码中的好习惯:变量定义遵循约定,即全局变量以g_开头,局部变量以l_开头

Qualify All References to Variables and Columns in SQL Statements

前面的例子,变量的引用是隐式的,下面是显式引用的例子:

sql 复制代码
PACKAGE BODY scope_demo
IS
   PROCEDURE set_global (number_in IN NUMBER)
   IS
     l_salary  ...;
     l_count   ...;
   BEGIN
      
      DECLARE
         l_inner   PLS_INTEGER;
      BEGIN
         ... set_global.l_count ...
         ... local_block.l_inner ...
         ... set_global.l_salary ...
      END local_block;

      scope_demo.g_global := set_global.number_in;
   END set_global;
END scope_demo;

可以看到,变量前面均加了范围指定符,如set_global是PROCEDURE名,local_block是BLOCK名,scope_demo是PACKAGE名。范围指定符均出现在END后面。

显式引用有几个好处:

  1. 提高代码的可读性
  2. 避免变量名称与列名称相同时可能出现的错误
  3. 充分利用 Oracle Database 11g 中提供的细粒度依赖性跟踪

我们先看前两个,第 20 章再解释第三个。

Improve readability

PL/SQL 程序中嵌入的几乎每个 SQL 语句都包含对列和变量的引用。 在小而简单的 SQL 语句中,区分这些不同的引用相对容易。 然而,在大多数应用程序中,您会发现非常长、极其复杂的 SQL 语句,其中包含数十甚至数百个对列和变量的引用。

如果您不限定这些引用,则很难一眼区分变量和列。 通过这些限定符,代码可以非常清楚地自我记录这些引用的来源。

尽管命名约定很有帮助,例如'l_'开头表示局部变量,'g_'开头表示全局变量。但并不足以保证随着时间的推移,PL/SQL 编译器始终按照您的预期解释您的标识符。

Avoid bugs through qualifiers

如果您没有限定对嵌入式 SQL 语句中所有 PL/SQL 变量的引用,那么今天正常工作的代码将来可能会突然不再工作。 而且可能很难找出问题所在。

例如下面这个没有指定范围限定符的例子。l_salary当时是个局部变量,但2年后,应用决定为表增加一列,也叫l_salary,此时就发生了冲突:

sql 复制代码
SELECT 
...  WHERE salary > l_salary;

在嵌入式 SQL 语句中,Oracle 数据库对未解析的标识符,会首先尝试将引用解析为指定表之一中的列。 如果找不到匹配项,它会尝试将引用解析为作用域内的 PL/SQL 变量。

所以你看,编译都没有错误,但业务逻辑就变了。这可能是一个非常难以追踪和修复的错误!

您还应该限定对这些嵌入式 SQL 语句中所有列名和变量的引用,而不是仅仅依靠命名约定来避免标识符之间的"冲突"。 那么,随着底层表的发展,您的代码将来出现异常行为的可能性就会大大降低。

Visibility

变量另一个重要的属性是它的可见性,即是否可以仅使用其名称来引用它,或者是否需要在其前面附加范围前缀。

Visible identifiers

可见标识符实际上可能引用以下任何内容:

  • 当前块中声明的标识符
  • 在包含当前块的块中声明的标识符
  • 您拥有的独立数据库对象(表、视图、序列等)或 PL/SQL 对象(过程、函数、类型)
  • 您拥有适当权限的独立数据库对象或 PL/SQL 对象,并且是您可以看到的 Oracle 同义词的目标
  • 循环索引变量(仅在循环体内可见且在范围内)

PL/SQL 还允许引用不直接可见的范围内项目,如下一节所述。

Qualified identifiers

不可见标识符的一个常见示例是包规范中声明的任何内容,例如变量、数据类型、过程或函数。 要引用该包外部的这些元素之一,您只需在其前面添加一个点限定符,类似于使用表名称限定列名的方式。

例如:

  • package .program
  • package .constant
  • schema .package .program
Qualifying identifier names with module names

必要时,PL/SQL 提供了许多方法来限定标识符,以便可以解析对该标识符的引用。 例如,使用包,您可以创建具有全局范围的变量。然后,我可以在包外部引用该变量,只要在标识符名称前面加上包名称即可。

默认情况下,分配给这些包级变量之一的值在当前数据库会话期间持续存在,直到会话断开。

除非显示指定,对变量的解析都是从内到外的。

SQL 的名称解析首先匹配列名称,而不是 PL/SQL 标识符。

Nested programs

PL/SQL 还提供了一个特别重要的功能,称为嵌套程序。 嵌套程序是完全出现在封闭块的声明部分内的过程或函数。 值得注意的是,嵌套程序可以引用先前在外部块中声明的任何变量和参数。

嵌套程序可以使您的程序更具可读性和可维护性,并且还允许您重用出现在块中多个位置的逻辑。 更多信息,请参阅第 17 章。

The PL/SQL Character Set

PL/SQL 程序由一系列语句组成,每个语句由一行或多行文本组成。 您可用的精确字符取决于您使用的数据库字符集。

PL/SQL 是一种不区分大小写的语言。 大写字母的处理方式与小写字母相同,除非被分隔符包围,使它们成为文字字符串。 按照惯例,本书作者更喜欢使用大写字母表示内置语言关键字,使用小写字母表示程序员定义的标识符。

注意以下5个字符:

sql 复制代码
& { } [ ]

虽然文字字符串中允许使用所有字符,但 Oracle 似乎并未在 PL/SQL 可见部分的任何地方使用这五个特定字符。 此外,没有直接的方法可以在程序员定义的标识符中使用这些字符。

其中许多字符(无论是单独的还是与其他字符组合)在 PL/SQL 中都具有特殊的意义。 下表列出了这些特殊符号。

符号 描述
; 分号:终止声明和语句
% 百分号:属性指示符(游标属性如%ISOPEN和间接声明属性如%ROWTYPE); 也用作 LIKE 条件的通配符
_ 单下划线:LIKE条件下的单字符通配符
@ At标志:远程定位指示器
: 冒号:主机变量指示符,例如 Oracle Forms 中的 :block.item
< > 或 != 或 ^= or ~= 不等于
|| 双竖线:连接运算符
<< 和>> 标签分隔符
<= 和 >= 小于或等于和大于或等于关系运算符
:= 赋值运算符
=> 位置符号的关联运算符
... 双点:范围运算符
/* 和 */ 开始和结束多行注释块分隔符

字符被组合成词汇单元,也称为语言的原子,因为它们是最小的单个组件。 PL/SQL 中的词法单元是以下任意一种:

  • 标识符
  • 文字
  • 分隔符
  • 注释

Identifiers

标识符是 PL/SQL 对象的名称,包括以下任意内容:

  • 常数或变量
  • 例外
  • 游标
  • 程序名称:过程、函数、包、对象类型、触发器等。
  • 保留字
  • 标签

PL/SQL 标识符的默认属性总结如下:

  • 长度最多 30 个字符
  • 必须以字母开头
  • 可以包含 $(美元符号)、_(下划线)和 #(井号)
  • 不能包含任何"空白"字符
  • 不区分大小写

标识符是程序中对象的句柄,也是与其他程序员通信的主要方式之一。 因此,许多组织采用命名约定。 即使没有命名约定的要求,您仍然需要仔细选择变量名称...即使您是唯一会看到代码的人!

尽管在实践中很少这样做,但实际上您可以通过用双引号将标识符括起来来打破其中一些规则(不推荐)。

您可能需要在 SQL 语句中使用双引号技巧来引用大小写混合名称存在的数据库对象。 当程序员使用 Microsoft Access 创建 Oracle 表时,我就见过这种情况。

Reserved Words

PL/SQL 提供两种内置标识符:

  • 保留字(如BEGIN,END)
  • STANDARD 包中的标识符

在这两种情况下,您不应该(而且在许多情况下不能)重新定义标识符以供程序自己使用。

Reserved words

PL/SQL 编译器保留某些标识符仅供其使用。 换句话说,您不能使用该标识符的名称来声明变量。 这些称为保留字。 例如,你不能声明一个名为 end 的变量。

Identifiers from STANDARD package

除了避免使用与关键字重复的标识符之外,还应该避免使用实际上覆盖 Oracle 公司在名为 STANDARD 的特殊内置包中定义的名称的标识符。 STANDARD 是 PL/SQL 中的两个默认包之一; Oracle 在这个包中定义了 PL/SQL 语言的许多基本构建块,包括 PLS_INTEGER 等数据类型、DUP_VAL_ON_INDEX 等异常以及 UPPER、REPLACE 和 TO_DATE 等函数。

STANDARD(以及 DBMS_STANDARD,另一个默认包)中定义的标识符不是保留字。 您可以使用相同的名称声明自己的变量,并且您的代码将编译。 然而,如果你这样做,将会造成很多混乱。

STANDARD 包将在第 24 章中详细探讨。

How to avoid using reserved words

为您的标识符找到有效的名称应该是最不重要的问题,因为合法字符有成千上万的排列。 问题是:如何知道自己的程序中是否无意中使用了保留字? 首先,如果您尝试使用实际保留的标识符的名称,编译器会通知您。 如果您的好奇心迫使您进一步研究,您可以针对 V$RESERVED_WORDS 视图构建一个查询,然后尝试编译一个使用保留字作为标识符的动态构造的 PL/SQL 块。 我正是这么做的; 您可以在本书网站上的reserved_words.sql 文件中找到该脚本。 运行此脚本的输出位于reserved.txt 中。

sql 复制代码
-- 以下是19c的结果,和作者12c的结果是一致的
Reserved Word Analysis Summary
Total count in V$RESERVED_WORDS = 1733
Total number of reserved words = 118
Total number of non-reserved words = 1615

Reserved Words in PL/SQL - Cannot Use as Identifiers
}
RETURN
CLOSE
START
MOD
...

一般来说,我建议您避免使用 Oracle 公司用作其自身技术一部分的任何词语。 更好的是,使用采用一致前缀和后缀的命名约定,实际上保证您不会遇到真正的 PL/SQL 保留字。

Whitespace and Keywords

标识符必须至少用一个空格或定界符分隔,但您可以在可以放置空格的地方添加额外的空格、换行符(换行符和/或回车符)和制表符来格式化文本,而不改变你代码的含义。

但是,您不能在词汇单元内放置空格、回车符或制表符,例如"不等于"符号 (!=)不能写成! =

Literals

文字是不由标识符表示的值; 它只是一个值。 以下是您可以在 PL/SQL 程序中看到的一些文字:

  • 数字。如123.45f(32位浮点数), 7D(64位浮点数)
  • 字符串。如'Hello, World',q'!hello!'
  • 时间间隔。如INTERVAL '25-6' YEAR TO MONTH, INTERVAL '-18' MONTH, NULL
  • 布尔值。如TRUE,FALSE,NULL

字符串 q'!hello!'中, ! 是用户定义的分隔符,在 Oracle 数据库 10g 中引入; 前导的q 和两端的单引号告诉编译器 ! 是分隔符,而字符串就是单词 hello。

INTERVAL 数据类型允许您管理日期或时间戳之间的时间量。

与标识符不同,PL/SQL 中的字符串文字区分大小写。因此'Steven'和'steven'不相等。

NULLs

在 Oracle 数据库中,值的缺失由关键字 NULL 表示。 如上一节所示,几乎所有 PL/SQL 数据类型的变量都可以以 null 状态存在(此规则的例外是任何关联数组类型,其实例永远不会为 null)。 正确处理 NULL 变量对于程序员来说都是一个挑战,而且NULL字符串需要特殊考虑。

在 Oracle SQL 和 PL/SQL 中,空字符串通常与零字符的文字无法区分,字面上表示为''(两个连续的单引号,中间没有字符)。 例如,以下表达式在 SQL 和 PL/SQL 中都将求值为 TRUE:

sql 复制代码
'' IS NULL

在 PL/SQL 中将零长度字符串分配给 VARCHAR2(n) 变量也会产生 NULL 结果:

sql 复制代码
DECLARE
   str VARCHAR2(1) := '';
BEGIN
   IF str IS NULL   -- will be TRUE

此行为与数据库对 VARCHAR2 表列的处理一致。

不过,让我们看看 CHAR 数据------它有点奇怪。 如果您在 PL/SQL 中创建 CHAR(n) 变量并为其分配零长度字符串,则数据库会用空格字符填充空变量,使其不为空:

sql 复制代码
DECLARE
   flag CHAR(2) := '';  -- try to assign zero-length string to CHAR(2)
BEGIN
   IF flag = '  '   ...   -- will be TRUE
   IF flag IS NULL  ...   -- will be FALSE

奇怪的是,PL/SQL 是您会看到这种行为的唯一地方。 在数据库中,当您将零长度字符串插入到 CHAR(n) 表列中时,数据库不会将该列的内容填充为空白,而是将其保留为 NULL!

sql 复制代码
SQL> create table t1(a varchar2(16));

Table created.

SQL> insert into t1 values ('');

1 row created.

SQL> select count(*) from t1 where a is null;

  COUNT(*)
----------
         1

SQL> insert into t1 values ("");
ERROR:
ORA-01741: illegal zero-length identifier

这些示例说明 Oracle 部分遵守 ANSI SQL 标准 92 和 99 版本,该标准强制要求零长度字符串和 NULL 字符串之间存在差异。 Oracle承认这种差异,并表示将来可能会完全采用该标准。 不过,该警告已经发出了大约 15 年,但目前还没有发生。

虽然 NULL 的行为就像其默认数据类型是 VARCHAR2,但数据库将尝试将 NULL 隐式转换为当前操作所需的任何类型。 有时,您可能需要使用 TO_NUMBER(NULL) 或 CAST(NULL AS NUMBER) 等语法进行显式转换。

Embedding Single Quotes Inside a Literal String

较麻烦的是,当您需要将分隔符本身放入字符串中时。 在 Oracle 数据库 10g 发布之前,如果您希望字符串中包含单引号,则可以在彼此旁边写入两个单引号。 下表提供了一些示例。

|文字(默认分隔符)|实际值|

|'There''s no business like show business.'|'There's no business like show business.'|

|'"Hound of the Baskervilles"'|Hound of the Baskervilles'|

|''''|'|

|'''hello'''|'hello'|

|''''''|''|

为了简化这种类型的构造,Oracle 数据库 10g 引入了用户定义的分隔符。 以"q"开头的文字来标记分隔符,并用单引号将分隔表达式括起来。

文字(突出显示分隔符) 实际值
q' ( There's no business like show business.) ' There's no business like show business.'
q' { "Hound of the Baskervilles" } ' "Hound of the Baskervilles"
q' [ ' ] ' '
q' !'hello' ! ' 'hello'

还有,q'|''|'相当于''

如示例所示,您可以使用普通分隔符,例如 ! 或|,或者您可以使用**"配对"**分隔符,例如左括号、右括号、花括号和方括号。

最后一点:正如您所期望的,双引号字符在字符串文字中没有任何特殊意义。 它被视为与字母或数字相同。

Numeric Literals

数字文字可以是整数或实数(包含小数部分的数字)。 请注意,PL/SQL 认为数字 154.00 是 NUMBER 类型的实数,即使小数部分为零并且该数字实际上是整数。 在内部,整数和实数具有不同的表示形式,并且两者之间的转换有小的开销。

您还可以使用科学记数法来指定数字文字。 使用字母 E(大写或小写)将数字乘以 10 的 n 次方(例如 3.05E19、12e--5)。

从 Oracle Database 10g 开始,实数可以是 Oracle NUMBER 类型或 IEEE 754 标准浮点类型。 浮点文字可以是 BINARY(32 位;用尾随 F 指定)或 BINARY DOUBLE(64 位;用 D 指定)。

在某些表达式中,您可以按照 IEEE 标准的规定使用下表中的命名常量。

描述 二进制浮点数(32 位) 二进制双精度(64 位)
"不是数字"(NaN); 除以 0 或无效运算的结果 BINARY_FLOAT_NAN BINARY_DOUBLE_NAN
正无穷大 BINARY_FLOAT_INFINITY BINARY_DOUBLE_INFINITY
可表示的绝对最大数 BINARY_FLOAT_MAX_NORMAL BINARY_DOUBLE_MAX_NORMAL
最小正常数; 下溢阈值 BINARY_FLOAT_MIN_NORMAL BINARY_DOUBLE_MIN_NORMAL
小于下溢阈值的最大正数 BINARY_FLOAT_MAX_SUBNORMAL BINARY_DOUBLE_MAX_SUBNORMAL
可表示的绝对最小正数 BINARY_FLOAT_MIN_SUBNORMAL BINARY_DOUBLE_MIN_SUBNORMAL

Boolean Literals

PL/SQL 提供了两种文字来表示布尔值:TRUE 和 FALSE。 这些值不是字符串; 你不应该在它们周围加上引号。

另一方面,在检查布尔表达式的值时不需要引用文字值。 相反,只需让该表达式不言而喻,如以下 IF 语句的条件子句所示:

sql 复制代码
DECLARE
   enough_money BOOLEAN;
BEGIN
   IF enough_money
   THEN
      ...

布尔表达式、变量或常量也可能计算为 NULL,它既不是 TRUE 也不是 FALSE。 有关详细信息,请参阅第 4 章。

The Semicolon Delimiter

PL/SQL 程序由一系列声明和语句组成。 这些是逻辑上定义的,而不是物理上的。 换句话说,它们并不是以代码行的物理结尾结束;而是以分号 (😉 结尾。 事实上,一条语句通常分布在多行中以使其更具可读性。

仍然需要分号来终止每个逻辑可执行语句,即使它们相互嵌套。 除非您试图创建不可读的代码,否则我建议您不要将 IF 语句的不同组成部分组合在一行上。 我还建议您在每一行上放置不超过一个声明或声明。

Comments

内联文档(也称为注释)是优秀程序的重要元素。 虽然本书提供了许多关于如何通过良好的命名实践和模块化使程序自我记录的建议,但这些技术本身很少足以传达对复杂程序的透彻理解。

PL/SQL 提供两种不同的注释样式:单行注释和多行块注释。

Single-Line Comment Syntax

单行注释以两个连字符 (--) 开头,不能用空格或任何其他字符分隔。 双连字符之后到物理行末尾的所有文本都被视为注释,会被编译器忽略。 如果双连字符出现在行的开头,则整行都是注释。

Multiline Comment Syntax

虽然单行注释对于记录简短的代码或忽略当前不希望执行的行很有用,但多行注释更适合包含较长的注释块。

多行注释以斜杠星号 (/) 开头,以星号斜杠 (/) 结束。 PL/SQL 将这两个符号序列之间找到的所有字符视为注释的一部分,并且编译器会忽略它们。

以下多行注释示例显示了过程的标题部分。 我在左边距中使用垂直条,这样当眼睛向下移动到程序的左边缘时,它可以轻松地挑选出注释块:

sql 复制代码
PROCEDURE calc_revenue (company_id IN NUMBER) IS
/*
| Program: calc_revenue
| Author: Steven Feuerstein
| Change history:
|   10-JUN-2009 Incorporate new formulas
|   23-SEP-2008 - Program created
|*/
BEGIN
   ...
END;

您还可以使用多行注释来屏蔽代码行以进行测试。

The PRAGMA Keyword

真正源自希腊语的编程概念是 pragma,它的意思是"行为",或者隐含地是"动作"。 在各种编程语言中,编译指示通常是一行源代码,规定您希望编译器执行的操作。 这就像你给编译器的一个选项; 它可能会导致程序不同的运行时行为,但它不会直接转换为字节码。

PL/SQL 有一个 PRAGMA 关键字,其语法如下:

sql 复制代码
PRAGMA instruction_to_compiler;

PL/SQL 编译器将在声明部分的任何位置接受此类指令,但大多数指令对于放置都有某些附加要求。

PL/SQL 提供了多种编译指示:

  • AUTONOMOUS_TRANSACTION

    告诉 PL/SQL 运行时引擎提交或回滚当前块内对数据库所做的任何更改,而不影响主事务或外部事务。 更多信息请参见第 14 章。

  • EXCEPTION_INIT

    告诉编译器将特定的错误号与您在程序中声明为异常的标识符相关联。 必须遵循异常声明。 有关详细信息,请参阅第 6 章。

  • RESTRICT_REFERENCES

    告诉编译器打包程序的纯度级别(无副作用)。 更多信息请参见第 17 章。

  • SERIALLY_REUSABLE

    告诉 PL/SQL 运行时引擎包级数据不应在对该数据的引用之间保留。 更多信息请参见第 18 章。

以下块演示了如何使用 EXCEPTION_INIT 编译指示来命名内置异常,否则该异常只有一个数字:

sql 复制代码
DECLARE
   no_such_sequence EXCEPTION;
   PRAGMA EXCEPTION_INIT (no_such_sequence, −2289);
BEGIN
   ...
EXCEPTION
   WHEN no_such_sequence
   THEN
      q$error_manager.raise_error ('Sequence not defined');
END;

Labels

PL/SQL 标签是一种命名程序特定部分的方法。 从语法上来说,标签的格式如下:

sql 复制代码
<<identifier>>

这里identifier是一个有效的标识符,这里没有终止符。 标签直接出现在它们所标记的事物的前面,该事物必须是可执行语句 - 即使它只是 NULL 语句:

sql 复制代码
BEGIN
   ...
   <<the_spot>>
   NULL;

因为匿名块本身就是可执行语句,所以标签可以在匿名块执行期间"命名"它。

为块添加标签的原因之一是提高代码的可读性。 当您给某些东西命名时,您就可以自行记录该代码。 您还澄清了自己对该代码应该做什么的想法,有时会找出过程中的错误。

使用块标签的另一个原因是允许您限定对封闭块中在当前嵌套块中具有重复名称的元素的引用。 当然,应尽量避免重名。

标签的第三个功能是充当 GOTO 语句的目标。 参见第 4 章中对 GOTO 的讨论。

尽管我见过或参与过的程序很少需要使用标签,但此功能的最后一个用途比前三个组合更重要:标签可以用作嵌套循环中 EXIT 语句的目标。

sql 复制代码
BEGIN
   <<outer_loop>>
   LOOP
      LOOP
         EXIT outer_loop;
      END LOOP;
      some_statement;
   END LOOP;
END;

生词

  • indispensable 必不可少,必须
相关推荐
永乐春秋19 分钟前
WEB-通用漏洞&SQL注入&CTF&二次&堆叠&DNS带外
数据库·sql
王小小鸭1 小时前
【开发小技巧11】用经典报表实现badge list效果,根据回显内容用颜色加以区分
oracle·oracle apex
大白要努力!1 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
武子康4 小时前
大数据-230 离线数仓 - ODS层的构建 Hive处理 UDF 与 SerDe 处理 与 当前总结
java·大数据·数据仓库·hive·hadoop·sql·hdfs
Mephisto.java4 小时前
【大数据学习 | Spark】Spark的改变分区的算子
大数据·elasticsearch·oracle·spark·kafka·memcache
远歌已逝7 小时前
维护在线重做日志(二)
数据库·oracle
武子康12 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
爱上口袋的天空13 小时前
09 - Clickhouse的SQL操作
数据库·sql·clickhouse
Yang.9915 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
LKID体16 小时前
Python操作neo4j库py2neo使用(一)
python·oracle·neo4j