zoukankan      html  css  js  c++  java
  • ORACLE数据库之PL/SQL编程

    1、PL/SQL简介

    PL/SQL是Oracle在数据库中引入的一种过程化编程语言。PL/SQL构建于SQL之上,可以用来编写包含SQL语句的程序。可以通过IF语句或LOOP语句实现控制程序的执行流程,甚至可以定义变量,以便在语句之间传递数据信息,这样PL/SQL语言就能够实现操控程序处理的细节过程。

    1.1 PL/SQL块结构

    PL/SQL程序是以块(BLOCK)为基本单位,整个PL/SQL块分三部分:
    声明部分(用DECLARE开头)、执行部分(以BEGIN开头)和异常处理部分(以EXCEPTION开头)。其中执行部分必选,其他两个部分可选。

    [DECLARE]
    --声明部分,可选
    BEGIN
    --执行部分,必须
    [EXCEPTION]
    --异常处理部分,可选
    END
    

    每一条语句都必须以分号结束。

    1.2 代码注释和标示符

    1)单行注释
    由两个连接符号“--”开始,后面紧跟着注释内容。
    2)多行注释
    由/开头,以/结尾。
    3)标识符
    标识符必须满足以下条件:
    当定义变量、常量时,每行只能定义一个变量或者常量。
    当定义变量、常量时,名称必须以英文字符(AZ、az)开始,并且最大长度为30个字符。如果以其他字符开始,那么必须使用双引号引住。
    当定义变量、常量时,名称只能使用AZ、az、0~9、_、$和#。如果以其他字符开始,那么必须使用双引号引住。
    当定义变量、常量时,名称不能使用Oracle关键字。如果要使用Oracle关键字,那么必须使用双引号引住。

    合法的字符集主要包含以下内容:
    大写和小写字母:AZ或az
    数字:0~9
    非显示的字符:制表符、空格和回车
    数字符号:+、-、*、/、>、<、=等
    间隔符:包括()、{}、?、!、;、:、@、#、%、$、&等

    4)分界符
    用来将标识符相互分隔开。
    +、-、、/、=、>、<、(、)、:、%、'、<>、!=、~=、^=、<=、>=、@、/、:、**、:=、=>、..、||、<<、>>、--、/、*/、

    1.3 文本

    文本是指实际的数值的数值。包括数字文本、字符文本、字符串文本、布尔文本、日期时间文本等。

    2、数据类型、变量、常量

    2.1基本数据类型

    1)数值类型
    数值类型主要包含NUMBER、PLS_INTEGER和BINARY_INTEGER三种基本数据类型。其中NUMBER类型可以存储整数和浮点数,而PLS_INTEGER和BINARY_INTEGER类型只能存储整数。
    NUMBER类型可以通过NUMBER(P,S)的形式来格式化字符串,P代表精度(数值中所有有效数字的个数),S代表刻度范围(小数点右面小数位的个数)。

    Num_Money NUMBER(9,2)  --声明一个精度为9,且刻度范围为2的表示金额的变量
    

    与NUMBER类型等价的类型别名:DEC、DECIMAL、DOUBLE、INTEGER、INT、NUMERIC、SMALLINT、PLS_INTEGER、BINARY_INTEGER等。

    2)字符类型
    字符类型主要包括VARCHAR2、CHAR、LONG、NCHAR和NVARCHAR2等,这些类型的变量用来存储字符串或字符数据。
    VARCHAR2用来存储可变长度的字符串

    VARCHAR2(maxlength) --maxlength用来表示存储字符串的最大长度,最大值为32727,在定义变量时必须给出。
    

    CHAR类型表示指定长度的字符串。如果赋给CHAR类型的值不足maxlength则会在其后面用空格补全。

    CHAR(maxlength)     --maxlength用来表示存储字符串的最大长度,最大值为32727,定义变量时不是必须给出,默认长度为1
    

    LONG类型表示一个可变长度的字符串,最大长度为32767字节。
    NCHAR和NVARCHAR2类型的长度根据各国字符集来确定。

    3)日期类型
    日期类型只有一种:DATE类型,用来存储日期和时间信息,存储空间为7个字节,分别使用一个字节存储世纪、年、月、日、时、分、秒。
    4)布尔类型
    布尔类型也只有一种:BOOLEAN,主要用来程序的流程控制和业务逻辑判断。其变量值可以是TRUE、FALSE、NULL中的一种。

    2.2特殊数据类型

    1)%TYPE类型
    关键字可以声明一个与指定列相同的数据类型,他通常紧跟在指定列名的后面。

    declare
      var_job emp.job%type  --声明一个与emp表中job列的数据类型完全相同的变量var_job 
    

    2)RECORD类型
    RECORD类型可以存储由多个列值组成的一行数据。声明记录类型变量之前,需要先定义记录类型,然后才可以声明记录类型的变量。记录类型是一种结构化的数据类型,使用type语句进行定义。
    语法格式如下:

    type record_type is record
    (
    var_member1 data_type[not null][:=default_value],
    ...
    var_member data_type[not null][:=default_value]
    )
    

    3)%ROWTYPE类型
    %ROWTYPE类型结合“%TYPE类型”和“记录类型”变量的优点,它可以根据数据表中行的结构定义一种特殊的数据类型,用来存储从数据表中检索到的一行数据。语法形式如下:

    rowVar_name table_name%rowtype
    

    可以把“table_name%rowtype”看作是一种能够存储表中一行数据的特殊类型。

    2.3定义变量和常量

    1)定义变量
    语法格式:

    <变量名><数据类型>[(长度):=<初始值>];
    

    2)定义常量
    语法格式:

    <变量名>constant<数据类型>:=<常量值>;
    

    3)变量初始化
    PL/SQL定义了一个未初始化变量应该存放的内容,其被赋值未NULL。

    2.4 PL/SQL表达式

    1)字符表达式
    唯一的字符运算符就是并置运算符“||”,它的作用是把几个字符连在一起。例如'Hello'||'World'||'!'的值就是'Hello World!'

    2)布尔表达式
    布尔表达式是一个判断结果为真还是为假的条件。它的值只有TRUE、FALSE、NULL。例如:(x>y)、NULL、(4>5)OR(-1<0)
    布尔表达式由3个布尔运算符:AND、OR和NOT。它们的操作对象是布尔变量或表达式。
    布尔表达式的算术运算符有:=、<、<=、!=、>、>=
    此外,between操作符可以划定一个范围,在范围内为真,否则为假。如:1 between 0 and 100 表达式的值为真。
    IN操作符判断一个元素是否数据某个集合。如:'Scott'IN('Mike'、'Jone'、'Mary')为假。

    3、流程控制语句

    3.1 选择语句

    1)IF...THEN语句

    if <condition_expression> then
      plsql_sentence;
    end if
    

    2)IF...THEN...ELSE语句

    if <condition_expression> then
      plsql_sentence_1;
    else
      plsql_sentence_2;
    end if
    

    3)IF...THEN...ELSIF语句

    if <condition_expression1> then
      plsql_sentence_1;
    elsif<condition_expression> then
      plsql_sentence_2;
    ...
    else
      plsql_sentence_n;
    end if
    

    4)CASE语句

    case<selector>
      when<expression_1> then plsql_sentence_1;
      when<expression_2> then plsql_sentence_2;
      ...
      when<expression_n> then plsql_sentence_n;
      [else plsql_sentence;]
    end case;
    

    3.2 循环语句

    1)LOOP语句
    LOOP语句先执行一次循环体,然后判断‘EXIT WHEN’关键字后面的条件表达式的值是true还是false。如果是true,退出循环体。如果是false,再次执行循环体。

    loop
      plsql_sentence;
      exit when end_condition_exp
    end loop;
    

    2)WHILE语句

    while condition_expression loop
      plsql_sentence;
    end loop;
    

    3)FOR语句

    for variable_counter_name in[reverse] lower_limit...upper_limit loop
      plsql_sentence;
    end loop;
    

    4)GOTO语句
    无条件转向语句。

    GOTO label;
    

    4、PL/SQL游标

    游标提供了一种从表中检索数据并进行操作的灵活手段,游标主要用在服务器上,处理由客户端发送给服务器端的SQL语句,或是批处理、存储过程、触发器中的数据处理请求。游标的作用就相当于指针,通过游标PL/SQL程序可以一次处理查询结果集中的一行,并可以对该行数据执行特定操作,从而为用户在处理数据的过程中提供了很大方便。

    4.1 基本原理

    游标操作数据主要包含显式游标和隐式游标。
    显式游标是由用户声明和操作的一种游标;隐式游标是Oracle为所有数据操纵语句(包括只返回单行数据的查询语句)自动声明和操作的一种游标。

    4.2 显式游标

    显式游标是由用户声明和操作的一种游标,通常用于操作查询结果集(即由SELECT语句返回id查询结果)。
    使用它处理数据的步骤:声明游标、打开游标、读取游标和关闭游标。其中读取游标可能是一个反复操作的步骤,因为游标每次只能读取一行数据,所以对于多条记录,需要反复读取,直到游标读取不到数据为止。

    1)声明游标
    语法格式:

    cursor cur_name[input_parameter1[,input_parameter2]...]
    [return ret_type]
    is select_sentence;
    

    2)打开游标
    语法格式:

    open cur_name[(para_value1[,para_value1]...)]
    

    打开游标就是执行定义的select语句。执行完毕,查询结果装入内存,游标停在查询结果的首部。
    3)读取游标
    读取游标就是逐行将结果集中的数据保存到变量中。语法格式如下:

    fetch cur_name into {variable};
    

    刚刚打开游标时,指针指向结果集中的第一行,当使用FRTCH...INTO语句读取数据完毕,游标指针自动指向下一行数据。此时循环结构中使用FRTCH...INTO语句,每次循环都会从结果集中读取一行数据,直至指针指向结果集中最后一条记录之后为止。
    4)关闭游标
    语法格式:

    close cur_name;
    

    举例:

    set serveroutput on
    declare
    /*声明游标*/
      cursor cur_emp(var_job in varchar2:='SALESMAN')
        is select empno,ename,sal
           from emp
           where job=var_job;
    
      type record_emp is record --声明一个记录类型
        (
        /*定义当前记录的成员变量*/
        var_empno emp.empno%type,
        var_ename emp.ename%type,
        var_sal emp.sal%type
        );
      emp_row record_emp;--声明一个record_emp类型的变量
    
    begin
      open cur_emp('MANAGER');      --打开游标
      fetch cur_emp into cur_row; --先让指针指向结果集的第一行,并把值保存在cur_row中
      while cur_emp%found loop
        dbms_output.put_line(cur_row.var_ename||'的编号是'||cur_row.var_empno||',工资是'||cur_row.var_sal)
        fetch cur_emp into cur_row;  --让指针指向结果集的下一行,并把值保存在cur_row中
      end loop;
      close cur_emp;  --关闭游标
    
    end;
    

    4.3 隐式游标

    在执行一个SQL语句时,Oracle会自动创建一个隐式游标。
    隐式游标主要是处理数据操纵语句(如UPDATE、DELETE)的执行结果,当特殊情况下,也可以处理SELECT语句的查询结果。
    由于隐式游标也有属性,当使用隐式游标的属性时,需要在属性前面加上隐式游标的默认名称--SQL。
    举例如下

    set serveroutput on
    begin
      update emp
      set sal=sal*(1+0.2)--把销售员的工资上调20%
      where job='SALESMAN';
      if sql%notfound then --如果update语句没有影响到任何一条数据
         dbms_output.put_line('没有雇员需要上调工资')
      else  --如果update语句至少影响到一条数据
         dbms_output.put_line('有'||sql%rowcount||'个雇员工资上调20%');
      end if;
    end;
    

    4.4 游标的属性

    1)是否找到游标(%FOUND)
    该属性表示当前游标是否指向有效一行,若是则值为TRUE,否则值为FALSE。
    检查此属性可以判断是否结束游标使用。

    open cur_emp;   --打开游标
    fetch cur_emp into var_ename,var_job;  --将第一行数据放入变量中,游标后移
    loop 
      exit when not cur_emp%found;
    end loop;
    

    在隐式游标中此属性的引用方法是SQL%FOUND。

    delete from emp where empno=emp_id;--emp_id为一个有值变量
    if SQL%FOUND then  --如果删除成功,写入SUCCESS表中该行员工编码
      insert into success values(empno);
    else      --如果删除不成功,写入fail表中该行员工编码
      insert into fail values(empno);
    

    2)是否没找到游标(%NOTFOUND)
    该属性与%FOUND属性类型相似,但其值恰好相反。

    open cur_emp;   --打开游标
    fetch cur_emp into var_ename,var_job;  --将第一行数据放入变量中,游标后移
    loop 
      exit when cur_emp%notfound;
    end loop;
    

    在隐式游标中此属性的引用方法是SQL%NOTFOUND。

    delete from emp where empno=emp_id;--emp_id为一个有值变量
    if SQL%NOTFOUND then  --如果删除不成功,写入fail表中该行员工编码
      insert into fail values(empno);
    else      --如果删除成功,写入sucess表中该行员工编码
      insert into sucess values(empno);
    

    3)游标行数(%ROWCOUNT)
    该属性记录了游标抽取过的记录行数,也可以理解为当前游标所在的行数。

    loop 
      fetch cur_emp into var_ename,var_job;  --将一行数据放入变量中,游标后移
      exit when cur_emp%ROWCOUNT=10;--只抽取10条记录
    end loop;
    

    4)游标是否打开(%ISOPEN)
    该属性表示游标是否处于打开状态。

    IF cur_emp%ISOPEN THEN
      fetch cur_emp into var_ename,var_job; 
    ELSE
      OPEN cur_emp;
    END IF;
    

    在隐式游标中此属性的引用方法是SQL%ISOPEN。在隐式游标中SQL%ISOPEN属性总为TRUE。因此在隐式游标中不用打开和关闭游标,也不用检查游标状态。

    5)参数化游标
    在定义游标时,可以带上参数,使得在游标使用时,根据参数不同所选中的数据行也不同,达到动态使用的目的。

    set serveroutput on
    declare
    var_ename varchar2(50);--声明变量,用来存储雇员名称
    var_job varchar2(50);--声明变量,用来存储雇员职务
    /*声明游标,检索指定员工编号的雇员信息*/
    cursor cur_emp    --定义游标,检索指定员工编号的雇员信息
    is select ename,job
      from emp
      where empno=7499;
    
    begin
      open cur_emp;   --打开游标
      fetch cur_emp into var_ename,var_job;  --读取游标,并存储雇员名称和职务
      if cur_emp%found then --若检索到数据,则输出雇员信息
         dbms_output.put_line('编号为7499的雇员名称为:'||var_ename||',职务是:'||var_job)
      else  --提示无记录信息
         dbms_output.put_line('无数据记录');
      end if;
    end;
    

    4.5 游标变量

    前面所讲的游标都是与一个SQL语句相关联,并且编译该块的时候此语句已经是可知的,是静态的。
    游标变量可以在运行时与不同的语句关联,是动态的。
    游标变量被用于处理多行的查询结果集。
    在同一个PL/SQL块中,游标变量不同于特定的查询绑定,而是在打开游标时才能确定所对应的查询。因此游标变量可以一次对应多个查询。
    在使用游标变量之前,必须先声明游标变量。
    1)声明游标变量
    游标变量是一种引用类型。在程序运行时,可以指向不同的存储单元。
    定义游标变量:

    TYPE <类型名> is REF  CURSOR
    RETURN <返回类型>
    

    <类型名>表示新的引用类型名字,<返回类型>是一个记录类型,指明最终由游标变量返回的选择列表的类型。

    declare 
    --定义非受限游标变量
    TYPE t_FlexibleRef IS REF CURSOR;
    --游标变量
    V_CURSORVar t_FlexibleRef;
    

    2)打开游标变量
    如果要将一个游标变量与一个特定的SELECT语句相关联,需要使用OPEN FOR语句,其语法格式是:

    OPEN <游标变量> FOR <SELECT语句>
    

    如果游标变量是受限的,则SELECT语句的返回类型必须与游标所限的记录类型匹配。

    declare 
    --定义受限游标变量
    TYPE t_StudentRef IS REF CURSOR
    RETURN STUDENTS%ROWTYPE;
    --游标变量
    V_STUDENTVar t_StudentRef;  --定义新的记录类型
    
    BEGIN
      OPEN V_STUDENTVar  FOR
      SELECT * FROM STUDENTS;
    END;
    

    3)关闭游标变量
    CLOSE语句。

    4.6 通过for语句循环游标

    1)隐式游标

    set serveroutput on
    begin
      for emp_record in(select empno,ename,sal from emp where job='SALESMAN')--遍历隐式游标中的记录
      loop                                                 --遍历雇员信息
        dbms_output.put('雇员编号:'||emp_record.empno);  --输出雇员编号
        dbms_output.put(';'||'雇员名称:'||emp_record.empno);--输出雇员名称
        dbms_output.put(';'||'雇员工资:'||emp_record.empno);--输出雇员工资
      end loop;
    end;
    

    2)显式游标

    set serveroutput on
    declare
      cursor cur_emp is
      select * from emp
      where depno=30    --检索部门编号为30的雇员
    begin
      for emp_record in cur_emp --遍历显式游标中的记录
      loop                                                 --遍历雇员信息
        dbms_output.put('雇员编号:'||emp_record.empno);  --输出雇员编号
        dbms_output.put(';'||'雇员名称:'||emp_record.empno);--输出雇员名称
        dbms_output.put(';'||'雇员工资:'||emp_record.empno);--输出雇员工资
      end loop;
    end;
    

    5、PL/SQL异常处理

  • 相关阅读:
    技术学习博2
    正则匹配两个特定词组中间的内容的写法
    springboot mitre HTTP Proxy Servlet POST hang timeout 不执行的解决方案
    JAVA实现的HTTP反向代理 [smiley-http-proxy-servlet]学习
    get方式url传递map的写法,control传入map数据url格式&params[key]=value&params[key2]=value2
    angular7 学习笔记记录--1. TypeScript基础
    Operator '>' cannot be applied to types 'boolean' and 'number'?
    记录在linux环境redis如何重启版本5.x
    ElasticSearch (with docker )入门学习
    Dataway【实测】,让服务飞起来,让SpringBoot不再需要Controller、Service、DAO、Mapper
  • 原文地址:https://www.cnblogs.com/bbn0111/p/15024209.html
Copyright © 2011-2022 走看看