PL/SQL触发器报错:ORA-00984与PLS-00382求助
PL/SQL触发器错误排查与修复
原始问题
我是PL/SQL开发新手,创建了如下触发器:
create or replace trigger schema.trg_CP after insert on tdlrp referencing old as old for each row --------------------------------------------------------------------------------------------------------- declare v_fkidnc schema.tdlrp.fkidnc%type; v_errortype schema.tdlrp.xerrort%type; v_fkerrorID schema.tepm.ferror%type; v_linerror number; v_pr schema.tpm.pipm%type; v_pkdocid_r schema.tddr.pidr%type; --------------------------------------------------------------------------------------------------------- begin if inserting then select fkidnc, xerrort into v_fkidnc, v_errortype from schema.tdlrp; -- if v_fkidnc = 1 then if v_errortype = 1 then select ferror, fipcm into v_fkerrorID, v_linerror from schema.tepm; select pipm into v_pr from schema.tpm where fipcm = v_linerror; insert into schema.tddr(pidr, fipc,user, datea, fiptm) values(schema.seq_tddr.nextval, old.fipc,'A', systimestamp, v_pr); select pidr into v_pkdocid_r from tddr where fiptm = v_pr; insert into schema.tere(pidr, ferror, fidre, user, datea, fipcm) values(schema.seq_tere.nextval, v_fkerrorID, v_pkdocid_r, 'A', SYSTIMESTAMP, v_linerror); END IF; END IF; END IF; EXCEPTION WHEN OTHERS THEN RAISE; END trg_CP;
执行脚本时出现错误:
PL/SQL: ORA-00984: column not allowed in here
错误指向select attr into variable语句,请问如何解决?是否是语法问题?
更新后的问题(2022-09-15 15:31)
按照建议修改后,出现新错误:
PLS-00382: expression is of wrong type
错误指向begin语句,修改后的触发器代码如下:
create or replace trigger schema.trg_CP after insert on tdlrp referencing old as old for each row --------------------------------------------------------------------------------------------------------- declare v_fkidnc schema.tdlrp.fkidnc%type; v_errortype schema.tdlrp.xerrort%type; v_fkerrorID schema.tepm.ferror%type; v_linerror number; v_pr schema.tpm.pipm%type; v_pkdocid_r schema.tddr.pidr%type; --------------------------------------------------------------------------------------------------------- begin select fkidnc, xerrort into v_fkidnc, v_errortype from schema.tdlrp; -- if :new.fkidnc = 1 and :new.errortype = 1 then select ferror, fipcm into v_fkerrorID, v_linerror from schema.tepm; select pipm into v_pr from schema.tpm where fipcm = v_linerror; insert into schema.tddr(pidr, fipc,user, datea, fiptm) values(schema.seq_tddr.nextval, old.fipc,'A', systimestamp, v_pr); select pidr into v_pkdocid_r from tddr where fiptm = v_pr; insert into schema.tere(pidr, ferror, fidre, user, datea, fipcm) values(schema.seq_tere.nextval, v_fkerrorID, v_pkdocid_r, 'A', SYSTIMESTAMP, v_linerror); END IF; -- EXCEPTION WHEN OTHERS THEN RAISE; END trg_CP;
请问如何解决这些错误?
错误原因与修复方案
第一个错误(ORA-00984)原因
- 错误访问行数据:行级触发器中必须用
:new.字段名获取当前插入行的字段值,直接查询整个tdlrp表会返回多行,还可能触发变异表问题,同时不符合触发器的行数据访问规则。 - 无效的
old引用:after insert触发器中没有旧行数据,old.fipc是无效的,应该用:new.fipc。
第二个错误(PLS-00382)原因
- 字段名不匹配:
:new.errortype不存在,原始表中对应的字段是xerrort,类型不匹配导致类型错误。 - 未过滤的
select into:多个select into语句没有where条件,会返回多行,触发too_many_rows错误,属于逻辑语法错误。
修复后的完整代码
create or replace trigger schema.trg_CP after insert on tdlrp for each row declare v_fkerrorID schema.tepm.ferror%type; v_linerror number; v_pr schema.tpm.pipm%type; v_pkdocid_r schema.tddr.pidr%type; begin -- 直接用:new获取当前插入行的字段值,无需查询整个表 if :new.fkidnc = 1 and :new.xerrort = 1 then -- 补充where条件,确保查询tepm返回单行(需根据实际业务逻辑调整过滤条件) select ferror, fipcm into v_fkerrorID, v_linerror from schema.tepm where ferror = :new.xerrort; -- 示例条件,需匹配你的业务规则 select pipm into v_pr from schema.tpm where fipcm = v_linerror; -- 插入tddr时用returning子句直接获取生成的pidr,避免二次查询 insert into schema.tddr(pidr, fipc, "user", datea, fiptm) values(schema.seq_tddr.nextval, :new.fipc, 'A', systimestamp, v_pr) returning pidr into v_pkdocid_r; insert into schema.tere(pidr, ferror, fidre, "user", datea, fipcm) values(schema.seq_tere.nextval, v_fkerrorID, v_pkdocid_r, 'A', SYSTIMESTAMP, v_linerror); end if; exception when others then -- 自定义错误信息,方便排查问题 raise_application_error(-20001, '触发器执行错误: ' || sqlcode || ' - ' || sqlerrm); end trg_CP;
关键修复点
- 移除查询整个
tdlrp表的语句,直接通过:new访问当前插入行的字段,避免变异表和多行返回问题。 - 修正字段名错误:将
:new.errortype改为:new.xerrort,匹配表定义。 - 所有
select into语句补充where条件,确保返回单行,避免too_many_rows错误。 - 使用
returning子句获取插入tddr后的pidr,无需额外查询,提升效率并避免数据不一致。 - 替换无效的
old.fipc为:new.fipc,符合insert触发器的行数据访问规则。 - 异常处理中添加自定义错误信息,便于排查问题。
- 注意
user是Oracle关键字,作为字段名时需用双引号包裹(如果你的表确实使用该字段名)。
内容的提问来源于stack exchange,提问作者Nhoj Anec
相关产品推荐
相关产品推荐

