Oracle day 08 火推

来源:互联网 发布:类似招联好期贷的软件 编辑:程序博客网 时间:2024/05/18 13:10


GOTO语句

作用: 当前代码执行时, 跳转到标签位置 继续执行 

标签定义语法格式: <<标签名>> 

GOTO语法格式:goto 标签名


set serveroutput on;
declare

begin
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('上山打老虎');
    dbms_output.put_line('老虎没打到');
    dbms_output.put_line('打到小松鼠');
    goto a;
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('代码执行完毕');
    <<a>>
end;
/   
end语句前, 必须是一行可执行代码

我们上面的案例中, 最后一行是标签 , 程序报错, 说end出现的时机不对 !

如果我们的逻辑 确实已经完毕了 , 我们可以通过空行来实现最后一行代码的添加 !
NULL;

上述案例 改造后:
set serveroutput on;
declare

begin
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('上山打老虎');
    dbms_output.put_line('老虎没打到');
    dbms_output.put_line('打到小松鼠');
    goto a;
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('代码执行完毕');
    <<a>>
    NULL;
end;
/
使用goto模拟循环: 
    我们循环输出10首相同的打油诗


set serveroutput on;
declare
var_count number :=0;
begin
    <<a>>
    var_count := var_count+1;
    dbms_output.put_line('一二三四五');
    dbms_output.put_line('上山打老虎');
    dbms_output.put_line('老虎没打到');
    dbms_output.put_line('打到小松鼠');
    if var_count!=10 then
        goto a;
    end if;
    dbms_output.put_line('代码执行完毕,当前count为:'||var_count);

    NULL;
end;
/
游标 对象

概念:  Java中也存在结果集(游标) (ResultSet)

游标就是查询结果的容器

使用步骤与语法: 

1.  声明一个游标

    申明区中定义: 
        cursor 游标变量名称 is 查询语句;

2.  打开游标
    在执行区操作:

        open 游标变量名称;

3.  游标下移, 并提取一行数据

    fetch 游标变量名称 into  变量; 
    --如果结果集中存在的数据格式为一列多行数据 , 可以赋值给基本数据类型 (number  varchar2....)
    --更多情况下, 我们是赋值给了 record类型

4.  关闭游标

    close 游标变量名称;

        --原因: 释放数据库连接句柄 , 连接句柄数量1024
        --与Java中资源释放很像,  已经释放的资源 不可重复释放 !
定义一个游标, 结果集是s_emp表中的id,last_name,salary, 然后提取游标的前5条数据, 并打印到控制台 .

set serveroutput on;
declare
    --声明游标
    cursor s_emp_cursor is select id,last_name,salary from s_emp;
    --定义record , 用来存储游标中取出的数据
    type myemp is record(
        id s_emp.id%type,
        last_name s_emp.last_name%type,
        salary s_emp.salary%type
    );
    --定义一个record类型的 变量
    var_myemp myemp;

begin
    --打开游标
    open s_emp_cursor;
    --循环取出前五条
    for i in 1..5 loop
        --  游标向下移动一行, 并取出这行数据
        fetch s_emp_cursor into var_myemp;
        dbms_output.put_line('员工编号:'||var_myemp.id||',姓名:'||var_myemp.last_name||',月薪:'||var_myemp.salary);
    end loop;
    --关闭游标
    close s_emp_cursor;
end;
/
通过游标%rowtype得到与游标属性一致的record变量

--改造上述的案例

set serveroutput on;
declare
    --定义游标
    cursor s_emp_cursor is select id,last_name,salary from s_emp;
    --定义了一个与游标中属性一致的 record类型的变量
    var_myemp s_emp_cursor%rowtype;
begin
    --打开游标
    open s_emp_cursor;
    --循环取出游标前五条
    for i in 1..5 loop
        --  游标向下移动一行, 并取出移动后行的数据赋值给var_myemp变量
        fetch s_emp_cursor into var_myemp;
        dbms_output.put_line('员工编号:'||var_myemp.id||',姓名:'||var_myemp.last_name||',月薪:'||var_myemp.salary);
    end loop;
    --关闭游标
    close s_emp_cursor;
end;
/
通过游标获取 多个表格中的数据

查询s_dept表和s_region表 , 通过游标取出数据 , 并显示

set serveroutput on;
declare
    cursor s_dr_cursor is select d.id dr_id,d.name dname,r.name rname from s_dept d,s_region r where d.region_id=r.id;

    var_dr s_dr_cursor%rowtype;
begin
    open s_dr_cursor;
    fetch s_dr_cursor into var_dr;
    dbms_output.put_line('部门编号:'||var_dr.dr_id||',部门名称:'||var_dr.dname||',所在地区:'||var_dr.rname);
    close s_dr_cursor;
