PL/SQL基础语法大全

PL/SQL最小有意义的代码单元叫做块(block)。一个块就是一组代码,这个块给出了执行边界,也为变量声明和异常处理提供了作用范围。PL/SQL允许我们创建匿名块和命名块。命名块可以是包、过程、函数、触发器或者对象类型。

1、PL/SQL块结构

PL/SQL最小有意义的代码单元叫做块(block)。一个块就是一组代码,这个块给出了执行边界,也为变量声明和异常处理提供了作用范围。PL/SQL允许我们创建匿名块和命名块。命名块可以是包、过程、函数、触发器或者对象类型。

一个PL/SQL块最多可以由4个不同单元组成,只有一个单是必不可少的(执行单元)。

  • 块头(header)  只有命名块才会有这个单元。块头确定命名块获程序的调用方式,这个单元是可选的。

  • 声明单元(declaration section)  定义变量、游标、以及可以被后面执行单元或异常单元引用的子块单元。这个单元也是可选的

  • 执行单元(execution section)  这一部分包含要执行的业务逻辑,这个单元式必须的

  • 异常处理单元(exception section)   处理抛出的异常,这个单元式可选的

例如:插入指定的名称到employee且插入一个日期 

PROCEDURE get_happy (ename_in IN VARCHAR2)    -- 块头
IS
    l_hiredate    DATE;    -- 声明单元
BEGIN
    l_hiredate := SYSDATE - 2;
    INSERT INTO employee (emp_name, hiredate) VALUES (ename_in, l_hiredate);    -- 执行单元
EXCEPTION
    WHEN DUP_VAL_IN_INDEX THEN    -- 异常处理单元
        DBMS_OUTPUT.PUT_LINE('Cannot insert.');
END;

2、匿名块

匿名块没有一个可以引用的句柄,因此不能被其他块调用。相反匿名块可以调用其他块。匿名块直接以DECLARE或BEGIN开始。如:

BEGIN
    DBMS_OUTPUT.PUT_LINE('Hello World');
END;

一个匿名PL/SQL代码块的语法通常是这样:

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

a、最小匿名块

BEGIN
    DBMS_OUTPUT.PUT_LINE(SYSDATE);
END;

b、有声明单元

DECLARE
    now_date    VARCHA2(9);
BEGIN
    now_date := SYSDATE;
    DBMS_OUTPUT.PUT_LINE( now_date);
END;

c、存在异常处理块

DECLARE
    now_date    VARCHA2(9);
BEGIN
    now_date := SYSDATE;
    DBMS_OUTPUT.PUT_LINE( now_date);
EXCEPTION
    WHEN VALUE_ERROR THEN
        DBMS_OUTPUT.PUT_LINE('now_date is too small');
END;


3、命名块

命名块和匿名块最大区别在于,命名块有头部信息。一个过程的头部是这样的:

PROCEDURE [schema.] name [(parameter [, parameter  . . . ])]
            [AUTHID {DEFINER | CURRENT_USER}]

一个函数的头部的语法类似,但是有RETURN关键字:

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

例如:创建一个hello过程,显示'Hello World'。

PROCEDURE hello
IS
    v_str    VARCHAR2(100);
BEGIN
    v_str := 'Hello World';
    DBMS_OUTPUT.PUT_LINE(v_str );
END;


4、嵌套块

PL/SQL允许块中再嵌套块。被嵌套的块还有其他的叫法比如闭包块、子块或者sub-block如。外层的PL/SQL块可以叫包围块或者父块。

PROCEDURE hello
IS
    v_str    VARCHAR2(100);
BEGIN
    v_str := 'Hello World';
    
    /* 嵌套模块开始  */
    DECLARE
        v_str2
    BEGIN
        v_str2 := v_str || ' inner block';
        DBMS_OUTPUT.PUT_LINE(v_str2);
    END;
    /* 嵌套模块结束 */
    DBMS_OUTPUT.PUT_LINE(v_str );
END;


5、作用范围

在PL/SQL中,变量、异常、模块和一些其他的结构都是属于声明它们的块局部。当这个块结构结束后,我们就再也无法引用这些结构中声明的变量。


