• KingbaseES PL/SQL 过程语言参考手册(3. PL/SQL语言基础)


    3. PL/SQL语言基础

    本章节阐述PL/SQL语言的基本组成。

    3.1. 字符集

    任何要由PL/SQL处理或存储在数据库中的字符数据都必须表示为字节序列。单个字符的字节表示形式称为字符码。一组字符码称为字符集。

    每个数据库都支持一个数据库字符集和一个国家字符集。PL/SQL也支持这些字符集。本章节解释了PL/SQL如何使用数据库字符集和国家字符集。

    3.1.1. 数据库字符集

    PL/SQL使用数据库字符集表示:

    • 存储PL/SQL单元的源文本;

    • 数据类型CHAR、VARCHAR2、CLOB和LONG的字符值;

    数据库字符集可以是单字节,将每个支持的字符映射到一个特定的字节,也可以是多字节,宽度不同,将每个支持的字符映射到一个由一个、两个、三个或四个字节组成的序列。字符码中的最大字节数取决于特定的字符集。

    每个数据库字符集都包含以下基本字符:

    • 拉丁字母:A到Z和a到z

    • 十进制数字:0到9

    • 标点符号

    • 空白字符:空格、制表符、换行符和回车符

    仅使用基本字符的PL/SQL源文本可以在任何数据库中存储和编译。使用非基本字符的PL/SQL源文本只能在数据库字符集支持这些非基本字符的数据库中存储和编译。

    表 3.1.38 每个数据库字符集中的标点字符

    标点

    名称

    (

    左括号

    )

    右括号

    <

    小于号

    >

    大于号

    加号

    减号

    乘号

    /

    除号

    =

    等于

    ,

    逗号

    ;

    分号

    :

    冒号

    .

    句号

    !

    叹号

    ?

    问号

    单引号

    双引号

    @

    艾特符号

    %

    百分号

    #

    井号

    $

    美元符号

    _

    下划线

    竖线

    3.1.2. 国际字符集

    PL/SQL使用国际字符集来表示数据类型NCHAR、NVARCHAR和NCLOB的字符值。

    3.1.3. 关于字符排序

    排序规则是用于确定在比较和排序两个字符串时的一组规则,例如一个字符串是等于另一个字符串、在另一个字符串之前还是在另一个字符串之后。

    不同的排序对应不同语言的规则。排序规则敏感操作是比较文本并需要排序规则来控制比较规则的操作。

    KingbaseES数据库的PL/SQL的字符排序默认与SQL的字符排序规则一致。

    3.2. 词法单元

    PL/SQL的词法单位是其最小的单个组件,包括:

    • 分隔符

    • 标识符

    • 常量

    • 编译指示

    • 注释

    • 词法单元之间的空白字符

    3.2.1. 分隔符

    分隔符用于标记词法元素之间的分割,可以是一个字符,也可以是由多个字符组合组成的,都有特殊的意义。不要在分隔符中嵌入任何其他字符(包括空格字符)。

    表 3.2.30 PLSQL分隔符

    分隔符

    含义

    加法运算符

    :=

    赋值运算符

    %

    属性标识

    '

    字符串分隔符

    .

    对象标识

    丨丨

    连接运算符

    /

    除法运算符

    (

    表达式或列表分隔符(开始)

    )

    表达式或列表分隔符(结束)

    ,

    项目分隔符

    <<

    标签分隔符(开始)

    >>

    标签分隔符(结束)

    /*

    多行注释分隔符(开始)

    */

    多行注释分隔符(结束)

    乘法运算符

    "

    带引号的标识符分隔符

    ..

    范围运算符

    =

    关系运算符(相等)

    <>

    关系运算符(不相等)

    !=

    关系运算符(不相等)

    ~=

    关系运算符(不相等)

    ^=

    关系运算符(不相等)

    <

    关系运算符(小于)

    >

    关系运算符(大于)

    <=

    关系运算符(小于或等于)

    >=

    关系运算符(大于或等于)

    --

    单行注释指示符

    ;

    语句终止符

    减法运算符

    ~

    求反运算符

    3.2.2. 标识符

    标识符用于命名PL/SQL语法单元,包括:

    • 常量

    • 游标

    • 异常

    • 关键字

    • 标签

    • 保留字

    • 子程序

    • 类型

    • 变量

    标识符中的每个字符都是有意义的,例如lastname和last_name是不同的。

    必须通过一个或多个空白或者一个标点符号来分隔相邻的标识符。

    标识符的大小写是不敏感的。例如lastname、Lastname、LASTNAME是相同的。

    3.2.2.1. 保留字和关键字

    PL/SQL中有一些具有特殊意义的标识符,被称作保留字和关键字。

    不能使用保留字做为用户定义的标识符。

    可以用关键字作为用户定义的标识符,但不建议这样做。

    3.2.2.2. 预定义标识符

    预定义标识符在预定义的包STANDARD中声明。

    您可以使用预定义的标识符作为用户定义的标识符,但不建议这样做。

    3.2.2.3. 用户自定义标识符

    一个用户自定义标识符:

    • 由数据库字符集中的字符组成

    • 一般用户自定义标识符或带引号的用户自定义标识符

    3.2.2.3.1. 普通自定义用户标识符

    普通用户定义标识符:

    • 字母开头

    • 可以包括字母、数字和以下符号:

    • 美元符号($)

    • 数字符号(#)

    • 下划线(_)

    • 不是保留字

    数据库字符集定义了哪些字符被分类为字母和数字。 例如以下是可接受的标识符:

    X
    
    t2
    
    credit_limit
    
    LastName
    
    kes$number
    
    money$$$tree
    
    try_again_
    

    PL/SQL不容许在标识符中使用分隔符,如下所示:

    mine&yours -- 不允许使用符号(&)
    
    debit-amount -- 不允许使用连字符(-)
    
    on/off -- 不允许使用斜杠(/)
    
    user id -- 空格是不允许的
    

    3.2.2.3.2. 带引号的用户自定义标识符

    引用用户定义标识符用双引号括起来。

    在双引号之间,除双引号、换行符和空字符外,允许使用数据库字符集中的任何字符。例如,这些标识符是可以接受的:

    "X+Y"
    
    "last name"
    
    "on/off switch"
    
    "employee(s)"
    
    "*** header info ***"
    

    KingbaseES数据库PL/SQL中带引号的用户定义标识符任何情况下都不区分大小写:

    • 如果带引号的用户定义标识符(不包含双引号)是有效的普通用户自定义标识符,则双引号在引用该标识符时是可选的。

    • 可以使用保留字作为引用的用户定义标识符,但不建议这样做。因为保留字不是有效的普通用户自定义标识符,所以必须始终将标识符用双引号括起来。

    示例 3-1 对带引号的用户自定义标识符的不区分大小写的有效引用

    在本例中,带引号的用户自定义标识符 “HELLO”在没有双引号的情况下是一个有效的一般用户自定义标识符。因此,Hello的引用用法是有效的。

    \set SQLTERM /
    DECLARE
       "HEI" varchar2(10) := 'hei';
    BEGIN
       RAISE NOTICE '%',HEI;
    END;
    /
    

    结果:

    NOTICE:  hei
    

    示例 3-2 对带引号的用户自定义标识符的不区分大小写的有效引用

    在本例中,引用“Hello”有效,因为KingbaseES下的PL/SQL标识符不区分大小写。

    \set SQLTERM /
    DECLARE
       "HEI" varchar2(10) := 'hei';
    BEGIN
       RAISE NOTICE '%',hei;
    END;
    /
    

    结果:

    NOTICE:  hei
    

    示例 3-3保留字作为引用的用户定义标识符

    本例中第一个示例将保留字BEGIN加双引号后”BEGIN”,可以作为用户定义的标识符使用,引用该标识符时,不区分大小写;第二个示例定义了”BEGIN”和”Begin”两个变量,但因为不区分大小写,所以认为是同一个变量,运行结果提示报错。

    \set SQLTERM /
    DECLARE
       "END" varchar2(15) := 'UPPERCASE';
    BEGIN
       DBMS_Output.Put_Line("END");
       DBMS_Output.Put_Line("End");
       DBMS_Output.Put_Line("end");
    END;
    /
    

    结果:

    UPPERCASE
    UPPERCASE
    UPPERCASE
    
    \set SQLTERM /
    DECLARE
       "END" varchar2(15) := 'UPPERCASE';
       "End" varchar2(15) := 'Initial Capital';
    BEGIN
       DBMS_Output.Put_Line("END");
       DBMS_Output.Put_Line("End");
    END;
    /
    

    结果:

    ERROR:  duplicate declaration at or near ""End""
    LINE 3: "End" varchar2(15) := 'Initial Capital';
    

    示例 3-4 忽略双引号

    本例引用了一个带引号的用户定义标识符,该标识符是一个保留字,但忽略了将其括在双引号中。

    \set SQLTERM /
    DECLARE
       "HEI" varchar2(10) := 'hei'; -- HEI is not a reserved word
       "END" varchar2(10) := 'end'; -- END is a reserved word
    BEGIN
       DBMS_Output.Put_Line(Hei); -- Double quotation marks are optional
       DBMS_Output.Put_Line(END); -- Double quotation marks are required
    end;
    /
    

    结果:

    ERROR:  unexpected end of function definition at end of input
    LINE 6: DBMS_Output.Put_Line(END); -- Double quotation marks are req...
    

    3.2.3. 常数

    常数就是一个数字、字符、字符串、或布尔值。它本身是数据不是对数据的引用。常数也不是用标识符来标识,当然也不是计算出来的。例,123是整数常数,’abc’是字符常数,而1+2不是常数。

    PL/SQL常数包括所有SQL常数和布尔文本(SQL没有)。布尔常数是预定义的逻辑值TRUE、FALSE或NULL。NULL表示未知值。

    在PL/SQL中使用字符常数,需注意:

    • 字符常数是大小写敏感的。

    例如,’Z’和’z’是不同的。

    • 空白字符也是有意义的。

    例如,这些都是不同的:

    'abc'
    
    ' abc'
    
    'abc '
    
    ' abc '
    
    'a b c'
    
    • PL/SQL没有行连接字符,表示“此字符串与下一个源代码行上的字符串是同一个”。如果在下一行代码行存在字符串,则该字符串包含换行符。

    例如,以下PL/SQL代码:

    set serverout on
    \set SQLTERM /
    BEGIN
        DBMS_OUTPUT.PUT_LINE('Test string
    wrapping.');
    END;
    /
    

    结果:

    Test string
    wrapping.
    

    如果字符串一行内放不下,打印不希望包含换行符,则使用字符串连接运算符(||)构造字符串。

    例如,以下PL/SQL代码:

    set serverout on
    \set SQLTERM /
    BEGIN
          DBMS_OUTPUT.PUT_LINE('Test string ' ||
          'concatenation');
    END;
    /
    

    结果:

    test string concatenation.
    
    • ‘0’到’9’不等同于整数常数0到9。

    但是,由于PL/SQL将它们转换为整数,因此可以在算术表达式中使用它们。

    • 零字符的字符常数的值为NULL,称为NULL字符串。

    但是,此NULL值不是布尔值NULL。

    • 普通字符常数由数据库字符集中的字符组成。

    • 国家字符常数由国家字符集中的字符组成。

    3.2.4. 编译指令

    编译指令(pragma)是编译器在编译时处理的一条指令。

    一条编译指令以保留字PRAGMA开头,后跟编译指令的名称。有些编译指令有参数。编译指令可以出现在声明或语句之前。其他限制可能适用于特定编译指令。编译指令影响的程度取决于编译指令本身。编译器无法识别其名称或参数的编译指令无效。

    3.2.5. 注释

    PL/SQL编译器忽略注释。向程序添加注释可以增强可读性。通常,使用注释来描述每个代码段的用途,也可以将代码通过注释禁用。

    3.2.5.1. 单行注释

    单行注释开始于--,一直到行尾结束。

    • 对于函数、存储过程、程序包、触发器等sql语句定义中,“--”单行注释只保留AS到END间的。

    • 对于TYPE BODY语句定义中,“--”单行注释只保留语句内的函数、存储过程等的AS到END间的。

    测试或调试程序时,可以通过单行注释禁用一行代码,例如:

    -- DELETE FROM employees WHERE comm_pct IS NULL
    

    示例 3-5 单行注释

    这个例子有3处单行注释。

    \set SQLTERM /
    DECLARE
       num_func NUMBER;
       nums NUMBER;
    BEGIN
       -- Begin processing
       SELECT COUNT(*) INTO nums
       FROM PG_PROC
       WHERE PRONAME = 'f1'; -- Check number of function f1
       num_func := nums; -- Compute another value
    END;
    /
    

    3.2.5.2. 多行注释

    可以注释多行代码, /*注释内容*/。

    您可以使用多行注释分隔符“注释掉”代码部分。执行此操作时,请注意不要引起嵌套多行注释。一条多行注释不能包含另一条多行注释。但是,多行注释可以包含单行注释。

    例如,这会引发语法错误:

    /*
    IF 2 + 2 = 4 THEN
       some_condition := TRUE;
       /* We expect this THEN to always be performed */
    END IF;
    */
    

    以下不会引发语法错误:

    /*
    IF 1 THEN
       num1 := 1;
       /* We expect this THEN to always be performed */
    END IF;
    */
    

    示例 3-6 多行注释

    \set SQLTERM /
    DECLARE
       num1 number;
       num2 number;
    BEGIN
       /* Perform some simple tests and assignments */
       IF 1 THEN
          num1 := 1;
          /* test for multiline comments  */
       END IF;
       /* test for multiline comments 1
          test for multiline comments 2
          test for multiline comments 3*/
       num2 = 2;
       raise notice 'num1 = %,num2 = %', num1, num2;
    END;
    /
    

    结果:

    NOTICE:  num1 = 1,num2 = 2
    

    3.2.6. 词法单元之间的空白字符

    您可以在词法单元之间放置空白字符,这通常会使源代码文本更易于阅读。

    示例 3-7空白字符,提高代码可读性

    \set SQLTERM /
    DECLARE
       a NUMBER := 10;
       b NUMBER := 5;
       min NUMBER;
    BEGIN
       IF a 
    

    3.3. 声明

    声明为值分配存储空间,指定其数据类型,并命名存储位置,以便后续可以引用它。

    必须先声明对象,然后才能引用它们。声明可以出现在任何块、子程序或包的声明部分。

    3.3.1. NOT NULL约束

    可以对标量变量或常量(或复合变量或常量的标量分量)施加NOT NULL约束。

    NOT NULL约束阻止为元素分配空值。该元素可以隐式(从其数据类型)或显式获取该约束。

    隐式或显式指定NOT NULL的标变量声明必须为变量指定初始值(因为标量变量的默认初始值为NULL)。

    PL/SQL将任何长度为零的字符串视为NULL值。这包括由字符函数和布尔表达式返回的值。

    示例 3-8有NOT NULL约束的变量声明

    本例中变量name显式地获得NOT NULL约束,变量a,b,c则通过他们的数据类型获得NOT NULL约束。

    \set SQLTERM /
    DECLARE
       name text NOT NULL := 'test';
       a NATURALN := 9999;
       b POSITIVEN := 9999;
       c SIMPLE_INTEGER := 9999;
    BEGIN
       NULL;
    END;
    /
    

    示例 3-9初始化为NULL值的变量

    本例中所有变量初始化为NULL。

    \set SQLTERM /
    DECLARE
       null_value text := TO_CHAR('');
       name text;
       invalid BOOLEAN := (name != '');
    BEGIN
       NULL;
    END;
    /
    

    3.3.2. 声明变量

    变量声明需要指定变量名称和数据类型。对于大多数据类型,声明变量也可以指定初始值。变量名称必须是有效的用户定义标识符。数据类型可以是任何PL/SQL数据类型。

    PL/SQL数据类型包括SQL数据类型。数据类型可以是标量(不含内部组件),也可以是复合的(含内部组件)。

    示例 3-10标量变量声明

    本例使用标量数据类型声明了几个变量。

    \set SQLTERM /
    DECLARE
       num NUMBER(6); -- SQL data type
       name VARCHAR2(20); -- SQL data type
       have_error BOOLEAN; -- PL/SQL-only data type
       price NUMBER(6,2); -- SQL data type
       description text; -- SQL data type
    BEGIN
       NULL;
    END;
    /
    

    3.3.3. 声明常量

    常数保持不变的值。声明变量中的相关信息也适用于声明常量,但是声明常量时,有两个必要条件:关键字CONSTANT和常量的初始化值(常数的初始值是它的永久值)。

    示例 3-11声明常量

    本例中用标量数据类型声明了3个常量。

    \set SQLTERM /
    DECLARE
       limit CONSTANT REAL := 5000.00; -- SQL data type
       seconds_of_minute CONSTANT INTEGER := 60; -- SQL data type
       have_error CONSTANT BOOLEAN := FALSE; -- PL/SQL-only data type
    BEGIN
       NULL;
    END;
    /
    

    3.3.4. 常量和变量的初始化

    在变量的声明中初始化是可选的。除非指定NOT NULL,则变量的初始化赋值是必须的。

    如果声明位于块或子程序中,则每次控制传递到块或子程序时,都会将初始值指定给变量或常量。

    如果声明在包规范中,则初始值将赋给每个会话的变量或常量(无论变量或常量是公共的还是私有的)。

    为了指定初始化值,使用操作符:=或关键字DEFAULT进行初始化,后跟表达式。表达式可以包含前面已经声明的常量或已经初始化的变量。如果没有为变量指定初始值,请在将其用于任何其他上下文之前为其赋值。

    示例 3-12带有初始值的变量和常量声明

    本例将初始值分配给它声明的常量和变量。minutes_of_day取决于minutes_of_hour和hours_of_day的乘积。

    \set SQLTERM /
    DECLARE
       hours_of_day INTEGER := 24;
       minutes_of_hour INTEGER := 60;
       minutes_of_day INTERGER := minutes_of_hour * hours_of_day;
    BEGIN
       NULL;
    END;
    /
    

    示例 3-13默认情况下变量初始化为NULL

    在本例中,默认情况下变量num的初始值为NULL。该示例使用“IS[NOT]NULL运算符”来显示NULL与0值不同。

    \set SQLTERM /
    DECLARE
       num INTEGER; -- initial value is NULL by default
    BEGIN
       num := num + 1; -- NULL + 1 is still NULL
       IF num IS NULL THEN
          raise notice 'num is NULL.';
       END IF;
    END;
    /
    

    结果:

    NOTICE:  num is NULL.
    

    3.3.5. 使用%TYPE属性声明

    通过%TYPE属性,可以声明与之前声明的变量或列具有相同数据类型的数据项(而不需要知道该类型具体是什么)。如果被引用项的声明更改,则引用项的声明也会相应更改。 此种声明的语法如下:

    referencing_item referenced_item%TYPE;
    

    引用项从被引用项继承数据类型和大小。被引用项的约束条件不被继承。

    当声明变量来抓取数据库数值时,%TYPE属性特别有用。声明与列类型相同的变量的语法如下:

    variable_name table_name.column_name%TYPE;
    

    示例 3-14声明与列类型相同的变量

    在本例中,变量surname继承列student.name的数据类型和大小,列student.name具有NOT NULL非空约束。因为stuname不继承NOTNULL约束,所以它的声明不需要初始值。

    CREATE TABLE student(id int PRIMARY KEY, name text NOT NULL, score number);
    insert into student values (1, 'xx', 99);
    \set SQLTERM /
    DECLARE
       stuname student.name%TYPE;
    BEGIN
       RAISE NOTICE 'stuname = %',stuname;
    END;
    /
    

    结果:

    NOTICE:  stuname = 
    

    示例 3-15声明与另一个变量类型相同的变量

    在本例中,变量surname继承变量name的数据类型、大小。因为surname不继承name的约束条件,所以它的声明可指定初始值也可以不指定。

    \set SQLTERM /
    DECLARE
       name VARCHAR(25) NOT NULL := 'Smith';
       surname name%TYPE := 'Jones';
    BEGIN
       DBMS_OUTPUT.PUT_LINE('name=' || name);
       DBMS_OUTPUT.PUT_LINE('surname=' || surname);
    END;
    /
    结果:
    name=Smith
    surname=Jones
    

    3.4. 对标识符的引用

    引用标识符时,使用的名称可以是简单的、限定的、远程的,也可以是限定的和远程的。

    标识符的简单名称是其声明中的名称。

    例如:

    \set SQLTERM /
    DECLARE
       b INTEGER; -- Declaration
    BEGIN
       b := 1; -- Reference with simple name
    END;
    /
    

    如果在已经命名的PL/SQL单元里声明了标识符,则可以(有时必须)使用限定名来引用他。使用方法如下:

    unit_name.simple_identifier_name
    

    例如,如果包p声明标识符a,则可以使用限定名称p.a引用标识符。单元名称也可以(有时必须)限定。当标识符不可见时,必须对其进行限定。

    3.5. 标识符的作用域和可见性

    标识符的作用域是PL/SQL单元中可以引用标识符的区域。标识符的可见性是PL/SQL单元中可以引用标识符而无需对其进行限定的区域。标识符是声明它的PL/SQL单元的本地标识符。如果该单元有子单元,那么标识符对它们来说是全局的。

    如果子单元重新声明了一个全局标识符,那么在子单元内部,两个标识符都在作用域内,但只有本地标识符可见。要引用全局标识符,子单元必须使用声明它的单元的名称来限定它。如果该单元没有名称,则子单元无法引用全局标识符。

    PL/SQL单元不能引用在同一级别的其他单元中声明的标识符,因为这些标识符对于程序块来说既不是局部的,也不是全局的。

    不能在同一PL/SQL单元中两次声明同一标识符。如果这样做,则在引用重复标识符时会发生错误。

    可以用两个不同的PL/SQL单元声明相同的标识符。标识符表示的两个对象是不同的。改变一个不会影响另一个。

    在同一作用域内,为标签和子程序指定唯一的名称,以避免混淆和意外结果。

    示例 3-16标识符的作用域和可见性

    本例显示了几个标识符的作用域和可见性。第一个子块重新声明全局标识符a。要引用全局变量a,第一个子块必须使用外部块的名称对其进行限定,但外部块没有名称。因此,第一子块不能引用全局变量a;它只能引用其局部变量a。由于子块处于同一级别,第一个子块不能引用d,第二个子块不能引用c。

    \set SQLTERM /
    -- Outer block:
    DECLARE
       a TEXT; -- Scope of a (CHAR) begins
       b INT; -- Scope of b begins
    BEGIN
       -- Visible: a (CHAR), b
       -- First sub-block:
       DECLARE
          a INT; -- Scope of a (INTEGER) begins
          c NUMBER; -- Scope of c begins
       BEGIN
          -- Visible: a (INTEGER), b, c
          NULL;
       END; -- Scopes of a (INTEGER) and c end
       -- Second sub-block:
       DECLARE
          d VARCHAR; -- Scope of d begins
       BEGIN
          -- Visible: a (CHAR), b, d
          NULL;
       END; -- Scope of d ends
       -- Visible: a (CHAR), b
    END; -- Scopes of a (CHAR) and b end
    /
    

    示例 3-17使用块标签限定重新声明的全局标识符

    此示例使用名称lable1标记块。因此,在子块重新声明全局变量num后,它可以通过使用块标签限定其名称来引用该全局变量。子块还可以通过其简单名称引用其局部变量num。

    \set SQLTERM /
    BEGIN
       <> -- label
       DECLARE
            num number := 1.1;
       BEGIN
          DECLARE
             num number := 1.2;
          BEGIN
             raise notice 'num = %', num;
             raise notice 'lable1.num = %', lable1.num;
          END;
       END;
    END;
    /
    

    结果:

    NOTICE:  num = 1.2
    NOTICE:  lable1.num = 1.1
    

    示例 3-18用子程序名限定标识符

    在本例中,check_credit过程声明了一个变量,rating和一个函数check_rating。函数内部又重新声明变量rating。然后函数通过使用过程名限定来引用全局变量rating。

    \set SQLTERM /
    CREATE OR REPLACE PROCEDURE extenal_pro (num_max NUMBER) AS
       num NUMBER := 3;
       FUNCTION sub_pro RETURN BOOLEAN IS
          num NUMBER := 1;
          over_limit BOOLEAN;
       BEGIN
          IF extenal_pro.num <= num_max THEN -- reference global variable
             over_limit := FALSE;
          ELSE
             over_limit := TRUE;
             num := num_max; -- reference local variable
          END IF;
          RETURN over_limit;
       END sub_pro;
    BEGIN
       IF sub_pro THEN
          raise notice 'over_limit';
       ELSE
          raise notice 'not over_limit';
       END IF;
    END;
    /
    \set SQLTERM /
    BEGIN
       extenal_pro(1);
    END;
    /
    

    结果:

    NOTICE:  over_limit
    

    示例 3-19同一作用域内的重复声明的标识符

    不能在同一PL/SQL单元中两次声明同一标识符。如果这样做,则在引用重复标识符时会发生错误,如本例所示。

    \set SQLTERM /
    DECLARE
       num number;
       num int; -- duplicate identifier
    BEGIN
       num := 1;
    END;
    /
    

    结果:

    ERROR:  duplicate declaration at or near "num"
    LINE 3: num int; -- duplicate identifier
    

    示例 3-20在不同的单元中声明相同的标识符

    可以在两个不同的PL/SQL单元内声明相同的标识符。标识符表示的两个对象是不同的。如本例所示,更改一个不会影响另一个。在同一作用域内,为标签和子程序指定唯一的名称,以避免混淆和意外结果。

    \set SQLTERM /
    DECLARE
       PROCEDURE a
       IS
          x VARCHAR2(1);
       BEGIN
          x := 'a'; -- Assign the value 'a' to x
          RAISE NOTICE 'procedure p, x = %', x;
       END;
       PROCEDURE b
       IS
          x VARCHAR2(1);
       BEGIN
          x := 'b'; -- Assign the value 'b' to x
          RAISE NOTICE 'procedure p, x = %', x;
       END;
    BEGIN
       a;
       b;
    END;
    /
    

    结果:

    NOTICE:  procedure p, x = a
    NOTICE:  procedure p, x = b
    

    示例 3-21同一作用域内具有相同名称的标签和子程序

    在本例中,block是块和子程序的名称。块和子程序都声明了一个名为a的变量。在子程序中,block.a指的是局部变量a,而不是全局变量a。

    \set SQLTERM /
    BEGIN
       <>
       DECLARE
          a NUMBER := 5;
          PROCEDURE block AS
             a NUMBER := 0;
          BEGIN
             RAISE NOTICE 'a = %', a;
             RAISE NOTICE 'block.a = %', block.a;
          END;
       BEGIN
          block;
       END;
    END;
    /
    

    结果:

    NOTICE:  a = 0
    NOTICE:  block.a = 0
    

    3.6. 为变量赋值

    声明变量后,可以通过以下方式为其赋值: - 使用赋值语句将表达式赋值给变量。

    • 使用SELECT INTO 或 FETCH语句从table中赋值给变量。

    • 将其作为OUT或IN-OUT参数传递给子程序,然后在子程序内部赋值。

    变量和值必须具有兼容的数据类型。如果一种数据类型可以隐式转换为另一种数据类型,那么它与另一种数据类型兼容。

    3.6.1. 用赋值语句为变量赋值

    要将表达式的值赋给变量,请使用以下形式的赋值语句:

    variable_name := expression;
    

    示例 3-22使用赋值语句为变量赋值

    本例声明几个变量(为某些变量指定初始值),然后使用赋值语句将表达式的值赋值给它们。

    \set SQLTERM /
    DECLARE -- You can assign initial values here
       name text;
       score number;
       valid_id BOOLEAN;
       stu_rec1 student%ROWTYPE;
       stu_rec2 student%ROWTYPE;
       TYPE ass_tab IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
       ass_tab_var ass_tab;
    BEGIN -- You can assign values here too
       name := 'xx';
       score := 99;
       valid_id := TRUE;
       stu_rec1.name := name;
       stu_rec2.score := score;
       stu_rec2 := stu_rec1;
       ass_tab_var(5) := 0.2 * score;
    END;
    /
    

    3.6.2. 用SELECT INTO语句为变量赋值

    SELECT INTO语句的一种简单形式是:

    SELECT select_item [, select_item ]...
    INTO variable_name [, variable_name ]...
    FROM table_name;
    

    对于每个select_item,必须有一个对应的、类型兼容的variable_name。因为SQL没有布尔类型,所以variable_name不能是布尔变量。

    示例 3-23使用SELECT INTO语句为变量赋值

    本例使用SELECT INTO语句将姓名为'xx'的学生的得分的20%赋值给变量score。

    \set SQLTERM /
    DECLARE
       score NUMBER;
    BEGIN
       SELECT score * 0.2 INTO score
       FROM student
       WHERE name = 'xx';
       raise notice 'score = %',score;
    END;
    /
    

    结果:

    NOTICE:  score = 19.8
    

    3.6.3. 将值作为子程序的参数分配给变量

    如果将变量作为OUT或IN OUT参数传递给子程序,并且子程序为该参数指定了一个值,则该变量将在子程序完成运行后保留该值。

    示例 3-24 将变量赋值为IN-OUT子程序参数

    本例将变量score传递给过程adjust_score。该过程为相应的形式参数score赋值。因为score是一个IN OUT参数,所以变量score会在过程运行结束后保留赋给的值。

    \set SQLTERM /
    DECLARE
       score NUMBER;
       PROCEDURE adjust_score (
       score IN OUT NUMBER,
       adjustment NUMBER
       ) IS
       BEGIN
          score := score + adjustment;
       END;
    BEGIN
       SELECT score INTO score
       FROM student
       WHERE name = 'xx';
       raise notice 'before invoking procedure , score = %', score;
       adjust_score (score, 0.5);
       raise notice 'before invoking procedure , score = %', score;
    END;
    /
    

    结果:

    NOTICE:  before invoking procedure , score = 99
    NOTICE:  before invoking procedure , score = 99.5
    

    3.6.4. 给BOOLEAN变量赋值

    只有值TRUE、FALSE和NULL可以给布尔变量赋值。

    示例 3-25给BOOLEAN变量赋值

    这个示例布尔变量stop默认初始化为NULL,后将其赋值为FALSE,并与TRUE进行比较,用一个BOOLEAN表达式的值给其赋值。

    \set SQLTERM /
    DECLARE
       stop BOOLEAN;
       num NUMBER := 0;
    BEGIN
       stop := FALSE;
       WHILE stop != TRUE
       LOOP
          num := num + 1;
          stop := (num > 500);
       END LOOP;
    END;
    /
  • 相关阅读:
    效果最大化的所需素材
    SqlServer触发器使用整理
    Lua专栏目录
    java集合ArrayList如何赋值?
    用googletest写cpp单测
    前端环境 本机可切换node多版本 问题源头是node使用的高版本
    C#/.Net的多播委托到底是啥?彻底剖析下
    猿创征文|HCIE-Security Day62:web安全基础,web协议详解,辨析cookie和session
    Android提取视频或音频
    结构体和类的区别详细讲解
  • 原文地址:https://blog.csdn.net/arthemis_14/article/details/126389193