end;
游标属性

使用这些属性 可以完成循环遍历的操作

1.  游标变量%found
    在游标下移后 提取到了新数据 ,则返回true , 否则返回false

2.  游标变量%notfound
    在游标下移后, 未提取到新数据, 则返回true , 否则返回false


-   上述的属性, 使用的前提条件: 

    1.  游标必须是已经打开的 . 否则会报错 : 非法游标
    2.  游标必须执行过下移操作(fetch) ,否则返回null
循环遍历游标

set serveroutput on;
declare
    cursor s_dr_cursor is 
        select d.id dr_id,d.name dname,r.name rname from s_dept d,s_region r where d.region_id=r.id;

    var_dr s_dr_cursor%rowtype;
begin
    open s_dr_cursor;
    loop
        fetch s_dr_cursor into var_dr;
        --如果上次提取数据失败, 则退出循环
        exit when s_dr_cursor%notfound;
        dbms_output.put_line('部门编号:'||var_dr.dr_id||',部门名称:'||var_dr.dname||',所在地区:'||var_dr.rname);
    end loop;
    close s_dr_cursor;
end;
练习: 改造上述循环游标案例, 使用while循环完成:

set serveroutput on;
declare
    cursor s_dr_cursor is select d.id dr_id,d.name dname,r.name rname from s_dept d,s_region r where d.region_id=r.id;

    var_dr s_dr_cursor%rowtype;
begin
    open s_dr_cursor;
fetch s_dr_cursor into var_dr;
    while s_dr_cursor%found loop        
        dbms_output.put_line('部门编号:'||var_dr.dr_id||',部门名称:'||var_dr.dname||',所在地区:'||var_dr.rname);
  fetch s_dr_cursor into var_dr;
end loop;

    close s_dr_cursor;
end;


-   1.  什么是循环条件
        循环条件 指的是  当条件结果为true时, 循环继续!

-   2.  什么是退出循环条件

        退出循环条件 指的是  当条件结果为true时, 循环结束
游标其它属性:

int[] arr = {1,2,3,4,5};

1.  isopen : 判断游标是否打开   boolean类型, 无法参与字符串的拼接
2.  rowcount: 获取当前游标所在的行的偏移量

set serveroutput on;
declare
    cursor s_dr_cursor is select d.id dr_id,d.name dname,r.name rname from s_dept d,s_region r where d.region_id=r.id;

    var_dr s_dr_cursor%rowtype;
begin
    open s_dr_cursor;
fetch s_dr_cursor into var_dr;
    while s_dr_cursor%found loop        
        dbms_output.put_line('部门编号:'||var_dr.dr_id||',部门名称:'||var_dr.dname||',所在地区:'||var_dr.rname);
        -- 输出当前游标的打开状态
  if s_dr_cursor%isopen then
        dbms_output.put_line('当前游标打开');
  end if;
        --  输出当前的偏移量
        dbms_output.put_line('当前游标的偏移:'||s_dr_cursor%rowcount);
  fetch s_dr_cursor into var_dr;
end loop;

    close s_dr_cursor;
end;
智能循环 遍历游标

for循环遍历游标时 

    -   自动定义record变量
    -   自动打开游标
    -   自动提取数据赋值给record变量
    -   自动关闭游标


set serveroutput on;
declare
    cursor s_dr_cursor is select d.id dr_id,d.name dname,r.name rname from s_dept d,s_region r where d.region_id=r.id;

begin
    for var_dr in s_dr_cursor loop
        dbms_output.put_line('部门编号:'||var_dr.dr_id||',部门名称:'||var_dr.dname||',所在地区:'||var_dr.rname);
    end loop;
end;
带参数的游标

一个游标在定义时, 可以指定游标打开时需要传递的参数 , 这个参数 可以应用到select语句中

格式 

    1.  定义游标时, 设置形式参数列表
        cursor 游标变量名称(参数列表) is select语句;
    2.  打开游标时, 传递实际参数
        open 游标变量名称(参数);

练习: 

    --根据用户输入的员工编号, 查询一个员工的信息(id,last_name,salary): 

    set serveroutput on;
    declare
        cursor myemp_cursor(var_id number) is select id,last_name,salary from s_emp where id = var_id;

        var_me myemp_cursor%rowtype;
        var_id number;
    begin
        var_id := &请输入您要查询的员工的id;
        open myemp_cursor(var_id);
        fetch myemp_cursor info var_me;
        dbms_output.put_line('员工的编号:'||var_me.id||',员工的姓名:'||var_me.last_name||',月薪:'||var_me.salary);
    end;
    /
使用智能循环时, 如何传递参数 

之前我们说, for循环 会自动打开游标

