• Oracle PL/SQL


    PL/SQL 简介

    PL/SQL 是过程语言(Procedural Language)与结构化查询语言(SQL)结合而成的编程语言,是对 SQL 的扩展,它支持多种数据类型,如大对象和集合类型,可使用条件和循环等控制结构,可用于创建存储过程、触发器和程序包,给SQL语句的执行添加程序逻辑,与 Oracle 服务器和 Oracle 工具紧密集成,具备可移植性、灵活性和安全性。
     

    PL/SQL 的优点

    • 支持 SQL,在 PL/SQL 中可以使用:
      1.数据操纵命令
      2.事务控制命令
      3.游标控制
      4.SQL 函数和 SQL 运算符
    • 支持面向对象编程 (OOP)
    • 可移植性,可运行在任何操作系统和平台上的Oralce 数据库
    • 更佳的性能,PL/SQL 经过编译执行
     
      
    • 与 SQL 紧密集成,简化数据处理。
      1.支持所有 SQL 数据类型
      2.支持 NULL 值
      3.支持 %TYPE 和 %ROWTYPE 属性类型
      
     
    • 安全性,可以通过存储过程限制用户对数据的访问
     

    PL/SQL 的体系结构

    PL/SQL 引擎驻留在 Oracle 服务器中,该引擎接受 PL/SQL 块并对其进行编译执行。
     

    PL/SQL基础

    PL/SQL 块简介

    PL/SQL 块是构成 PL/SQL 程序的基本单元,它将逻辑上相关的声明和语句组合在一起。
    PL/SQL 分为三个部分,声明部分、可执行部分和异常处理部分。
    复制代码
    [DECLARE  
        declarations]   --声明部分定义变量、游标和自定义异常
        BEGIN
        executable statements  --包含 SQL 和 PL/SQL 语句的可执行部分
        [EXCEPTION 
        handlers]  --指定出现错误时需要执行的操作
        END;
    复制代码
    复制代码
    DECLARE
      qty_on_hand NUMBER(5);    --声明部分定义变量、游标和自定义异常
    BEGIN     --begin到end 包含 SQL 和 PL/SQL 语句的可执行部分
      SELECT quantity INTO qty_on_hand
      FROM Products
      WHERE product = '芭比娃娃'
      FOR UPDATE OF quantity;
      IF qty_on_hand > 0 THEN
        UPDATE Products SET quantity = quantity + 1
        WHERE product = '芭比娃娃';
        INSERT INTO purchase_record
        VALUES ('已购买芭比娃娃', SYSDATE);
      END IF;
      COMMIT;
    EXCEPTION  /* 异常处理语句 */  --指定出现错误时需要执行的操作
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('出错:'|| SQLERRM);  
    END;
    复制代码

    PL/SQL中的复合符号

      :=        赋值操作符
      ||         连接操作符
      --        单行注释
      /**/      多行注释
      <<>>  标签分隔符
      ..         范围操作符
      **        求幂操作符
     

    变量和常量

    PL/SQL 块中可以使用变量和常量
      1.在声明部分声明,使用前必须先声明
      2.声明时必须指定数据类型,每行声明一个标识符
      3.在可执行部分的 SQL 语句和过程语句中使用
     
    声明变量和常量的语法:
    identifier [CONSTANT] datatype [NOT NULL]   
            [:= | DEFAULT expr];
    给变量赋值有两种方法:
    1.使用赋值语句 :=
    2.使用 SELECT INTO 语句
    复制代码
    DECLARE
      icode VARCHAR2(6);
      p_catg VARCHAR2(20);
      p_rate NUMBER;
      c_rate CONSTANT NUMBER := 0.10;
    BEGIN
      ...
      icode := 'i205';
      SELECT p_category, itemrate * c_rate
      INTO  p_catg, p_rate
      FROM itemfile WHERE itemcode = icode;
      ...
    END;
    复制代码

     数据类型

    PL/SQL 支持的内置数据类型

     

     指定数值的存储格式

     字符数据类型

    字符数据类型包括:
    1.CHAR
    2.VARCHAR2
    3.LONG
    4.RAW
    5.LONG RAW
    PL/SQL 的数据类型与 SQL数据类型的比较

    数据类型

    SQL类型

    PL/SQL类型

    CHAR

    1~2000

    1~32767

    LONG

    1~2GB

    1~32760

    LONG RAW

    1~2GB

    1~32760

    RAW

    1~2000

    1~32767

    VARCHAR2

    1~4000

    1~32767

    日期时间和布尔数据类型

    日期时间类型
    1.存储日期和时间数据
    2.常用的两种日期时间类型
    ①DATE
    ②TIMESTAMP
     
    布尔数据类型
    1.此类别只有一种类型,即BOOLEAN类型
    2.用于存储逻辑值(TRUE、FALSE和NULL)
    3.不能向数据库中插入BOOLEAN数据
    4.不能将列值保存到BOOLEAN变量中
    5.只能对BOOLEAN变量执行逻辑操作

    LOB  数据类型

    用于存储大文本、图像、视频剪辑和声音剪辑等非结构化数据。
    LOB 数据类型可存储最大 4GB的数据。
    LOB 类型包括:
      1.BLOB   将大型二进制对象存储在数据库中
      2.CLOB   将大型字符数据存储在数据库中
      3.NCLOB   存储大型UNICODE字符数据
      4.BFILE     将大型二进制对象存储在操作系统文件中
    LOB 类型的数据库列仅存储定位符,该定位符指向大型对象的存储位置
    DBMS_LOB程序包用于操纵 LOB 数据
    复制代码
    SET SERVEROUTPUT ON
    DECLARE
      clob_var   CLOB;
      amount     INTEGER;
      offset     INTEGER;
      output_var VARCHAR2(100);
    BEGIN
      SELECT chapter_text INTO clob_var   --从表中选择 CLOB 定位符到 clob_var变量中
      FROM my_book_text
      WHERE chapter_id=5;
      amount := 24;  -- 要读取的字符数
      offset := 1;   -- 起始位置
      DBMS_LOB.READ(clob_var,amount,offset,output_var);  --从CLOB数据中读取24个字符存储到 output_var 变量中
      DBMS_OUTPUT.PUT_LINE(output_var);  --显示读到的信息
    END;
    复制代码

      属性类型

    用于引用数据库列的数据类型,以及表示表中一行的记录类型。
     
    属性类型有两种:
    1.%TYPE  -  引用变量和数据库列的数据类型
    2.%ROWTYPE  -  提供表示表中一行的记录类型
     
    使用属性类型的优点:
    1.不需要知道被引用的表列的具体类型
    2.如果被引用对象的数据类型发生改变,PL/SQL 变量的数据类型也随之改变
    icode itemfile.itemcode%TYPE;
    emp_rec scott.emp%ROWTYPE;

     逻辑比较

    逻辑比较用于比较变量和常量的值,这些表达式称为布尔表达式,布尔表达式由关系运算符与变量或常量组成。

    关系运算符

    说明

    =

    比较两个变量是否相等,如果值相当,则返回 True

    <>, !=

    比较两个变量,如果不相等,则返回 True

    <

    比较两个变量,检查值 1 是否小于值 2

    >

    比较两个变量,检查值 1 是否大于 值 2

    <=

    比较两个变量,检查变量 1 是否小于等于变量 2

    >=

    比较两个变量,检查变量 1 是否大于等于变量 2

     
    布尔表达式的结果为TRUE、FALSE或NULL,通常由逻辑运算符AND、OR和NOT连接。
    布尔表达式有三种类型:
      1.数字布尔型
      2.字符布尔型
      3.日期布尔型
     

    控制结构

    PL/SQL 支持的流程控制结构:

      条件控制
        1.IF 语句
        2.CASE 语句
      循环控制
        1.LOOP 循环
        2.WHILE 循环
        3.FOR 循环
      顺序控制
        1.GOTO 语句
        2.NULL 语句
     

    条件控制

    复制代码
    DECLARE
        icode VARCHAR2(4);
        irate NUMBER;
    BEGIN
        icode := 'i203';
      SELECT itemrate INTO irate FROM itemfile 
      WHERE  itemcode = icode;
      IF irate > 200 THEN      --条件判断
        UPDATE itemfile SET itemrate = itemrate - 200
        WHERE itemcode = icode;
      ELSE
        UPDATE itemfile SET itemrate = itemrate - 50
        WHERE itemcode = icode;
      END IF;    --结束
      DBMS_OUTPUT.PUT_LINE('itemrate='|| irate);
    END;
    复制代码
    CASE 语句用于根据单个变量或表达式与多个值进行比较,执行 CASE 语句前,先计算选择器的值。
    复制代码
    BEGIN
        CASE ‘&grade’
          WHEN ’A’ THEN DBMS_OUTPUT.PUT_LINE(’优异’);
          WHEN ’B’ THEN DBMS_OUTPUT.PUT_LINE (优秀’);
          WHEN ’C’ THEN DBMS_OUTPUT.PUT_LINE (’良好’);
          WHEN ’D’ THEN DBMS_OUTPUT.PUT_LINE (’一般’);
          WHEN ’F’ THEN DBMS_OUTPUT.PUT_LINE (’较差’);
          ELSE DBMS_OUTPUT.PUT_LINE (’没有此成绩’);
        END CASE;
    END;
    复制代码

     循环控制

    循环控制用于重复执行一系列语句。
    循环控制语句包括:
      1.LOOP、EXIT 和 EXIT WHEN
     
    循环控制的三种类型:
      1.LOOP   -   无条件循环
    LOOP 
      sequence_of_statements
    END LOOP;
      2.WHILE  -  根据条件循环
    WHILE condition LOOP 
      sequence_of_statements
    END LOOP;
      3.FOR  -  循环固定的次数
    FOR counter IN [REVERSE] value1..value2
    LOOP 
      sequence_of_statements
    END LOOP;
    loop...exit...when...end loop循环控制

    采用loop...exit...when...end loop循环控制的语法结构如下所示:

    loop
      循环体;
      exit when循环条件;
    end loop
    while...loop...end loop循环控制

    这种循环控制的语法如下:

    while 条件
    loop
      执行语句段;
    end loop;

    循环例子:

    复制代码
    --while循环
    --循环输出Hello world
    declare
        var_i int := 10;
    begin
        loop
            dbms_output.put_line('Hello world');
            if var_i = 0 then
                exit;
            end if;
            var_i := var_i - 1;
        end loop;
    end;
    
    --loop输出1-10
    declare
        var_i int := 1;
    begin
        loop
            dbms_output.put_line('i = ' || var_i);
            exit when var_i = 10;
            var_i := var_i + 1;
        end loop;
    End
    
    --while循环1-5
    Declare
        var_i int:=1;
    Begin
        while var_i<=10 loop
            Dbms_output.put_line('I='||var_i);
            Var_i:=var_i+1;
        End loop;
    End;
    
    
    
    --for 循环 : for 变量 in 范围 loop
    --1-10输出
    begin
        for i in 1..10 loop
            dbms_output.put_line('i = ' || i);
        end loop;
    end
    
    --对员工的工资判断,如果少于2000则加50,直到工资满足为止!
    declare
        var_sal int;
    begin
        loop
            select sal into var_sal from emp where empno = 7499;
            exit when var_sal >= 2000;
            update emp set sal = sal + 50 where empno = 7499;
            dbms_output.put_line('加50');
        end loop;
    end;
    复制代码

    顺序控制

    顺序控制用于按顺序执行语句。
    顺序控制语句包括:
      1.GOTO 语句 -  无条件地转到标签指定的语句
      2.NULL 语句 -  什么也不做的空语句
    复制代码
    DECLARE
      qtyhand itemfile.qty_hand%type;
      relevel itemfile.re_level%type;
    BEGIN
      SELECT qty_hand,re_level INTO qtyhand,relevel
      FROM itemfile WHERE itemcode = 'i201';
      IF qtyhand < relevel THEN
        GOTO updation;  --跳转到<<updation>>语句块
      ELSE
        GOTO quit;  --跳转到<<quit>>
      END IF;
      <<updation>>
      UPDATE itemfile SET qty_hand = qty_hand + re_level
      WHERE itemcode = 'i201';
      <<quit>>
      NULL;
    END;
    复制代码

     动态 SQL

    动态 SQL 是指要执行的SQL语句需要在执行的时候才能确定的SQL语句,是在PL/SQL程序执行时生成的 SQL 语句,编译程序对动态 SQL 不做处理,而是在程序运行时动态构造语句、对语句进行语法分析并执行。DDL 语句命令和会话控制语句不能在 PL/SQL 中直接使用,但是可以通过动态 SQL 来执行。
     
    执行动态 SQL 的语法:
       EXECUTE IMMEDIATE dynamic_sql_string
    
          [INTO  define_variable_list]
    
          [USING bind_argument_list];

     例:

    复制代码
    DECLARE
      sql_stmt VARCHAR2(200);
      emp_id NUMBER(4) := 7566;
      emp_rec emp%ROWTYPE;
    BEGIN
        EXECUTE IMMEDIATE 
        'CREATE TABLE bonus1 (id NUMBER, amt NUMBER)';
    
        sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
        EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
    END;
    复制代码
    复制代码
    --显示员工编号为7499的所有信息
    declare
        Var_row emp%rowtype;
    begin
        select * into var_row from emp where empno = 7499;
        dbms_output.put_line('编号=' || var_row.empno || '姓名=' || var_row.ename);
    end;
    复制代码
    复制代码
    --动态执行
    declare
        var_row emp%rowtype;
        var_sql varchar(100);
        var_empno int;
    begin
        var_sql := 'select * from emp where empno = :num' ;
        execute immediate var_sql into var_row using var_empno;
        dbms_output.put_line('编号=' || var_row.empno || '姓名=' || var_row.ename);
    end;
    复制代码
    --用动态SQL来实现分页
    begin
        execute immediate 'select * from (select rownum rn, d.* from (select * from :tableName order by sal desc) d) where rn > :min and rn <= :max' using 'emp' , 1, 5;
    End;

     错误处理

     
    在运行程序时出现的错误叫做异常,发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分。
     
    异常有两种类型:
    1.预定义异常 -  当 PL/SQL 程序违反 Oracle 规则或超越系统限制时隐式引发
    2.用户定义异常  -  用户可以在 PL/SQL 块的声明部分定义异常,自定义的异常通过 RAISE 语句显式引发
     
     
    处理预定义异常
    复制代码
    access_into_null   --在未初化对象时出现
    case_not_found    --在CASE语句中的选项与用户输入的数据不匹配时出现
    collection_is_null    --在给尚未初始化的表或数组赋值时出现
    cursor_already_open    --在用户试图打开已经打开的游标时出现
    dup_val_on_index    --在用户试图将重复的值存在使用唯一索引的数据库列中时出现
    invalid_cursor        --在执行非法游标运算(如打开一个尚未打开的游标)时出现
    invalid_number     --在将字符串转换为数字时出现
    login_denied        --在输入的用户名或密码无效时出现
    no_data_found     --在表中不存在的请求的行时出现,此外,当程序引用已经删除的元素时
    storage_error       --在内存损坏或PL/SQL耗尽内存时出现
    too_many_rows    --在执行SELECT INTO语句后返回多行时出现
    value_error    --在产生大小限制错误时出现
    zero_divide    --以零作除数时出现
    Others          --针对所有异常
    
    复制代码

     处理用户定义异常

    复制代码
    DECLARE 
      invalidCATEGORY EXCEPTION;
      category VARCHAR2(10);
    BEGIN
      category := '&Category';
      IF category NOT IN ('附件','顶盖','备件') THEN
        RAISE invalidCATEGORY;
      ELSE
        DBMS_OUTPUT.PUT_LINE('您输入的类别是'|| category);
      END IF;
    EXCEPTION
      WHEN invalidCATEGORY THEN
        DBMS_OUTPUT.PUT_LINE('无法识别该类别');
    END;
    复制代码

     引发应用程序错误

    复制代码
    DECLARE
      rate itemfile.itemrate%TYPE;
      rate_exception EXCEPTION;  --定义异常
    BEGIN
      SELECT NVL(itemrate,0) INTO rate FROM itemfile 
      WHERE  itemcode = 'i207';
      IF rate = 0 THEN
        RAISE rate_exception;  --引发异常
      ELSE
        DBMS_OUTPUT.PUT_LINE('项费率为:' || rate);
      END IF;
    EXCEPTION
      WHEN rate_exception THEN  --扑捉异常
        RAISE_APPLICATION_ERROR(-20001, '未指定项费率');
    END;
    复制代码

    引发系统级错误

    begin
        if 10 > 5 then
            raise_application_error(-20001, '这个是自定义错误显示');
        end if;
    end; 
  • 相关阅读:
    Roads in the Kingdom CodeForces
    Vasya and Shifts CodeForces
    SOS dp
    Singer House CodeForces
    Codeforces Round #419 (Div. 1) (ABCD)
    在踏踏实实的生活里让自己坚持去做梦
    Replace Delegation with Inheritance
    Replace Inheritance with Delegation
    Replace Parameter with Methods
    Preserve Whole Object
  • 原文地址:https://www.cnblogs.com/bluedy1229/p/5005335.html
Copyright © 2020-2023  润新知