该功能主要是实现根据传过来的参数,读取接口中间表的数据,解析并新增到MPD主表及其子表中,并将每条数据执行结果,成功或失败反馈回去。若中间表不存在某数据,或发生异常如违反唯一性约束,需将业务表数据操作全部回滚。
折腾了好几天,遇到各种难题,百度了N多资料,终于实现,不容易啊~~ 粗体的地方值得学习。
create or replace procedure INSERT_MPD(crossids in varchar2,
flag out varchar2,
o_cur out sys_refcursor) as
begin
declare
type t_cursor is ref cursor;
cur_mpd t_cursor;
v_mpdno ppcp_mpd.mpdno%type;
v_taref ppcp_mpd.taref%type;
v_actype ppcp_mpd.actype%type;
v_isrepair ppcp_mpd.is_repair%type;
v_ata ppcp_mpd.ata%type;
v_effective ppcp_mpd.effective%type;
v_effdes ppcp_mpd.effective_des%type;
v_rii ppcp_mpd.rii%type;
v_tasktype ppcp_mpd.tasktype%type;
v_rref ppcp_mpd.rref%type;
v_des ppcp_mpd.description%type;
v_manhours ppcp_mpd.manhours%type;
v_crossid tdms_ppcp_mpd.crossid%type;
v_zone tdms_ppcp_mpd.zone%type;
v_msthres tdms_ppcp_mpd.first_interval%type;
v_msint tdms_ppcp_mpd.interval%type;
v_airworth tdms_ppcp_mpd.airworth%type;
v_mpdid ppcp_mpd.mpd_id%type;
l_sql varchar2(5000);
cur_zone t_cursor;
cur_airworth t_cursor;
cur_thres t_cursor;
cur_int t_cursor;
cur_crossid t_cursor;
vv_zone ppcp_mpd_zone.zone%type;
vv_airworth ppcp_mpd_airworth.airworth%type;
vv_msthres varchar2(200);
vv_msint varchar2(200);
vv_unit ppcp_mpd_int.unit%type;
vv_num ppcp_mpd_int.ms_threshold%type;
-- 申明数组,保存已处理记录的crossid
type type_array is table of int index by binary_integer;
var_array type_array;
i int;
begin
i := 1;
flag := 'success'; -- 返回值,判断是否执行成功
-- 按逗号分隔字符串的SQL语句
l_sql := 'WITH A AS
(SELECT ''' || crossids || ''' A FROM DUAL)
select result
from (SELECT DECODE(B, 0, SUBSTR(A, C), SUBSTR(A, C, B - C)) result
FROM (SELECT A, B, (LAG(B, 1, 0) OVER(ORDER BY LV)) + 1 C
FROM (SELECT A, INSTR(A, '','', 1, LEVEL) B, LEVEL LV
FROM A
CONNECT BY LEVEL <=
(LENGTH(A) - LENGTH(REPLACE(A, '','', ''''))) + 1)))
where result is not null';
open cur_crossid for l_sql;
loop
fetch cur_crossid
into v_crossid;
exit when cur_crossid%notfound;
l_sql := 'select tpm.actype,
tpm.is_repair,
tpm.mpdno,
tpm.taref,
tpm.ata,
tpm.effective,
tpm.effective_des,
tpm.rii,
tpm.tasktype,
tpm.rref,
tpm.zone,
tpm.airworth,
tpm.first_interval,
tpm.interval,
tpm.description,
tpm.manhours,
tpm.crossid
from tdms_ppcp_mpd tpm
where tpm.crossid = ' || v_crossid;
open cur_mpd for l_sql;
-- 读取数据 (因为只有一行数据,否则要在外加循环loop)
fetch cur_mpd
into v_actype,
v_isrepair,
v_mpdno,
v_taref,
v_ata,
v_effective,
v_effdes,
v_rii,
v_tasktype,
v_rref,
v_zone,
v_airworth,
v_msthres,
v_msint,
v_des,
v_manhours,
v_crossid;
-- 一定要写在fetch后,fetch用于获取游标结果集中的记录
-- 属性%ROWCOUNT用于返回一个整数值,显示迄今为止从游标结果集中获取记录的总数。
-- 查询结果记录为零,表示中间表无该数据,主动抛出异常
if cur_mpd%rowcount = 0 then
raise NO_DATA_FOUND;
end if;
select PPCP_MPD_SEQ.NEXTVAL into v_mpdid from dual;
insert into ppcp_mpd
(actype,
is_repair,
mpdno,
taref,
ata,
effective,
effective_des,
rii,
tasktype,
rref,
description,
manhours,
updatedwhen,
mpd_id,
crossid)
values
(v_actype,
v_isrepair,
v_mpdno,
v_taref,
v_ata,
v_effective,
v_effdes,
v_rii,
v_tasktype,
v_rref,
v_des,
v_manhours,
sysdate,
v_mpdid,
v_crossid);
--解析MS条目zone
l_sql := get_spilt_sql(v_zone); -- 获得分割字符串的SQL语句
open cur_zone for l_sql;
loop
fetch cur_zone
into vv_zone;
exit when cur_zone%notfound;
insert into ppcp_mpd_zone (mpd_id, zone) values (v_mpdid, vv_zone);
end loop;
close cur_zone;
--解析MS条目airworth
l_sql := get_spilt_sql(v_airworth);
open cur_airworth for l_sql;
loop
fetch cur_airworth
into vv_airworth;
exit when cur_airworth%notfound;
insert into ppcp_mpd_airworth
(mpd_id, airworth)
values
(v_mpdid, vv_airworth);
end loop;
close cur_airworth;
--解析MS条目interval
-- 分割首检的字符串, 并插入间隔表
--dbms_output.put_line('v_msthres:' || v_msthres );
l_sql := get_spilt_sql(v_msthres);
open cur_thres for l_sql;
loop
fetch cur_thres
into vv_msthres;
exit when cur_thres%notfound;
-- 解析数字和单位,插入int表
vv_unit := upper(substr(vv_msthres, -2));
vv_num := to_number(substr(vv_msthres, 1, length(vv_msthres) - 2));
--dbms_output.put_line('threshold:' || vv_num || '-' || vv_unit );
insert into ppcp_mpd_int
(mpd_id, unit, ms_threshold)
values
(v_mpdid, vv_unit, vv_num);
end loop;
close cur_thres;
-- 分割重复检的字符串, 并插入或更新到间隔表
l_sql := get_spilt_sql(v_msint); -- 函数,组装按空格分隔字符的SQL查询语句
open cur_int for l_sql;
loop
fetch cur_int
into vv_msint;
exit when cur_int%notfound;
-- 解析数字和单位,插入或更新到int表
vv_unit := upper(substr(vv_msint, -2));
vv_num := to_number(substr(vv_msint, 1, length(vv_msint) - 2));
update ppcp_mpd_int
set ms_interv = vv_num
where mpd_id = v_mpdid
and unit = vv_unit;
if SQL%NOTFOUND then
insert into ppcp_mpd_int
(mpd_id, unit, ms_interv)
values
(v_mpdid, vv_unit, vv_num);
end if;
end loop;
close cur_int;
var_array(i) := v_crossid;
i := i + 1;
close cur_mpd;
end loop; -- 循环读取新增数据结束
close cur_crossid;
-- 循环插入执行成功的crossid
for j in 1 .. var_array.count loop
dbms_output.put_line(var_array(j));
insert into message_content
(crossid,
objectid,
objectNum,
objectstatus,
Objectcontent,
errormemo,
errorID)
values
(var_array(j), null, null, 'success', null, null, null);
end loop;
open o_cur for
select * from message_content;
exception
when DUP_VAL_ON_INDEX then
rollback; -- 业务数据先全部回滚
-- 插入执行可以成功记录的crossid
for j in 1 .. var_array.count loop
dbms_output.put_line(var_array(j));
insert_Message(var_array(j), 'success', null, null); -- 另一个存储过程
end loop;
-- 插入执行发生异常记录的crossid
insert_Message(v_crossid, 'fail', '违反唯一性约束', '001');
open o_cur for
select * from message_content;
flag := 'fail';
when NO_DATA_FOUND then
rollback; -- 业务数据先全部回滚
-- 插入执行可以成功记录的crossid
for j in 1 .. var_array.count loop
dbms_output.put_line(var_array(j));
insert_Message(var_array(j), 'success', null, null);
end loop;
-- 插入执行发生异常记录的crossid
insert_Message(v_crossid, 'fail', '中间表没有此数据', '101');
open o_cur for
select * from message_content;
flag := 'fail';
when others then
rollback; -- 要求全部回滚
-- 插入执行可以成功记录的crossid
for j in 1 .. var_array.count loop
dbms_output.put_line(var_array(j));
insert_Message(var_array(j), 'success', null, null);
end loop;
-- 插入执行发生异常记录的crossid
insert_Message(v_crossid, 'fail', '未知原因', '002');
open o_cur for
select * from message_content;
flag := 'fail';
end;
end INSERT_MPD;