zoukankan      html  css  js  c++  java
  • 游标(cursor)--显式游标&隐式游标、游标四个属性、循环遍历

    https://blog.csdn.net/qq_36743482/article/details/79354036

    1.1 cursor是什么
    cursor是光标,游标的意思。比如我们的鼠标的光标就是cursor。
    那么在数据库中cursor是什么呢?
    当运行DML(select,update,insert,delete)语句时,ORACLE会在内存中为其分配缓冲区(Context Area),PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域。
    游标在运行DML语句时打开,完成后关闭。
    通俗的说:
    我们知道,select语句会产生一个结果集,而游标是指在这个结果集上的第一条记录的一个指针。
    而我们每次取出(fetch)一条记录,cursor就会自动指向下一条记录。
    如果学过Java的话,可以这样理解,cursor类似于Java中的迭代器iterator。

    1.2 cursor作用
    基于以上的理解,cursor自然就被用于:取出每一条记录,遍历结果集。

    1.3 cursor的四个属性
    cursor有如下四个属性:

    %isopen:布尔类型。判断游标是否打开,打开为true。对于隐式游标而言,这个值总是false,因为隐式游标在DML语句执行时打开,结束时就立即关闭。
    %found:布尔类型。在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL。在执行DML语句后,SQL%FOUND的属性值将是:

      . TRUE :INSERT
      . TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
      . TRUE :SELECT INTO至少返回一行

    %notfound:布尔类型。当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE

    %rowcount:数值类型。在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功,SQL%ROWCOUNT的值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND。
    注:PLSQL中的布尔类型的值为null、true、false。

    2.显式游标和隐式游标
    在游标声明之前,我们来看下显式游标和隐式游标。

    2.1 隐式游标
    事实上,当我们在PLSQL中进行非查询(或者返回单条记录的查询)语句,如update、delete、insert等时,ORACLE 系统会自动地为这些操作设置游标并创建其工作区,并且隐式游标的名字为SQL,由ORACLE 系统定义。
    对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。
    PL/SQL管理隐式游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。
    用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。
    简单实例
    对于如下一张表ljb_test,更新每个人的薪水:


    set serveroutput on;
    begin
    update ljb_test set salary = salary + 1;
    dbms_output.put_line('更新了'||SQL%rowcount||'行数据'); --must before commit
    commit;
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    结果如下:


    这里需要指出的是:关于隐式游标的属性操作,必须在commit之前,可以尝试把打印输出放在commit之后,得到的结果是0。这里之所以结果加了2,是因为我实验了两次。

    2.2 显式游标
    当查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。
    显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。
    这里要做一个声明,我们所说的游标通常是指显式游标,而显式游标需要被声明。

    2.2.1 cursor的声明、打开、关闭、从游标提取数据
    声明游标

    CURSOR cursor_name IS select_statement;
    1
    打开游标

    OPEN cursor_name;
    1
    关闭游标

    CLOSE cursor_name;
    1
    从游标提取数据
    从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。
    语法如下:

    FETCH cursor_name INTO variable[,variable,...]
    1
    如:

    set serveroutput on;
    declare
    cursor c is select * from ljb_test; --1.声明游标的时候Oracle不会从数据库中取数据
    v_test c%rowtype;
    begin
    open c; --2.打开游标,此时从数据库中取数据,并把结果集放在内存中
    fetch c into v_test; --3.获取数据,fetch的时候游标自动往下移动一格
    dbms_output.put_line(v_test.name);

    fetch c into v_test;
    dbms_output.put_line(v_test.name);
    close c; --4.关闭游标,清掉内存。成对编程
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    命令行运行,结果如下:


    2.2.2 遍历结果集
    如果我们想要遍历整个测试表,显然需要通过循环来进行。
    正常情况下如果遵循循环遍历游标应当遵从以下步骤:
    1、打开游标
    2、开始循环
    3、从游标中取值
    4、检查那一行被返回
    5、处理
    6、关闭循环
    7、关闭游标
    事实上,我们确实可以通过该方式实现,即通过while循环和do while循环。
    但是,for循环却不无需这么复杂,这里我们重点介绍for循环。
    上文提到,PLSQL中有三种循环,这里需要指出的是,使用游标遍历时,最简单最稳定的就是for循环,但另外两种循环仍然会做简单介绍。如下:

    2.2.2.1 for循环遍历
    FOR循环的游标按照正常的声明方式声明,但是不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。
    for循环是最简单也是最不容易出错的方式,推荐采用for循环遍历。

    set serveroutput on;
    declare
    cursor c is select * from ljb_test;
    --无需在此声明变量v_test
    begin
    --无需显式打开游标
    for v_test in c loop
    --无需显式fetch
    dbms_output.put_line(c%rowcount||'--'||v_test.name);
    end loop;
    --无需显式关闭游标
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    九条记录全部被打印,运行结果如下:


    2.2.2.2 while循环遍历
    declare
    cursor c is select * from ljb_test; --声明游标的时候Oracle不会从数据库中取数据
    v_test c%rowtype;
    begin
    open c; --打开游标,此时从数据库中取数据,并把结果集放在内存中

    fetch c into v_test; --获取数据,fetch的时候游标自动往下移动一格
    while c%found loop
    dbms_output.put_line(c%rowcount||'--'||v_test.name);
    fetch c into v_test;
    end loop;
    close c; --关闭游标,清掉内存。成对编程
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    九条记录被遍历,结果如下:


    如果我们把fetch语句和打印语句调换一下位置,结果会怎样?


    可以看到,第一个记录被跳过取,最后一个打印两边。原因是,我们第一次打印前fetch了两次,而最后一个虽然c无法fetch到数据,但是上一个的c%fetch仍然是true。

    所以,采用while循环一定注意fetch和打印的顺序。do while类似。

    2.2.2.3 do while循环遍历
    declare
    cursor c is select * from ljb_test; --声明游标的时候Oracle不会从数据库中取数据
    v_test c%rowtype;
    begin
    open c;
    loop
    fetch c into v_test;
    exit when(c%notfound);
    dbms_output.put_line(c%rowcount||'--'||v_test.name); --如果顺序反了,就会最后一条记录打印两次
    end loop;
    close c; --关闭游标,清掉内存。成对编程
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13


    2.2.3 含参游标
    类似于函数,我们可以将参数传递给游标并在查询中使用。

    CURSOR cursor_name[(parameter[,parameter],...)]
    IS select_statement;
    1
    2
    参数定义方式为:

    Parameter_name [IN] data_type[{:=|DEFAULT} value]
    1
    需要注意的是:游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。

    declare
    cursor c(v_dep ljb_test.dep%type, v_salary ljb_test.salary%type)
    is select * from ljb_test where dep = v_dep and salary = v_salary;
    begin
    for v_temp in c(3,4000) loop
    dbms_output.put_line(v_temp.name);
    end loop;
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    结果如下:


    2.4 可更新游标
    declare
    cursor c is select * from ljb_test for update; --添加for update即可
    begin
    for v_temp in c loop
    if(v_temp.salary<3500) then
    update ljb_test set salary = salary * 2 where current of c; --更新条件
    elsif(v_temp = 5000) then
    delete from ljb_test where current of c; --更新条件
    end if;
    end loop;
    commit;
    end;
    /
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    ————————————————
    版权声明:本文为CSDN博主「刘金宝_Arvin」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_36743482/java/article/details/79354036

  • 相关阅读:
    微信小程序 --- 获取当前坐标
    微信小程序 --- 缓存数据
    微信小程序 --- 音乐的播放和控制
    微信小程序 --- webSocket
    微信小程序 --- 文件的上传和下载
    微信小程序 --- 选择图片和拍照
    微信小程序 --- loading提示框
    微信小程序 --- toast消息提示框
    Atitit.attilax软件研发与项目管理之道
    Atitit.attilax软件研发与项目管理之道
  • 原文地址:https://www.cnblogs.com/kakaisgood/p/12675132.html
Copyright © 2011-2022 走看看