【问题标题】:Use function to set value of field in BEFORE INSERT TRIGGER in Oracle在 Oracle 中使用函数设置 BEFORE INSERT TRIGGER 中的字段值
【发布时间】: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


猜你喜欢
  • 2017-03-24
  • 2018-04-05
  • 2011-03-13
  • 2011-03-16
  • 2011-09-18
  • 2014-05-08
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多