六、Oracle SQL,游标&RECORD&存过、游标、RECORD整合

8. 游标

8.1 简介

8.1.1 定义

实质上是数据集,类似数组一样,把查询的数据集存储在内存当中。

使用时可以通过游标指向其中一条记录,也可以通过循环游标达到循环数据集的目的。

8.1.2 游标的种类

  • 显式游标:使用之前必须得先声明定义,一般是对查询语句的结果进行定义游标。

    可以通过游标循环获取结果集内的记录,也可以根据业务需求跳出循环结束游标的获取。

    循环完成后,可以通过关闭游标,结果集就不能再获取了。全部操作完全由开发者自己编写完成,自己控制。

  • 隐式游标:指的是PL/SQL自己管理的游标,开发者不能自己控制操作,只能获得它的属性信息。

8.2 显式游标

显式游标在实际开发中经常使用到,可以丰富PL/SQL的开发程序的编写,实现一些循环类的复杂业务。游标的使用步骤如下:

--1.声明游标:
  声明游标指的是给游标命名并给游标关联一个查询结果集
cursor 游标名
is 查询语句

--2.打开游标:
  初始化游标指针
  PS:游标一旦打开后,游标对应的结果集就是静态不会再变了,不管查询的表的基础数据发生了变化。
open 游标名;

--3.读取游标中数据:
  通过fetch into语句完成,把当前游标指针指向的数据行读取到对应的变量中(声明的record变量)。
  PS:游标读取一般和循环LOOP一起使用,用于循环获取数据集中的记录。
fetch 游标名 into 声明的record变量

--4、关闭游标:
  关闭后,该游标关联的结果集就释放了,不能够再操作了
  PS:游标使用完,一定要关闭游标释放资源。
close 游标名;

8.2.1显式游标的属性

我们利用显式游标的属性值来获取游标所处的状态,然后对应做相应的处理,常用的属性有四个:

  • %NOTFOUND 表示游标获取数据的时候是否有数据提取出来,没有数据返回TRUE,有数据返回false,经常被用来判断游标是否全部循环完毕。

  • %FOUND 正好和%NOTFOUND相反,当游标提取数据值时有值,返回TRUE,否则返回FALSE。

  • %ISOPEN 用来判断游标是否打开。

  • %ROWCOUNT 表示当前游标FETCH INTO获取了多少行的记录值,用来做计数用的。

例子:创建一个游标循环打印学生信息表中学生基本信息,代码如下:

--定义游标
declare cursor cur_xsjbxx
is select * from stuinfo order by stuid;
  --定义记录变量  rowtype:用于接受一行数据
  ls_curinfo cur_xsjbxx%rowtype;
begin
    --打开游标
  open cur_xsjbxx;
    --循环
  loop
        --获取记录值并写入计入变量
    fetch cur_xsjbxx into ls_curinfo;
        --当没有数据时不再获取(%NOTFOUND用来判断游标是否全部循环完毕。)
        exit when cur_xsjbxx%notfound;
        --PL/sql中输出信息(相当与java中的System.out.println())
    dbms_output.put_line('学号:' || ls_curinfo.stuid || ',姓名:' || ls_curinfo.stuname);
  end loop;
    --关闭游标
  close cur_xsjbxx;
end;

8.3 隐式游标

  • 隐式游标虽然不能像显式游标一样具有操作性,但是在实际开发过程当中还是经常使用到它的属性值。

  • 隐式游标主要是用在select语句或一些dml操作语句时,PL/SQL程序会自动打开隐式游标,这个隐式游标是不受开发者控制的。

  • oracle隐式游标没有像显式游标一样声明游标名,而是直接采用“SQL”或“sql”作为隐式游标的名称。

  • 显式游标表示的属性值都是对结果集行数的一些判断,而隐式游标对应的就是DML语句影响的行数。

--隐式游标
declare
  --只定义记录变量,没有声明游标(如果一个表有较多的列,使用%rowtype来定义一个表示表中一行记录的变量)
  ls_xsjbxx stuinfo%rowtype;
begin
  --查询学生信息(select * into把整个表数据设置进定义的记录变量中,用变量来实现游标功能)
  select * into ls_xsjbxx from stuinfo t where t.stuid = 'SC201801001';
  if sql%found then
    dbms_output.put_line('学号:' || ls_xsjbxx.stuid || ',姓名:' || ls_xsjbxx.stuname);
  end if;

  --查询学生信息(不存在的学生)
  select * into ls_xsjbxx from stuinfo t where t.stuid = 'SC201901001';
  if sql%found then
    dbms_output.put_line('学号:' || ls_xsjbxx.stuid || ',姓名:' || ls_xsjbxx.stuname);
  end if;
