Oracle存储过程 自定义类型,集合读取

在实际应用场景中,需要通过存储过程解决批量录入,数据处理,批量返回的操作,且业务是实时的,即一次批量数据是一次性的。

针对这个场景,考虑过以下方法:使用临时缓存表,将数据处理后存入,需要使用时读取并删除;从其他业务上环节批量录入或批量返回的压力

而后确定批量一次数据量在200条内,此存储的调用比较频繁,存在被多处调用的情况。

考虑实际,如果使用临时表频繁读写删数据,可能会出现锁数据的情况;在业务上通过其他环节来找补也是下策。

最后确定了使用自定义数据类型和类型集合缓存处理好的数据,整体方案:将录入的格式约定成字符串,数据处理后缓存在集合,最后游标遍历集合返回数据。


自定义数据格式类型

-- 定义需要的数据类型,类似编程中的类
create or replace Type Check_Record
Is Object(P_Id NUMBER,V_Code Varchar2(2),V_Message NVARCHAR2(50))

-- 定义类型的集合,类似编程中的列表
create or replace Type PrescriptionCheck_Table  
Is Table Of PrescriptionCheck_Record

使用自定义类型,并通过游标返回类型列表信息

create or replace PROCEDURE p_check_refund_state (
    in_str   VARCHAR2, --输入字符串,格式:类型,ID;类型,ID...
    scur     OUT SYS_REFCURSOR -- 返回值
) IS
    --临时变量
    v_tempStr           VARCHAR(1000); -- 缓存解析字符串
    v_temp_in_str       VARCHAR(1000); -- 缓存输入字符串
    v_count_begin       int; -- 临时计数
    v_count_end         int; -- 临时计数
    v_type              NUMBER; --类型  检查申请 = 5,病理申请 = 6, 治疗申请 =7, 检验申请 = 8,手术申请 =9,用血申请 = 10,其他 = 99
    v_id                NUMBER; --ID
    v_code              VARCHAR(2); -- 返回值临时缓存
    v_message           VARCHAR(255); -- 返回信息临时缓存
    datatab             Check_Table := Check_Table(); -- 自定义类型的返回集合
    
BEGIN
  IF(in_str IS NOT NULL AND LENGTH(in_str) > 0) THEN
    v_temp_in_str := in_str;
    LOOP --循环解析字符串
      datatab.extend;-- 扩充一条
      datatab(datatab.count) :=  Check_Record(-1,0,'传入第' || datatab.count || '条数据有误!');
      --判断‘;’有无,若无取全部字符串,反之前取到第一个分号前位置。
      IF(INSTR(v_temp_in_str,';',1,1) != 0) THEN
        v_tempStr := SUBSTR(v_temp_in_str,0,INSTR(v_temp_in_str,';',1,1));                            
      ELSE
        v_tempStr := v_temp_in_str;
      END IF;

      v_count_end := LENGTH(v_tempStr);
      
      --解析目标字符串
      
      --判断','进行类型与id的分取,
      IF(INSTR(v_tempStr,',',1,1) != 0) THEN
        v_count_begin := INSTR(v_tempStr,',',1,1);
        v_type := TO_NUMBER(SUBSTR(v_tempStr,0,v_count_begin-1));
        
        IF(INSTR(v_tempStr,';',1,1) != 0) THEN
          v_id := TO_NUMBER(SUBSTR(v_tempStr,v_count_begin+1,v_count_end-v_count_begin-1));
        ELSE
          v_id := TO_NUMBER(SUBSTR(v_tempStr,v_count_begin+1,v_count_end));
        END IF;
    
        -- 单条业务数据处理
        p_check_One_state(v_type,v_id,v_code,v_message);
        -- 将处理后数据放入自定义集合
        datatab(datatab.count) :=  Check_Record(v_id,v_code,v_message);
      END IF;
      
      v_count_begin := LENGTH(v_temp_in_str);
      --丢弃解析过的字符串
      IF(v_count_begin != v_count_end) THEN
        v_temp_in_str := SUBSTR(v_temp_in_str,v_count_end+1,v_count_begin);
      ELSE
        v_temp_in_str := '';
      END IF;
      
    EXIT WHEN v_temp_in_str IS NULL OR LENGTH(v_temp_in_str) = 0;
    END LOOP;
    
  END IF;

  -- 遍历集合,数据返回
  OPEN scur FOR SELECT * FROM table(datatab);
-- 异常处理
EXCEPTION
    WHEN OTHERS THEN
      OPEN scur FOR SELECT * FROM table(datatab);
END;

过程中参考文章:

plsql创建存储过程(二、使用游标返回多列值)

Oracle存储过程中使用临时表的替代方案

oracle中自定义type、以及java中传递list到过程中的例子

你可能感兴趣的:(Oracle,.net,数据库)