6、规范SQL语句中所有对变量和列的引用

-- 包头
PACKAGE scope_demo
IS
    g_global NUMBER;
    
    PROCEDURE set_global (number_in IN NUMBER);
END scope_demo;
-- 包体
PACKAGE BODY scope_demo
IS
PROCEDURE set_global (number_in IN NUMBER) 
IS
    l_salary    NUMBER := 10000; -- 只能在set_global作用域中 
    l_count   PLS_INTEGER;
BEGIN
    -- 嵌套模块
    <<local_block>> -- 为嵌套模块命名
    DECLARE
        l_inner PLS_INTEGER; -- 只能在local_block嵌套块中使用
    BEGIN
        SELECT COUNT(*) INTO set_global . l_count  
         FROM employees e 
       WHERE e.department_id= local_block.l_inner 
            AND e.salary > set_global.l_salary;
    END local_block;
    scope_demo.g_global := set_global.number_in;
END set_global;
END scope_demo;

注意:在嵌入式SQL语句中,Oracle数据库会首先把这些不规范的标示符当作表中的列名来解释,如果不能找到匹配的列,Oracle会接着尝试把它当作作用范围内的PL/SQL变量来解释。


7、可见性

可见性表示我们是否可以仅通过名字引用一个变量,或者还需要在名字的前面加一个前缀。

a、可见的标示符

先观察一个例子:

declare
    age        NUMBER(2);
    name    VARCHAR2(100);
begin
    age := 22;
    name := 'zhangsan';
end;

因为 age 和 name 两个变量的声明和使用是再同一个块中,我们就可以非常方便的通过“非规范化”的标示符引用它们,这些标示符也被称为可见标示符。一个可见标示符实践上可能是这样的:

1)一个在当前块中声明的标示符

2)一个在包含当前块的块中声明的标示符

3)属于你所有的一个单独的数据库对象或者 PL/SQL 对象

4)一个你能看见的数据库别名,而且你对别名指向的数据库对象或者 PL/SQL 对象有适当的权限

5)一个循环体中的索引变量(但这个变量的作用域只在循环体中)

通过模块的名称来规范化标识符的名字,PL/SQL 提供许多方法来规范化一个标志符以保证对于标示符的引用能够被正确的解析。比如,使用包我们可以创建属于包的全局作用域变量。

PACKAGE comany_pkg
IS
    name    varchar2(200);
END comany_pkg;

我们可以通过 comany_pkg.name 的形式访问到该变量。

PL/SQL 还提供了一个特别重要的特性叫做嵌套程序。嵌套程序就是完全出现在包围块的声明单元的过程获函数。重要的是,嵌套程序可以引用外层块声明的变量及参数,如下:

PROCEDURE outer_proc (fudge_factory_in IN NUMBER)
IS
    subtotal    NUMBER    := 0;
    
    /* 嵌套块的开始,注意过程的全部内容都放在outer_proc 的声明单元 */
    PROCEDURE compute_running(increment_in IN PLS_INTEGER)
    IS
    BEGIN
        /* subtotal,是再上面申明的,即在作用范围内同时也是可见的 */
        subtotal    := subtotal + increment_in * fudge_factory_in ;
    END;
    /* 嵌套块的结束*/
BEGIN
    FOR month_idx IN 1..12 LOOP
        /* 调用compute_running嵌套程序 */
        compute_running(month_idx );
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('Fudged total for year: ' || subtotal);
END;


8、NULL

在 Oracle 数据库中,一个值的缺失是通过关键字 NULL 来表示的。

在 Oracle SQL 和 PL/SQL 中,一个空字符串和零个字符的直接量是没有区别的,后缀表现为''(两个连载一起的单引号,之间没有任何字符)。例如,下面表达式在SQL还是PL/SQL中结果都是TRUE。

'' IS NULL;

在PL/SQL中给VARCHAR2(n)变量赋值一个长度为0的字符串,导致结果就是NULL;

DECLARE
    str     VARCHAR2(0);
BEGIN
    IF str IS NULL THEN -- 结果是TURE

