【发布时间】:2022-06-11 01:36:24
【问题描述】:
这是我第一次在 Oracle 中使用 BEFORE INSERT 触发器。 我认为使用函数设置 :new 字段之一不会有问题,但显然有。
CREATE OR REPLACE TRIGGER
TRG_DESC_DOCUMENTO BEFORE INSERT ON DOTFILEPAT.DOCUMENTOS
FOR EACH ROW
DECLARE
VAR_SELECCION VARCHAR2(50);
VAR_CODIGO VARCHAR2(30);
VAR_VERIFICACION NUMBER;
BEGIN
VAR_SELECCION := :NEW.TIPO_DOCUMENTO;
VAR_CODIGO := :NEW.CODBARRAS;
--SELECT INSTR(:NEW.CODBARRAS,'F') INTO VAR_VERIFICACION FROM DUAL;
--IF(VAR_SELECCION = 'OFICIO' OR VAR_SELECCION = 'PROMOCION') THEN
:NEW.DESCRIPCION_DOCUMENTO := PATENTES.FN_NOMBRE_PROMO_OFICIOS(VAR_CODIGO,VAR_SELECCION);
--END IF;
END;
但是它不起作用,因为它只将 :new.descripcion_documento 值设置为 null。但是我测试了直接设置该字段(即:new.descripcion_documento = 'SOMETHING')并且它确实有效。
但是我需要使用该函数来查询新值。这是函数:
create or replace FUNCTION FN_NOMBRE_PROMO_OFICIOS(CODIGO IN VARCHAR2,TIPO_DOCUM IN VARCHAR2) RETURN VARCHAR2 AS
VAR_SALIDA VARCHAR2(4000);
BEGIN
IF(TIPO_DOCUM = 'PROMOCION') THEN
BEGIN
SELECT LISTAGG(TAUX.DES_TIPO,' | ' ON OVERFLOW TRUNCATE) WITHIN GROUP(ORDER BY TAUX.DES_TIPO) INTO VAR_SALIDA FROM TIPO_PROMOCION TAUX INNER JOIN
PROMOCION_TIPO P ON P.TIP_PROMOCION = TAUX.TIP_PROMOCION INNER JOIN PROMOCION PAUX ON PAUX.COD_OFICINA = P.COD_OFICINA
AND PAUX.TIP_LIBRO = P.TIP_LIBRO AND PAUX.SER_DOCUM = P.SER_DOCUM AND PAUX.NUM_DOCUM = P.NUM_DOCUM INNER JOIN DOTFILEPAT.DOCUMENTOS D ON D.CODBARRAS =
PAUX.COD_OFICINA||'/'||PAUX.TIP_LIBRO||'/'||PAUX.SER_DOCUM||'/'||LPAD(PAUX.NUM_DOCUM,6,0)
WHERE UPPER(D.TIPO_DOCUMENTO) ='PROMOCION' AND D.CODBARRAS = CODIGO;
END;
ELSIF(TIPO_DOCUM = 'OFICIO') THEN
BEGIN
SELECT T.DES_OFICIO INTO VAR_SALIDA FROM TIPO_OFICIO T INNER JOIN OFICIO O ON O.TIP_OFICIO = T.TIP_OFICIO INNER JOIN DOTFILEPAT.DOCUMENTOS D ON D.CODBARRAS =
O.COD_OFICINA_OFICIO||'/'||O.SER_OFICIO||'/'||O.NUM_OFICIO WHERE UPPER(D.TIPO_DOCUMENTO) ='OFICIO' AND D.CODBARRAS = CODIGO;
END;
END IF;
RETURN VAR_SALIDA;
EXCEPTION WHEN OTHERS THEN
IF(TIPO_DOCUM = 'PROMOCION') THEN
SELECT TAUX.DES_TIPO INTO VAR_SALIDA FROM TIPO_PROMOCION TAUX INNER JOIN
PROMOCION_TIPO P ON P.TIP_PROMOCION = TAUX.TIP_PROMOCION INNER JOIN PROMOCION PAUX ON PAUX.COD_OFICINA = P.COD_OFICINA
AND PAUX.TIP_LIBRO = P.TIP_LIBRO AND PAUX.SER_DOCUM = P.SER_DOCUM AND PAUX.NUM_DOCUM = P.NUM_DOCUM INNER JOIN DOTFILEPAT.DOCUMENTOS D ON D.CODBARRAS =
PAUX.COD_OFICINA||'/'||PAUX.TIP_LIBRO||'/'||PAUX.SER_DOCUM||'/'||LPAD(PAUX.NUM_DOCUM,6,0)
WHERE UPPER(D.TIPO_DOCUMENTO) ='PROMOCION' AND D.CODBARRAS = CODIGO AND P.IND_PRIMERO = 'S';
RETURN VAR_SALIDA;
ELSE RETURN NULL;
END IF;
END FN_NOMBRE_PROMO_OFICIOS;
知道为什么运行函数在触发器中不起作用吗?
更新:我遵循了 Brian Dellinger 的建议并像这样编辑了我的代码:
create or replace TRIGGER
DOTFILEPAT.TRG_DESC_DOCUMENTO FOR UPDATE OR INSERT ON DOTFILEPAT.DOCUMENTOS
COMPOUND TRIGGER
TYPE R_DOCUMENTOS IS RECORD(
CODIGOBARRAS DOCUMENTOS.CODBARRAS%TYPE,
DESC_DOCUM DOCUMENTOS.DESCRIPCION_DOCUMENTO%TYPE
);
TYPE T_DOCUMENTOS IS TABLE OF R_DOCUMENTOS
INDEX BY PLS_INTEGER;
REGISTRO_DOCUM T_DOCUMENTOS;
AFTER EACH ROW IS
BEGIN
REGISTRO_DOCUM(REGISTRO_DOCUM.COUNT +1).CODIGOBARRAS := :NEW.CODBARRAS;
REGISTRO_DOCUM(REGISTRO_DOCUM.COUNT +1).DESC_DOCUM := PATENTES.FN_NOMBRE_PROMO_OFICIOS(:NEW.CODBARRAS,:NEW.TIPO_DOCUMENTO);
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
--SELECT INSTR(:NEW.CODBARRAS,'F') INTO VAR_VERIFICACION FROM DUAL;
FOR INDX IN 1.. REGISTRO_DOCUM.COUNT
LOOP
UPDATE DOTFILEPAT.DOCUMENTOS SET DESCRIPCION_DOCUMENTO = REGISTRO_DOCUM(INDX).CODIGOBARRAS WHERE CODBARRAS = REGISTRO_DOCUM(INDX).CODIGOBARRAS;
END LOOP;
END AFTER STATEMENT;
END;
但是我似乎没有正确创建触发器,因为现在我得到了一个
ORA-04091: la tabla DOTFILEPAT.DOCUMENTOS está mutando, puede que el disparador/la función no puedan verla
但是复合触发器似乎是这样,有没有关于如何使复合触发器起作用的方法?
我还编辑了触发器的定义,包括 OF COLUMN 语句:
DOTFILEPAT.TRG_DESC_DOCUMENTO FOR INSERT OR UPDATE OF DESCRIPCION_DOCUMENTO ON DOTFILEPAT.DOCUMENTOS
但问题还是没有解决。
更新:感谢您的关注,正如 Pugzly 所要求的,我上传了 CREATE TABLE 脚本和一个最小的 DataSet。
以下是它们的链接: Dataset CREATE TABLE script
【问题讨论】:
-
我也测试了这个函数,对于我测试过的情况,它确实返回了一个不为空的值,但显然它运行得太慢,触发器无法工作
-
您正在对 Dotfilepat.documentos 执行前触发器,但您的函数正在引用该表。我的猜测是,您将需要使用复合触发器,而不是之前的触发器。 oracletutorial.com/plsql-tutorial/…
-
@BryanDellinger 我试着听从你的建议
-
如果你能提供一个最小的测试用例,它可能会有所帮助,其中包括一个创建表语句、示例数据和一个最小的函数。即只给出显示问题的最少代码
标签: sql database oracle function triggers