zoukankan      html  css  js  c++  java
  • (18)PL/SQL

    PL/SQL(Procedure Language/SQL)

    PL/SQL是Oracle对sql语言的过程化扩展---指在sql命令语言中增加了过程处理语句(如分支、循环等),使sql语言具有过程处理能力

    在sqlplus中执行一下操作

    set serveroutput on; --打开sqlplus的输出功能
    

    一、一个完整的格式

    1.只有执行体部分的结构,也就是只有begin ...end 部分

    begin
    dbms_output.put_line('123');
    end; 
    /

    运行后

    斜杠  /  就是让服务器执行前面所写的 SQL 脚本。 因为你普通的 select 语句, 一个分号,就可以执行。

    但是如果你的是存储过程, 那么遇到分号,就不能马上执行。 这个时候,就需要通过 斜杠 来执行

     

    2.包含声明和执行体两部分的结构

     

    declare
    v_result number(8,2);
    begin
    v_result :=100/6;
    dbms_output.put_line('最后的结果是'||v_result );
    end;
    /

    第一行声明变量关键字

    第二行声明变量

    二、注释

    单行注释用     --

    多行注释用    /**/

    三、字符命名规则

    PLSQL能用的字符集包括

    1.大小写字母A-Z,a-z

    2.数字0-9

    3.Tab、空格、回车

    4.数学符号:+,-,*,/,<,>

    5.(),{},[],?,!,;,:,@,#,%,$,&

    其他的字符都是非法字符(除引号里)

    四、基本数据类型

    定义变量时 变量名在前,数据类型在后

    1.数值类型

    number,pls_integer,binaru_integer

    Number类型可以存储整数或浮点数;

    例:Num number(9,2) 

     其中9表示精度,从左边不是零数到小数点后一共有9位,2表示小数点最多两位。这个区间内的的数值都是符合的

    2.字符类型

    varchar2,char,long,nchar,nvarchar2 

    name varchar2(80)   --可变字符串,最大长度4000.

    3.日期类型

     例: pdate  date;

    4.布尔类型

     boolean

    变量的赋值要用:=

    例:  b boolean:=True;

    declare
    count number(5,2);
    name varchar2(20);
    today date;
    begin
    --赋值
    count :=1
    name :='hello';
    today:=sysdate;
    --打印
    dbms_output.put_line(count);
    dbms_output.put_line(name);
    dbms_output.put_line(today);
    end;
    /

    5.特殊数据类型

    (1)引用型变量

    name emp.ename%type;  --把员工表中ename的类型 定义为name的类型
    declare
    name emp.ename%type;
    salary emp.sal%type;
    begin
    --查询出emp表姓名和薪水,并用into赋值给name和salary变量
    select ename,sal into name ,salary  from emp where empno=7839;
    dbms_output.put_line(name ||'的薪水是'||salary );
    end;
    /

    (2)记录型变量

    取一行变量的类型

    declare
    emp_rec emp%rowtype;
    begin
    --查询后把正行的变量名和类型都赋值给emp_rec
    select * into emp_rec from emp where empno=7839;
    dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
    end;
    /

    五、流程控制语句

    选择语句(包括4种)

    1、 if then

     只做一种条件判断

    /* Formatted on 2017/5/20 9:19:56 (QP5 v5.227.12220.39754) */
    set serveroutput on
    DECLARE
    name1 VARCHAR (50);
    name2 VARCHAR (50);
    BEGIN
    name1 := 'abc';
    name2 := 'abcd';
    
    IF LENGTH (name1) < LENGTH (name2)
    THEN
    DBMS_OUTPUT.put_line ('name1的长度小于name2');
    END IF;
    END;
    /

    if条件可判断是否为空或 and or not 等逻辑运算

    set serveroutput on
    DECLARE
    name1 VARCHAR (50);
    name2 VARCHAR (50);
    BEGIN
    name1 := '';
    
    IF name1 is not null
    THEN
    DBMS_OUTPUT.put_line ('name1不为空');
    else
    DBMS_OUTPUT.put_line ('name1为空');
    END IF;
    END;
    /

    2. if then else

     两种判断

    set serveroutput on
    DECLARE
    name1 VARCHAR (50);
    name2 VARCHAR (50);
    BEGIN
    name1 := 'abcde';
    name2 := 'abcd';
    
    IF LENGTH (name1) < LENGTH (name2)
    THEN
    DBMS_OUTPUT.put_line ('name1的长度小于name2');
    else
    DBMS_OUTPUT.put_line ('name1的长度大于name2');
    END IF;
    END;
    /

    3. if then elsif

     多分支判断

    DECLARE
       month   INT := 10;
    BEGIN
       IF month >= 1 AND month <= 3
       THEN
          DBMS_OUTPUT.put_line ('春天');
       ELSIF month >= 4 AND month <= 6
       THEN
          DBMS_OUTPUT.put_line ('夏天');
       ELSIF month >= 7 AND month <= 9
       THEN
          DBMS_OUTPUT.put_line ('秋天');
       ELSIF month >= 10 AND month <= 12
       THEN
          DBMS_OUTPUT.put_line ('冬天');
       ELSE
          DBMS_OUTPUT.put_line ('月份不合法');
       END IF;
    END;
    /

    4. case

    SET SERVEROUTPUT ON
    
    DECLARE
       score   VARCHAR (20) := '';
    BEGIN
       CASE score
          WHEN ''
          THEN
             DBMS_OUTPUT.put_line ('学霸你好');
          WHEN ''
          THEN
             DBMS_OUTPUT.put_line ('命中注定你是个普通人');
          WHEN ''
          THEN
             DBMS_OUTPUT.put_line ('未来的老板');
          ELSE
             DBMS_OUTPUT.put_line ('不要乱赋值');
       END CASE;
    END;
    /

    循环语句(3种)

    1.loop

     先执行一次循环体,然后再判断 exit when 关键字后面的条件表达式的值是ture还是false,如果是true退出循环,如果是flase则继续执行

    SET SERVEROUTPUT ON
    
    DECLARE
       num   INT := 5;
    BEGIN
       LOOP
          DBMS_OUTPUT.put_line ('num=' || num);
          num := num - 1;
          EXIT WHEN num = 2;
       END LOOP;
    
       DBMS_OUTPUT.put_line ('执行完成');
    END;
    /

    2.while

     先判断表达式,在循环。有可能执行0次

    SET SERVEROUTPUT ON
    
    DECLARE
       num   INT := 5;
    BEGIN
       WHILE num >= 1
       LOOP
          DBMS_OUTPUT.put_line ('num=' || num);
          num := num - 1;
       END LOOP;
    
       DBMS_OUTPUT.put_line ('执行完成');
    END;
    /

    3.for

     语法:

    for a in [reverse] b..c 
    loop ...
    end loop;

    a: 整数变量,用来作为计数器,默认计数器循环递增,如果加上了[reverse]  表示循环递减

    b:计数器下限值,当计数器的值小于下限值时,程序循环终止

    c:计数器上限值,当计数器的值大于上限值时,程序循环终止

    SET SERVEROUTPUT ON
    
    DECLARE
       num   INT := 6;
    BEGIN
       FOR i IN 3 .. 5    --i初始值是3,共执行三遍
       LOOP
          DBMS_OUTPUT.put_line ('num=' || num);
       END LOOP;
    
       DBMS_OUTPUT.put_line ('执行完成');
    END;
    /

    六、PL/SQL游标

     在PL/SQL里使用游标代表集合

    1.显示游标

    声明游标

    声明游标要在plsql的declare里

    cursor 游标名[(变量名 in 类型:='')]
    [return 返回值类型]
    is sql语句

    DECLARE
    CURSOR cur_n IS 
    SELECT id,name FROM student WHERE name= 'tom';
    DECLARE
    CURSOR cur_n(name1 in varchar2:='tom') IS--不要指定varchar2的长度,否则报错
    SELECT id,name  FROM student  WHERE name = name1;

    打开游标

    在打开游标的过程中,程序首先将符合条件的记录送人内存中,然后再将指‘针指’向第一条记录

    打开游标要写在begin里

    格式:

    open 游标名[参数]

    open cur_n;
    open cur_n('tom');

    读取游标

    打开游标后,开始读取游标中的数据,读取方式是逐行将结果数据保存到变量中

    格式:

    fetch 游标名 into 变量 

    fetch cur_n into 

    2.游标属性

    无论是显示游标还是隐式游标,都具有 %found %notfound %isopen %rowcount 四个属性

    通过这四个属性可以获知sql语句的执行结果以及该游标的状态信息。

    %found: 布尔型属性,如果SQL语句至少影响到一行数据,则改属性为true,否则为false

    %notfound:与%found功能相反

    %rowcount:数字型属性,返回受sql语句影响的行数

    %isopen:布尔型属性,当游标已经打开时返回true,关闭时则false

    declare
    --定义一个游标集合,指向该结果集的第一行
    cursor cemp is select ename,sal from emp;
    --定义变量
    pename emp.ename%type;
    psal emp.sal%type;
    begin
    --打开游标
    open cemp;
    loop 
    --取游标集合的一条记录
    fetch cemp into pename,psal;
    --游标行无数据时退出
    exit when cemp%notfound;
    dbms_output.put_line(pename||'的薪水是'||psal);
    end loop;
    --关闭游标
    close cemp;
    end;
    /

    3.隐示游标

    4.带参数光标

    带参数的游标就定义的时候和open的时候不带参数的游标有区别

    declare
    --定义一个参数
    cursor cemp(dno number) is select ename from emp where deptno=dno;
    pename emp.ename%type;
    begin
    open cemp(10);--传参
    loop
    fetch cemp into pename;
    exit when cemp%notfound;
    dbms_output.put_line(pename);
    end loop;
    close cemp;
    end;
    /

    5.光标数的限制

    oracle数据库只允许在同一个会话中打开300个光标。

    修改光标数的限制:

    alter system set open_cursors=400 scope=both;--允许400光标

    scope取值有三种:memory(只更改当前实例),spfile(只更改参数文件--数据库需要重启),both(前两者同时更改)

    七、异常

     异常格式:

    exception
    when 异常类型 then
    ...
    when 异常类型 then
    ...
    end;

    预定义异常

    zero_divide:除数为零时引发的异常

    access_into_null:企图为某个未初始化对象的属性赋值

    collection_is_null:企图使用未初始化的集合元素

    cursor_already_open:企图再次打开一个已经打开过的游标,但重新打开之前,游标未关闭

    invalid_number:企图将一个字符串转换成一个无效的数字而失效

    login_denied:企图使用无效的用户名或密码连接数据库

    no_data_found:select into 语句没有返回数据

    rowtype_mismatch:主游标变量与PL/SQL游标变量的返回类型不兼容

    self_is_null:使用对象类型时,使用空对象调用其方法

    subscript_beyond_count:元素下标超过嵌套表或varray的最大值

    subscript_outside_limit: 企图使用非法索引号引用嵌套表或varray中的元素

    sys_invalid_rowid:字符串向rowid转换时的错误,因为该字符串不是一个有效的rowid值

    timeout_on_resource oracle在等待资源时超时

    too_many_rows 执行select into 语句时,结果集超过一行引发的异常

     例:

    no_data_found

    declare
    pename emp.ename%type;
    begin
    select ename into pename from emp where empno=1234;
    exception
    when no_data_found then dbms_output.put_line('未找到该员工');
    --除了上面的异常以外的所有异常
    when others then dbms_output.put_line('其他例外');
    end;
    /

    too_many_rows

    declare
    pename emp.ename%type;
    begin
    --如果返回多行数据会报异常
    select ename into pename from emp where deptno=10;
    exception
    when too_many_rows then dbms_output.put_line('打印了多行');
    --除了上面的异常以外的所有异常
    when others then dbms_output.put_line('其他例外');
    end;
    /

    自定义异常

     

    declare
    cursor cemp is select ename from emp where deptno=99;
    pename emp.ename%type;
    --自定义异常
    no_emp_found exception;
    begin
    open cemp;
    fetch cemp into pename;
    if cemp%notfound then
    --抛出异常
    raise no_emp_found;
    -- 当发生异常后,oracle调用close自动关闭
    close cemp;
    exception
    whenno_emp_found then dbms_output.put_line('没有找到员工');
    when others then dbms_output.put_line('其他例外');
    end;
    /
  • 相关阅读:
    Flutter动画(1)动画基础介绍(重要)
    flutter AnimationController动画1
    flutter 动画示例
    Nginx 搭建图片服务器
    dart中list的map方法获取index
    Flutter 视频缩略图
    Flutter:设置字体不随系统字体大小进行改变
    Flutter 屏幕适配flutter_screenutil使用心得
    flutter 软键盘弹起导致定位底部按钮浮动在键盘上的问题
    C++ 代码小技巧(一)
  • 原文地址:https://www.cnblogs.com/buchizaodian/p/6528358.html
Copyright © 2011-2022 走看看