--根据用户输入的员工编号, 查询比这个编号小的员工的信息(id,last_name,salary): 

    set serveroutput on;
    declare
        cursor myemp_cursor(var_id number) is select id,last_name,salary from s_emp where id < var_id;


        var_id number;
    begin
        var_id := &请输入您要查询的员工的id;

        for var_me in myemp_cursor(var_id) loop
            dbms_output.put_line('员工的编号:'||var_me.id||',员工的姓名:'||var_me.last_name||',月薪:'||var_me.salary);
        end loop;

    end;
    /
参考游标 ref cursor

参考游标在声明时, 无需指定select语句.  在打开游标时 根据需求,传入指定的SQL语句!

语法格式: 

    1.  先声明类型-申明区
        type 自定义的名称(参考游标类名) is ref cursor;

    2.  再声明游标的变量-申明区
        变量名 自定义的名称(参考游标类名);

    3.  打开游标-执行区
        open 变量名 for '查询语句';
    ......

    --------------------------

    对比之前的操作: 
    1.  声明游标(得到变量)
        申明区
        cursor 变量名称 is 查询语句;


    后续操作与普通游标一致
练习: 

根据用户输入的操作类型, 来提示用户进行不同的操作查询:

set serveroutput on;
declare
    --定义参考游标类型名
    type mycursor is ref cursor;
    --  定义参考游标变量
    var_mycursor1 mycursor;
    --用来存储查询语句的字符串, 根据用户操作的不同, 赋予不同的查询语句
    var_SQL varchar2(500);
    --接收用户输入的操作类型
    var_type number;
    --接收用户输入的id参数
    var_id number;
    --定义变量
    var_salary number;
    var_name varchar2(25);
begin
    dbms_output.put_line('欢迎进入公司管理系统: ');
    dbms_output.put_line('请根据提示, 输入您的操作');
    var_type := &查询员工信息输入1查询部门信息输入2;
    if var_type=1 then
        --查询用户信息
        --1.提示用户输入要查询的员工id
        var_id := &请输入您要查询的员工编号;
        --  根据用户输入的内容 拼接处一个查询语句,并赋值给var_SQL
        var_SQL :='select salary from s_emp where id='||var_id;
        --  打开游标 并传递SQL语句
        open var_mycursor1 for var_SQL;
        --  从游标中取出数据,并打印
        fetch var_mycursor1 into var_salary;
        dbms_output.put_line('您查询的员工的工资为:'||var_salary);

    elsif var_type=2 then
    --查询部门信息
        --1.    提示用户输入要查询的部门编号
        var_id := &请输入您要查询的部门编号;
        -- 根据用户输入的部门编号, 来拼接SELECT语句
        var_SQL := 'select name from s_dept where id='||var_id;
        --  打开游标, 传递SQL语句
        open var_mycursor1 for var_SQL;
        --  从游标中取出数据 , 并打印
        fetch var_mycursor1 into var_name;
        dbms_output.put_line('您查询的部门名称为:'||var_name);


    else
    dbms_output.put_line('你是不是撒 , 脑袋有坑 !');
    end if;
end;

NULL值的比较

在PL/SQL中 null值参与判断的操作中, 所有情况都不会匹配, 只能进入else块

注意不要混淆:
    在SQL中, 对查询结果进行排序时, NULL值是最大的

set serveroutput on;
declare
    var_a number;
    var_b number;
begin


    if var_a>var_b then
        dbms_output.put_line('a大');
    elsif var_a=var_b then
        dbms_output.put_line('相等');
    elsif var_a!=var_b then
        dbms_output.put_line('不想等');
    elsif var_a<var_b then
        dbms_output.put_line('b大');
    else
        dbms_output.put_line('哈哈哈哈哈');
    end if;
    dbms_output.put_line('代码之行结束');

end;
/
异常处理

1.  编译时异常
    语法格式的问题
2.  运行时异常
    程序在运行时, 发生的一些异常
演示运行时异常的出现

set serveroutput on;
declare
    var_last_name s_emp.last_name%type;
begin
    select last_name into var_last_name from s_emp where id=-1;
    dbms_output.put_line(var_last_name);
end;
/

出现了异常   "no data found"
异常处理格式:

begin

exception

    --出现异常后,  这里的代码才会执行
    when 异常类型1 then
        --异常处理块
    when 异常类型2 then
        --异常处理块
    ...

    when 异常类型n then
        --异常处理块
    when others then
        --当上面的异常类型都不匹配时, 执行这里处理异常

end;
/
使用上述的格式, 处理上述代码的异常

set serveroutput on;
declare
    var_last_name s_emp.last_name%type;
begin
    select last_name into var_last_name from s_emp where id=-1;
    dbms_output.put_line(var_last_name);

exception
    when others then
    dbms_output.put_line('出现了异常, 哈哈哈哈哈哈哈哈啊哈哈哈哈哈哈哈');
