Oracle作业执行与SQL Develop运行语句(脚本)的区别
问题背景:在SQL Developer界面上执行UPDATE语句是成功的,但在作业上这个UPDATE语句会报错。如目标表有如下触发器:
create or replace TRIGGER CONCEPT."SICKBED_TRG" AFTER UPDATE OF USEDCODEID OR DELETE ON "CONCEPT"."SICKBED" FOR EACH ROW
DECLARE
v_ip varchar2(30);
v_user varchar2(30);
BEGIN
SELECT sys_context('userenv', 'IP_ADDRESS'), sys_context('userenv', 'SESSION_USER') INTO v_ip, v_user FROM dual;
CASE
WHEN UPDATING ('USEDCODEID') THEN
IF :new.USEDCODEID != :old.USEDCODEID THEN
INSERT INTO "CONCEPT"."SICKBEDMODIFIEDTRACE"(SICKBEDID, NO, NAME, ORDINAL, GENDERCODEID, ORGANIZATIONID, MODIFYEMPLOYEEID, ISDELETED, ROWVERSION
, USEDCODEID, PRICEPERDAY, AIRCONDITIONFEE, ITEMID, ISADDFLAG, TYPECODEID, RELEASEDATETIME, REMARK, ISBOOKINGFLAG, ISHIGHQUALITYFLAG, GETWARMTHFEE, GETWARMTHITEMID
, AIRCONDITIONITEMID, SENDMEDICINEGROUPTYPECODEID, BASEMEDICINEORGANIZATIONID, CHANGEREASONCODEID, GROUPNO, ISTURNOVER, ISHIDE, SICKBEDKINDCODEID, LOCATIONID
, USEDCODECHANGEDON, ISSPECIAL, ISDAYTIME, OBLIGATECODEID, EMERGENCYFLAG
, N_NO, N_NAME, N_ORDINAL, N_GENDERCODEID, N_ORGANIZATIONID, N_MODIFYEMPLOYEEID, N_ISDELETED, N_ROWVERSION
, N_USEDCODEID, N_PRICEPERDAY, N_AIRCONDITIONFEE, N_ITEMID, N_ISADDFLAG, N_TYPECODEID, N_RELEASEDATETIME, N_REMARK, N_ISBOOKINGFLAG, N_ISHIGHQUALITYFLAG, N_GETWARMTHFEE, N_GETWARMTHITEMID
, N_AIRCONDITIONITEMID, N_SENDMEDICINEGROUPTYPECODEID, N_BASEMEDICINEORGANIZATIONID, N_CHANGEREASONCODEID, N_GROUPNO, N_ISTURNOVER, N_ISHIDE, N_SICKBEDKINDCODEID, N_LOCATIONID
, N_USEDCODECHANGEDON, N_ISSPECIAL, N_ISDAYTIME, N_OBLIGATECODEID, N_EMERGENCYFLAG
, USERNAME, IP)
VALUES(:old.SICKBEDID, :old.NO, :old.NAME, :old.ORDINAL, :old.GENDERCODEID, :old.ORGANIZATIONID, :old.MODIFYEMPLOYEEID, :old.ISDELETED, :old.ROWVERSION
, :old.USEDCODEID, :old.PRICEPERDAY, :old.AIRCONDITIONFEE, :old.ITEMID, :old.ISADDFLAG, :old.TYPECODEID, :old.RELEASEDATETIME, :old.REMARK, :old.ISBOOKINGFLAG, :old.ISHIGHQUALITYFLAG, :old.GETWARMTHFEE, :old.GETWARMTHITEMID
, :old.AIRCONDITIONITEMID, :old.SENDMEDICINEGROUPTYPECODEID, :old.BASEMEDICINEORGANIZATIONID, :old.CHANGEREASONCODEID, :old.GROUPNO, :old.ISTURNOVER, :old.ISHIDE, :old.SICKBEDKINDCODEID, :old.LOCATIONID
, :old.USEDCODECHANGEDON, :old.ISSPECIAL, :old.ISDAYTIME, :old.OBLIGATECODEID, :old.EMERGENCYFLAG
, :new.NO, :new.NAME, :new.ORDINAL, :new.GENDERCODEID, :new.ORGANIZATIONID, :new.MODIFYEMPLOYEEID, :new.ISDELETED, :new.ROWVERSION
, :new.USEDCODEID, :new.PRICEPERDAY, :new.AIRCONDITIONFEE, :new.ITEMID, :new.ISADDFLAG, :new.TYPECODEID, :new.RELEASEDATETIME, :new.REMARK, :new.ISBOOKINGFLAG, :new.ISHIGHQUALITYFLAG, :new.GETWARMTHFEE, :new.GETWARMTHITEMID
, :new.AIRCONDITIONITEMID, :new.SENDMEDICINEGROUPTYPECODEID, :new.BASEMEDICINEORGANIZATIONID, :new.CHANGEREASONCODEID, :new.GROUPNO, :new.ISTURNOVER, :new.ISHIDE, :new.SICKBEDKINDCODEID, :new.LOCATIONID
, :new.USEDCODECHANGEDON, :new.ISSPECIAL, :new.ISDAYTIME, :new.OBLIGATECODEID, :new.EMERGENCYFLAG
, v_user, v_ip);
END IF;
WHEN DELETING THEN
RAISE_APPLICATION_ERROR(-20003, '不能物理删除床位表记录');
END CASE;
END;
由于UPDATE CONCEPT.SICKEBD表时,会通过触发器插入跟踪表数据,跟踪表的字段是不允许空的,如下获取数据库上下文数据在SQL Developer上运行得到正确的值,而在作业获取IP地址则为空(导致UPDATE语句的作业失败):
SELECT sys_context('userenv', 'IP_ADDRESS'), sys_context('userenv', 'SESSION_USER') INTO v_ip, v_user FROM dual;
所以上述语句需改为:SELECT NVL(sys_context('userenv', 'IP_ADDRESS'), NVL(sys_context('USERENV','HOST'),'JOB_IP')), sys_context('userenv', 'SESSION_USER') INTO v_ip, v_user FROM dual;
其次,关于分布式事务在SQL Developer上能正常运行,而在SQL Developer正常执行,而在作业里面就不能用分布式事务(只能提交Oracle部分,再提交SQL Server链接数据库部分),譬如下面存储过程
create or replace PROCEDURE "APPS"."JOBCORRECTSICKBEDUSEDCODE"
AS
v_sickbedids VARCHAR2(8000);
BEGIN
DELETE CONCEPT.SICKBEDMODIFIEDTRACE WHERE TRUNC(MODIFIEDON) < TRUNC(SYSDATE) - 30;
--更新床位状态
INSERT INTO "CONCEPT"."TBL_ORGANIZATIONSICKBEDTOMODIFY"(ORGANIZATIONID, SICKBEDID)
select s.ORGANIZATIONID, s.SICKBEDID from concept.sickbed s, entity.organization o
where s.ORGANIZATIONID=o.ORGANIZATIONID and s.ISDELETED=0 and o.ISDELETED=0 and s.USEDCODEID=1 -- and s.ORGANIZATIONID not in (430,1606)
and s.SICKBEDID>0 and s.SICKBEDID not in (select sickbedid from prpa.encounter e
where e.isdeleted=0 and e.encounterkindcodeid=1 and e.sickbedid>0 --and e.partitionflag=0
and (e.statuscodeid=1 or (e.statuscodeid=3 and trunc(e.dischargeon)>trunc(sysdate))));
UPDATE CONCEPT.SICKBED t
SET t.UsedCodeId = 0
WHERE t.SICKBEDID IN ( SELECT SICKBEDID FROM CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY WHERE ISMODIFIED=0 );
SELECT wmsys.wm_concat(ii.EXTENSION) INTO v_sickbedids FROM CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY s, CONCEPT.SICKBEDII ii WHERE s.SICKBEDID=ii.SICKBEDID and s.ISMODIFIED=0;
--dbms_output.put_line ('v_sickbedids:' || v_sickbedids);
IF v_sickbedids IS NOT NULL THEN
DBO.pHIS30_ReleaseSickBedStatus@IP(-1, v_sickbedids);
END if;
UPDATE CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY SET ISMODIFIED=1, MODIFIEDON=SYSDATE WHERE ISMODIFIED=0 ;
COMMIT;
END;
需要改为非分布式事务来处理(作业用时):
create or replace PROCEDURE "APPS"."JOBCORRECTSICKBEDUSEDCODE"
AS
v_sickbedids VARCHAR2(8000);
BEGIN
DELETE CONCEPT.SICKBEDMODIFIEDTRACE WHERE TRUNC(MODIFIEDON) < TRUNC(SYSDATE) - 30;
--更新床位状态
INSERT INTO "CONCEPT"."TBL_ORGANIZATIONSICKBEDTOMODIFY"(ORGANIZATIONID, SICKBEDID)
select s.ORGANIZATIONID, s.SICKBEDID from concept.sickbed s, entity.organization o
where s.ORGANIZATIONID=o.ORGANIZATIONID and s.ISDELETED=0 and o.ISDELETED=0 and s.USEDCODEID=1 -- and s.ORGANIZATIONID not in (430,1606)
and s.SICKBEDID>0 and s.SICKBEDID not in (select sickbedid from prpa.encounter e
where e.isdeleted=0 and e.encounterkindcodeid=1 and e.sickbedid>0 --and e.partitionflag=0
and (e.statuscodeid=1 or (e.statuscodeid=3 and trunc(e.dischargeon)>trunc(sysdate))));
UPDATE CONCEPT.SICKBED t
SET t.UsedCodeId = 0
WHERE t.SICKBEDID IN ( SELECT SICKBEDID FROM CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY WHERE ISMODIFIED=0 );
SELECT wmsys.wm_concat(ii.EXTENSION) INTO v_sickbedids FROM CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY s, CONCEPT.SICKBEDII ii WHERE s.SICKBEDID=ii.SICKBEDID and s.ISMODIFIED=0;
--dbms_output.put_line ('v_sickbedids:' || v_sickbedids);
UPDATE CONCEPT.TBL_ORGANIZATIONSICKBEDTOMODIFY SET ISMODIFIED=1, MODIFIEDON=SYSDATE WHERE ISMODIFIED=0 ;
COMMIT;
IF v_sickbedids IS NOT NULL THEN
DBO.pHIS30_ReleaseSickBedStatus@IP(-1, v_sickbedids);
END if;
COMMIT;
END;