zoukankan      html  css  js  c++  java
  • 【Oracle11g】18_PL/SQL基础

    1.PL/SQL简介

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

    2.PL/SQL的优点

    1)支持 SQL,在 PL/SQL 中可以使用:

    • 数据操纵命令
    • 事务控制命令
    • 游标控制
    • SQL 函数和 SQL 运算符

    2)用户把PL/SQL块整个发送到服务器端,oracle服务器端编译、运行,再把结果返回给用户
    3)可移植性,可运行在任何操作系统和平台上的Oralce 数据库
    4)更佳的性能,PL/SQL 经过编译执行
    5)安全性,可以通过存储过程限制用户对数据的访问
    6)与 SQL 紧密集成,简化数据处理。

    • 支持所有 SQL 数据类型
    • 支持 NULL 值
    • 支持 %TYPE 和 %ROWTYPE 属性类型

    3.PL/SQL的体系结构

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

    4.PL/SQL块简介

    1)PL/SQL 块是构成 PL/SQL 程序的基本单元
    2)将逻辑上相关的声明和语句组合在一起
    3)PL/SQL 分为三个部分,声明部分、可执行部分和异常处理部分

       [DECLARE declarations]
       BEGIN
           executable statements
           [EXCEPTION handlers]
       END;
    

    5.变量和常量

    • PL/SQL 块中可以使用变量和常量
      • 在声明部分声明,使用前必须先声明
      • 声明时必须指定数据类型,每行声明一个标识符
      • 在可执行部分的 SQL 语句和过程语句中使用
    • 声明变量和常量的语法:
    identifier [CONSTANT] datatype [NOT NULL]   
    		[:= | DEFAULT expr];
    
    • 给变量赋值有两种方法:
      • 使用赋值语句 :=
      • 使用 SELECT INTO 语句

    实战案例

    -- 建表准备环境
    create table student(id number,name varchar2(40),age number);
    insert into student values(1,'Jack',23);
    insert into student values(2,'Tom',25);
    insert into student values(3,'Alice',30);
    
    -- 查询表记录数的PL/SQL块
    declare 
        total_row number;
    begin
        select count(1) into total_row from student;
        dbms_output.put_line('一共有'|| total_row ||'记录');
    end;
    /
    

    执行PL/SQL块后结果如下图:

    6.PL/SQL数据类型

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

    6.1.1 数字数据类型

    BINARY_INTEGER:存储有符号整数,所需存储空间少于NUMBER类型值
    NUMBER:存储整数、实数和浮点数
    PLS_INTEGER:存储有符号整数,可使算术计算快速而有效

    Oracle11g推出了一个新的数据类型SIMPLE_INTEGER,这种数据类型的取值范围为–2147483 648~+2147483647,数据类型不为空。对于此数据类型,Oracle可以将这个数据类型的操作直接作用于硬件,从而提高性能。

    6.1.2 字符数据类型

    数据类型 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字节

    6.1.3 日期数据类型

    日期时间类型:存储日期和时间数据
    常用的两种日期时间类型

    • DATE
    • TIMESTAMP

    6.1.4 布尔数据类型

    布尔数据类型:此类别只有一种类型,即BOOLEAN类型

    • 用于存储逻辑值(TRUE、FALSE和NULL)
    • 不能向数据库中插入BOOLEAN数据
    • 不能将列值保存到BOOLEAN变量中
    • 只能对BOOLEAN变量执行逻辑操作

    6.1.5 LOB数据类型

    用于存储大文本、图像、视频剪辑和声音剪辑等非结构化数据。
    LOB 数据类型可存储最大 4GB的数据。
    LOB 类型包括:

    • BLOB 将大型二进制对象存储在数据库中
    • CLOB 将大型字符数据存储在数据库中
    • NCLOB 存储大型UNICODE字符数据
    • BFILE 将大型二进制对象存储在操作系统文件中

    LOB 类型的数据库列仅存储定位符,该定位符指向大型对象的存储位置
    DBMS_LOB程序包用于操纵 LOB 数据。

    实战演练:clob

    -- 创建表
    create table testclob(id number primary key,content clob);
    -- 插入数据
    insert into testclob values(1,'道不尽红尘奢恋 诉不完人间恩怨,世世代代都是缘,流着相同的血 喝着相同的水,这条路漫漫又长远,红花当然配绿叶 这一辈子谁来陪,渺渺茫茫来又回,往日情景再浮现 藕虽断了丝还连,,爱江山 更爱美人,哪个英雄好汉宁愿孤单,好儿郎 浑身是胆,壮志豪情四海远名扬,人生短短几个秋啊 不醉不罢休,东边儿我度的美人哪 西边儿黄河流,来呀来个酒啊 不醉不罢休,愁情烦事别放心头。');
    
    -- 查询
    select * from testclob;
    

    查询结果:

    从查询结果我们可以看到,通过普通的select只能查出部分数据。,所以下边使用PL/SQL来获取

    declare 
        clob_var   clob;
        amount     integer;
        offset     integer;
        output_var varchar2(10000);
    begin
        select content into clob_var from testclob where id=1;
        amount := 2000;
        offset := 1;
        dbms_lob.read(clob_var, amount, offset,  output_var);
        dbms_output.put_line(output_var) ;
    end;
    /
    

    运行结果:

    实战演练:blob

    -- 首先在c盘下创建文件夹photo,并且保存一张图片到该目录,例如:a.jpg
    
    -- 创建目录(使用system用户授权)
    grant read, write on directory PHOTO to scott;
    create directory PHOTO as 'c:/photo';
    
    -- 创建表
    create table testblob(id number primary key,photo blob);
    
    -- 创建存储过程
    create or replace procedure insertBlob(id varchar2, imgFile varchar2)
    is
        img_file bfile;
        img_blob blob;
        lob_length number;
    begin
        -- 先插入一个空值
        insert into testblob values(id, empty_blob() );
        select photo into img_blob from testblob where id = id;
    
        -- 读取img_file中的内容
        img_file := bfilename('PHOTO', imgFile);
        dbms_lob.open(img_file);
        lob_length := dbms_lob.getlength(img_file);
    
        -- 修改表中列photo的内容
        dbms_lob.loadfromfile(img_blob, img_file, lob_length);
        dbms_lob.close(img_file);
    end;
    /
    

    执行该存储过程

    exec insertBlob(1,'a.jpg');
    

    查询结果,发现已经保存成功

    7.属性类型

    用于引用数据库列的数据类型,以及表示表中一行的记录类型

    属性类型有两种:

    • %TYPE - 引用变量和数据库列的数据类型
    • %ROWTYPE - 提供表示表中一行的记录类型

    使用属性类型的优点:

    • 不需要知道被引用的表列的具体类型
    • 如果被引用对象的数据类型发生改变,PL/SQL 变量的数据类型也随之改变,健壮性。

    8.PL/SQL块中取序列的值

    -- 创建序列
    create sequence seq1 start with 1 increment by 1;
    
    -- 取值的PL/SQL块
    SQL> set serveroutput on -- 设置允许显示输出类似dbms_output
    
    declare
        num int;
    begin
        num := seq1.nextval; -- 11g新特性
        -- 11g之前:select seq1.nextval into num from dual;
        dbms_output.put_line('num的值是:' || num);
    end;
    /
    

    9.逻辑比较

    逻辑比较用于比较变量和常量的值,这些表达式称为布尔表达式
    布尔表达式由关系运算符与变量或常量组成
    布尔表达式的结果为TRUE、FALSE或NULL,通常由逻辑运算符AND、OR和NOT连接
    布尔表达式有三种类型:

    • 数字布尔型
    • 字符布尔型
    • 日期布尔型

    10.控制结构

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

    • 条件控制
      • IF 语句
      • CASE 语句
    • 循环控制
      • LOOP 循环
      • WHILE 循环
      • FOR 循环
    • 顺序控制
      • GOTO 语句
      • NULL 语句

    10.1 IF语句

    IF 语句根据条件执行一系列语句,有三种形式:IF-THEN、IF-THEN-ELSE 和 IF-THEN-ELSIF

    案例:

    -- 建表并插入数据
    create table t1(id number,name varchar2(10),age number);
    insert into t1 values(1,'Jack',19);
    insert into t1 values(2,'Tom',22);
    insert into t1 values(3,'Alice',11);
    commit;
    
    -----PL/SQ块:判断Jack的年龄是否大于18岁
    SQL> set serveroutput on -- 设置允许显示输出类似dbms_output
    declare
        v_age t1.age%type;
    begin
        select age into v_age from t1 where id=1;
        if v_age > 18 then
            dbms_output.put_line('Jack的年龄大于18岁');
        else
            dbms_output.put_line('Jack的年龄小于等于18岁');
        end if;
    end;
    /
    
    

    10.2 CASE语句

    CASE 语句用于根据单个变量或表达式与多个值进行比较。
    执行CASE 语句前,先计算选择器的值。

    案例

    --&grade表示从键盘输入值赋给变量grade
    declare 
        outgrade varchar2(20);
    begin
        outgrade := CASE &grade 
            WHEN 'A' THEN '优秀'
            WHEN 'B' THEN '良好'
            WHEN 'C' THEN '中等'
            WHEN 'D' THEN '及格'
            WHEN 'E' THEN '不及格'
            ELSE '没有此成绩'
        END;
        dbms_output.put_line(outgrade );
    end;    
    /    
    

    执行结果:

    10.3 循环控制

    循环控制用于重复执行一系列语句
    循环控制语句包括:

    • LOOP、EXIT 和 EXIT WHEN 、FOR 、WHILE

    循环控制的三种类型:

    • LOOP - 无条件循环
    • WHILE - 根据条件循环
    • FOR - 循环固定的次数
    -- LOOP循环
    LOOP 
      sequence_of_statements
    END LOOP;
    
    -- WHILE循环
    WHILE condition LOOP 
      sequence_of_statements
    END LOOP;
    
    -- FOR循环
    FOR counter IN [REVERSE] value1..value2
    LOOP 
      sequence_of_statements
    END LOOP;
    
    

    实战演练:按要求打印1~8的数字

    -- LOOP实现
    declare
        num number := 0;
    begin
        num := 1;
        loop
            dbms_output.put_line(num || '******');
            exit when num > 7;
            num := num + 1;
        end loop;
        dbms_output.put_line( '结束');
    end;
    /
    
    -- WHILE实现
    declare
        num number := 0;
    begin
        num := 1;
        while num <=8
        loop
            dbms_output.put_line(num || '******');
            num := num + 1;
        end loop;
        dbms_output.put_line( '结束');
    end;
    /
    
    -- FOR实现
    
    begin
        for num in 1..8
        loop
            dbms_output.put_line(num || '******');
        end loop;
        dbms_output.put_line( '结束');
    end;
    /
    

    10.4 continue语句

    continue表示本次循环结束,下次循序继续
    实战演练

    declare
        num number := 0;
    begin
        num := 1;
        loop
            num := num + 1;
            exit when num > 8;
            continue when num > 4;
            dbms_output.put_line(num || '******');     
        end loop;
        dbms_output.put_line( '结束');
    end;
    /
    

    执行结果:
    2******
    3******
    4******
    结束

    10.5 goto语句

    顺序控制用于按顺序执行语句
    顺序控制语句包括:

    • GOTO 语句 - 无条件地转到标签指定的语句
    • NULL 语句 - 什么也不做的空语句

    实战演练:按要求打印1~8

    -- null表示什么都不做,CPU停一下
    declare
        num number := 0;
    begin
        num := 1;
        <<aa>>
            dbms_output.put_line(num || '******');     
            num := num+1;
            if num <= 8 then goto aa;end if;
            if num > 8 then goto bb;end if;
        <<bb>> null;
        dbms_output.put_line( '结束');
    end;
    /
    

    11.动态SQL

    动态 SQL 是指在PL/SQL程序执行时生成的 SQL 语句。
    编译程序对动态 SQL 不做处理,而是在程序运行时动态构造语句、对语句进行语法分析并执行。
    DDL 语句命令和会话控制语句不能在 PL/SQL 中直接使用,但是可以通过动态 SQL 来执行。
    执行动态 SQL 的语法:

    EXECUTE IMMEDIATE dynamic_sql_string
          [INTO  define_variable_list]
          [USING bind_argument_list];
    

    实战演练

    begin
        execute immediate 'create table t2(id number)';
    end;
    /
    

    12.错误处理

    在运行程序时出现的错误叫做异常
    发生异常后,语句将停止执行,控制权转移到 PL/SQL 块的异常处理部分
    异常有两种类型:

    • 预定义异常 - 当 PL/SQL 程序违反 Oracle 规则或超越系统限制时隐式引发。
    • 用户定义异常 - 用户可以在 PL/SQL 块的声明部分定义异常,自定义的异常通过 RAISE 语句显式引发。

    12.1 预定义异常

    实战演练:预定义异常

    declare 
        v_name t1.name%type;
    begin
        select name into v_name from t1 where id=99;
        dbms_output.put_line(v_name);
    exception
        when no_data_found then
           dbms_output.put_line('没有这个人的信息存在!'); 
    end;
    /
    

    12.2 用户定义异常

    实战演练:用户定义异常

    -- 往表t1插入记录
    insert into t1 values(4,'Lucy',-12);
    
    SQL> select * from t1;
    
            ID NAME              AGE
    ---------- ---------- ----------
             1 Jack               19
             2 Tom                22
             3 Alice              11
             4 Lucy              -12
    
    -- 此时Lucy的年龄是异常的,在PL/SQL块做异常处理
    declare
        v_age t1.age%type;
        invalid_age exception;
    begin
        select age into v_age from t1 where id=4;
        if v_age < 0 then
            raise invalid_age ;
        else
            dbms_output.put_line('年龄正常');
        end if;
    exception
        when invalid_age then
            dbms_output.put_line('年龄错粗了,怎么可能是负数?');
    end;
    /
    

    13.引发应用程序错误

    RAISE_APPLICATION_ERROR 过程

    • 用于创建用户定义的错误信息
    • 可以在可执行部分和异常处理部分使用
    • 错误编号必须介于 –20000 和 –20999 之间
    • 错误消息的长度可长达 2048 个字节

    引发应用程序错误的语法:

    RAISE_APPLICATION_ERROR(error_number, error_message);
    

    实战演练

    declare
        v_age t1.age%type;
        invalid_age exception;
    begin
        select age into v_age from t1 where id=4;
        if v_age < 0 then
            raise invalid_age ;
        else
            dbms_output.put_line('年龄正常');
        end if;
    exception
        when invalid_age then
            dbms_output.put_line('年龄错粗了,怎么可能是负数?');
            RAISE_APPLICATION_ERROR(-20996, '年龄异常');
    end;
    /
    

  • 相关阅读:
    神秘题目4
    神秘题目3
    神秘题目2
    AC自动机
    Fence Obstacle Course 题解
    Fractal Streets
    龟速乘
    快速幂
    Stall Reservation
    Sunscreen
  • 原文地址:https://www.cnblogs.com/OliverQin/p/12771415.html
Copyright © 2011-2022 走看看