end;
/

异常被解决
--针对异常类型 进行处理

set serveroutput on;
declare
    var_last_name s_emp.last_name%type;
begin
    select last_name into var_last_name from s_emp where id=-1;
    dbms_output.put_line(var_last_name);

exception
    when no_data_found then
        dbms_output.put_line('出现了异常, 数据找不到');
    when others then
    dbms_output.put_line('出现了异常, 哈哈哈哈哈哈哈哈啊哈哈哈哈哈哈哈');
end;
/
存储过程

把一组逻辑相关的SQL语句/PLSQL语句 组织到一起的一个代码结构 , 我们称之为过程 !
存储过程没有返回值 !


创建存储过程的语法格式: 
    create or replace procedure 名称(形参列表)
    is
        /*申明区*/
    begin

    end;

调用的语法格式:

    方式1.    call 过程名(实参列表);
    方式2.    exec 过程名(实参列表);

删除存储过程
    drop procedure 存储过程名称;
练习

通过之前所学习的匿名块的编写,  编写一个案例,  比较两个数字的大小, 将大的数字输出 !

set serveroutput on;
declare
    var_a number :=100;
    var_b number :=-100;

begin
    if var_a>var_b then
        dbms_output.put_line('a大');
    elsif var_a<var_b then
        dbms_output.put_line('b大');
    else
        dbms_output.put_line('没有谁大谁小');         
    end if;
end;
根据上述的存储过程的语法格式, 将匿名块修改为存储过程, 并尝试调用

    create or replace procedure mymax(var_a number,var_b number)
    is
    begin
        if var_a>var_b then
            dbms_output.put_line('a大');
        elsif var_a<var_b then
            dbms_output.put_line('b大');
        else
            dbms_output.put_line('没有谁大谁小');         
        end if;
    end;
    /

编译完毕上述的存储过程后, 调用
set serveroutput on;
call mymax(100,200);

drop procedure mymax;
给参数添加默认值

    create or replace procedure mymax(var_a number:=500,var_b number:=1000)
    is
    begin
        if var_a>var_b then
            dbms_output.put_line('a大');
        elsif var_a<var_b then
            dbms_output.put_line('b大');
        else
            dbms_output.put_line('没有谁大谁小');         
        end if;
    end;
    /

    set serveroutput on;
    call mymax();
在匿名块中调用存储过程

set serveroutput on;
begin
    mymax();
end;
/
通过desc 查看存储过程

desc mymax;

参数名       类型         In/Out  默认值     
-----   ------      ------ ------- 
VAR_A   NUMBER        IN    DEFAULT(存在默认值) 
VAR_B   NUMBER        IN    DEFAULT(存在默认值)  

In/Out:
    参数的模式 , 默认为in , 指的是参数是否允许存储过程进行修改参数数据 !

    取值: 
        -   in: 默认模式, 表示参数只读
        -   out:表示参数只写
        -   in out: 可读可写
    如果指定了参数的模式为 out/in out , 参数在传递时, 必须时变量!
改造上述的代码, 添加一个返回参数

mymax存储过程, 存在三个形式参数, 1. number  2.number  3. number
    比较1和2的大小, 将大的数据 存储到3的位置

create or replace procedure mymax(var_a number:=500,var_b number:=1000,var_max out number)
    is
    begin
        if var_a>var_b then
            var_max := var_a;
        elsif var_a<var_b then
            var_max := var_b;
        else
            var_max := var_a;   
        end if;
    end;
    /

    set serveroutput on;
    declare
        var_max number;
    begin
        mymax(100,101,var_max);
        dbms_output.put_line('mymax返回了数据, 值为:'||var_max);
    end;
练习:
    1.  mymax存储过程, 存在2个形式参数, 1. number  2.number  
        比较1和2的大小, 
        将大的数据 存储到2的位置

    2.  mymax存储过程, 存在2个形式参数, 1. number  2.number  
        比较1和2的大小, 
        将大的数据 存储到2的位置, 将两个数的和存储到1的位置
根据参数名称传递参数

语法格式: 

    参数名称=>传递的值

create or replace procedure mymax(var_a number:=500,var_b number:=1000,var_max out number)
    is
    begin
        if var_a>var_b then
            var_max := var_a;
        elsif var_a<var_b then
            var_max := var_b;
        else
            var_max := var_a;   
        end if;
    end;
    /

    set serveroutput on;
    declare
        var_max number;
    begin
        mymax(var_a=>100,var_max);
        dbms_output.put_line('mymax返回了数据, 值为:'||var_max);
    end;
函数

public static void getXXX(int a,int b,HashMap<String,Object> data){
    if(a>b){
        data.put("max",a);
    }else{
        data.put("max",b);
    }
}