• Oracle学习笔记:利用oracle的 “表类型”复合变量,实现临时表的功能


    情景及需求:

    有A表为事实表,B为历史表

    create table A (fact_id int not null primary key,name varchar2(50));

    create table B (log_id int not null primary key,name varchar2(50),addtime timestamp);

      需求:建立存储过程prc,外部程序并行周期调用。该过程从A表取得一定量的数据(记录集)备份到B表,并从A中删除该批备份的数据(记录集),同时返回该批数据(记录集)到外部程序供外部程序使用

    分析:

    要实现上述需求,首先考虑该过程用于并行处理,需要对每一个处理进程进行事务隔离——既需要实现读隔离,oracle中可以通过select ...  from A   for update 实现。而每次处理的记录数可以通过订阅存储过程的入参“rowcount int”实现。返回记录集可以通过一个“rs out ref_syscursor”实现。而关键的部分是如果实现从A到B的记录转移?通常我们可以的定义一个事物级的临时表T来实现:A->T,T[+A]->B,从A删除T,返回T的记录集,删除T。虽然oracle的临时表已经做了很多的性能优化且具有自己的特点,但仍然是和磁盘打交道的做法——如果临时表的数据量很大——这是个很不错的选择,但如果处理的中间数据量不是很大,通过内存变量结构来实现岂不是更好吗!为此sqlserver中提供表变量这一机制,而oracle中复合数据类型[或称集合数据类型]“表类型”正是解决这一问题的机制,为了具有标准sql类似的集合操作oracle提供了在pl/sql中使用的bulk collect、for all操作。

    实现代码:

    create or replace procedure prc
    (
        rowcount int,
        rs       out sys_refcursor
    )
    as
        TYPE t_fact_id is table of int; --定义table类型
        vt_fact_id      t_fact_id; --定义table类型的变量
        v_first_fact_id int;
        v_last_fact_id  int;
    begin
        --批量获取A的fact_id字段信息到t_fact_id表类型的变量vt_fact_id中
        select fact_id bulk collect
        into   vt_fact_id
        from   a
        where  rownum <= rowcount
        for    update
        order  by fact_id;

        --批量插入到B
        forall i in vt_fact_id.first .. vt_fact_id.last
            insert into b
                select a.*, sysdate
                from   a
                where  fact_id = vt_fact_id(i);

        --获取插入到表变量的A表的fact_id的最小值、最大值,主要是为了定义输出结果集的条件
        v_first_fact_id := vt_fact_id(vt_fact_id.first);
        v_last_fact_id  := vt_fact_id(vt_fact_id.last);

        --输出结果集
        open rs for
            select *
            from   a
            where  fact_id between v_first_fact_id and v_last_fact_id;

        --批量删除A中的记录
        forall i in vt_fact_id.first .. vt_fact_id.last
            delete from a
            where  fact_id = vt_fact_id(i);

        commit;

    exception
        when others then
            dbms_output.put_line(sqlerrm);
            open rs for
                select *
                from   a
                where  0 = 1;
    end;

    讨论:

    1.如果A表的primary key列fact_id是直接插入到B表的,其实可以使用dml(delete)的returning fact_id bulk collect into vt_fact_id来获得记录集的fact_id表类型变量数据,而不用如例子中先select from A for update了,之后从B表获得返回的结果集

    2.例子中没有在正常的程序处理部分处理vt_fact_id是empty(不是null),而是通过exception部分处理的

  • 相关阅读:
    PHP 消息队列
    Nginx 设置负载均衡
    Nginx 服务器搭建
    PHP 获取文件扩展名的五种方式
    高并发和大流量解决方案
    <面试> PHP 常见算法
    Mysql 预查询处理 事务机制
    Linux定时任务 结合PHP实现实时监控
    Swoole 结合TP5搭建文字直播平台
    <记录> PHP Redis操作类
  • 原文地址:https://www.cnblogs.com/jinzhenshui/p/1431632.html
Copyright © 2020-2023  润新知