exception
  when no_data_found then
    dbms_output.put_line('该学生SC201901001不存在');
end;

9. RECORD(自定义结构)

9.1 定义

记录数据类型的一种,将几个相关的、分离的、基本数据类型的变量组成一个类似于整体表结构的对象,即RECORD复合数据类型。

在使用记录数据类型变量时,需要在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。

RECORD数据类型常用于存过与游标结合使用时,用于记录数据。

9.2 格式

/**
格式:
TYPE 名称(随便起)IS RECORD(
        列1名称  列1类型,
        列2名称  列2类型
);
*/

 TYPE T_RECORD IS RECORD (
    GOODS_CODE  VARCHAR2(64),
    GOODS_NAME VARCHAR2(64),
    ORDER_NUM VARCHAR2(16),
    DIS_ORDER_NUM VARCHAR2(16),
    TOTAL_ORDER_NUM VARCHAR2(16),
);

10. 存过、游标、RECORD整合

10.1 代码

/*1.定义存过*/
CREATE OR REPLACE
PROCEDURE PRO_RE_USER_ORD_GOODS(
--NOW_DATE格式:YYYYMMDD 如:20190801(此时统计的是2019年7月31日的数据)
NOW_DATE IN VARCHAR2
)
IS

    /*2.定义变量 START*/
    --定义RECORD型记录类型;
    TYPE T_RECORD IS RECORD (
        GOODS_CODE VARCHAR2 (64),
        GOODS_NAME VARCHAR2 (64)
    ) ;
    --定义返回结果集接收的变量,类型为T_RECORD;
  PS:这里也可以不用record,直接指定V_ROWRESUT为%rowtype类型
    V_ROWRESUT T_RECORD ;
    --定义主键
    PID VARCHAR2 (256) ;
    /*2.定义变量 end*/


        /*3.定义游标,执行查询结果集操作 START*/
        CURSOR CUR_RE_USER_ORD_GOODS
        IS
                --查询语句开始
                SELECT
                        A .GOODS_CODE,
                        B.GOODS_NAME
                FROM
                        (
                            SELECT
                                    ORD.GOODS_CODE
                            FROM
                                    ORDER_INFO ORD
                            GROUP BY
                                    ORD.GOODS_CODE
                        ) A
                LEFT JOIN GOODS_INFO B ON A .GOODS_CODE = B.GOODS_CODE ;
                --查询语句结束
        /*3.定义游标,执行查询结果集操作 END*/

        /*4.打开并循环游标,进行数据操作 START*/
        BEGIN
            OPEN CUR_RE_USER_ORD_GOODS;                          --打开游标;
            LOOP                                                 --开始执行循环,遍历查询结果集表;
                FETCH CUR_RE_USER_ORD_GOODS INTO V_ROWRESUT;       --循环游标并赋值给结构体变量;
                EXIT WHEN CUR_RE_USER_ORD_GOODS %NOTFOUND;         --如果游标遍历完成,就退出循环;

                --获取 UUID 并赋值给 PID 变量;
                SELECT SYS_GUID() INTO PID FROM DUAL;

                --插入“订购商品记录表” 开始
                INSERT INTO RE_USER_ORD_GOODS (
                    ID,
                    GOODS_CODE,
                    GOODS_NAME,
                    CREATE_TIME
                )VALUES(
                    PID,
                    V_ROWRESUT.GOODS_CODE,
                    V_ROWRESUT.GOODS_NAME,
                    SYSDATE
                );
                --插入“订购商品记录表” 结束

            END LOOP;                                           --结束循环;
            CLOSE CUR_RE_USER_ORD_GOODS;                        --关闭游标;
            COMMIT;                                             --提交 INSERT 操作;
        END;
        /*4.打开并循环游标,进行数据操作 END*/

10.2 oracle存储过程中is和as区别

在存储过程(PROCEDURE)和函数(FUNCTION)中没有区别;

在视图(VIEW)中只能用AS不能用IS;

在游标(CURSOR)中只能用IS不能用AS。

10.3 声明变量的方式

v_temp varchar(10)

v_temp tablename.property%type(表名属性名%type,指的是一个表中某个字段的类型,这样可以灵活使用)

v_stu    student%rowtype;(这种类型就是定义一个变量,这个变量的类型为一个表数据的行类型,用于接收查询的一整行数据)

10.4 赋值方式

:=


转载自:有梦想的肥宅