CHAR数据类型有些怪异,如果在PL/SQL中创建CHAR(n),然后将n=0,数据库会用空格字符填满这个变量,因为这个变量不为空:

DECLARE
    flag CHAR(2) := ' ';
BEGIN
    IF flag = '   '  . . .     --  结果为TRUE
    IF flag IS NULL . . .  -- 结果是FALSE


9、布尔直接量

PL/SQL提供了两个表示布尔值的直接量:TRUE 和 FALSE。这不是字符串,我们不用加引号。可以直接赋值给布尔类型的变量。如:

DECLARE
    flag    BOOLEAN;
BEGIN
    flag := TRUE;
    IF flag HTEN
        . . . 
    END IF;
END;

一个布尔表达式、变量、或者常量也可以是 NULL,这既不是 TRUE 也不是 FALSE。


10、分号分隔符

一个PL/SQL程序是由一系列的声明和语句组成。这些都是通过逻辑定义的,而不是物理定义的。换句话说,不是根据每一个物理行的结尾为结束的,而是用分号(;)结束的。如:

IF salary < 1000 
THEN
    salary :=  salary + salary * 0.25;
END IF;

IF salary < 1000 THEN salary :=  salary + salary * 0.25; END IF; --  不推荐


11、注释

PL/SQL 的注释分为“单行注释”和“多行注释”。语法如下:

-- 声明单行注释
/*
    声明多汗注释
*/

12、PRAGMA关键字

一个真正来自于希腊语的编程概念就是pragma,这意味着“契约”或者,暗示的是,一个“动作”。在许多编程语言中,pragma通常是一行用于告诉编译器采取什么行动的源代码。就像提供给编译器一个选项;可以导致不同的运行时刻行为,但又不会直接被翻译成字节代码。PL/SQL语法:

PRAGMA instruction_to_compiler PL/SQL编译器能够接受出现在声明单元的这种指令。不过许多指令还有额外的相关配置需求。

  • AUTONOMOUS_TRANSACTION  这个指令告诉PL/SQL运行引擎,当前块对数据库所作的修改提交或者回滚不影响主事务或者外层事务。

  • EXCEPTION_INIT  这个指令告诉编译器把一个特殊的错误号和我们在程序中声明的异常标示符关联起来。必须跟在异常声明之后。

  • RESTRICT_REFERENCES  告诉编译器一个包程序的纯度级别(避免副作用)。

  • SERIALLY_REUSABLE  告诉PL/SQL运行时引擎,包级别的数据在引用之间不应该保留。    

如:EXCEPTION_INIT 的用法:

DECLARE
    my_exception    EXCEPTION;
    PRAGMA EXCEPTION_INIT( my_exception, -2289);
BEGIN
    . . . 
EXCEPTION
    WHEN my_exception THEN
        . . .     
END;


13、标签

PL/SQL标签是一种为我们程序中特定部分命名的方法。语法:<<identifier>>。其中identifier是一个有效的PL/SQL标识符(最大长度可以到30个字符,并用字母开头)。不需要终结符号;可以直接放到其他标注的内容前面,这些内容必须是一个可执行的语句,就算是一个NULL语句:

BEGIN
    . . . 
    <<the_scpot>>
    NULL;

因为匿名块本身是可以执行的语句,一个标签就可以在匿名块的执行周期为其命名。如:

<<test>>
BEGIN
    . . . 
EXCEPTION
    . . . 
END test;

使用标签可以从当前、内嵌的代码中,规范的引用来自外层包围块的具有相同名字的元素。如:

<<out_block>>
DECLARE
    count NUMBER(4) := 100;
BEGIN
    /* 内部嵌套块*/
    DECLARE
        count    NUMBER(4) := 1;
    BEGIN
        IF count = out_block.count THEN
            . . . 
        END IF;
    END;
END;

以上如果不使用标签,则无法区分count到底是外围还是嵌套块的count。

标签还可以作为GOTO语句的目标。如:

DECLARE
    . . .
BEGIN
    . . . 
    GOTO label_name
    . . . 
    <<label_name>>
    . . . 
END;
人永远是要学习的。死的时候,才是毕业的时候。 —— 萧楚女
0 不喜欢
说说我的看法 -
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号