ORA-22903:不允许MULTISET表达式

时间:2019-01-02 02:30:47

标签: oracle plsql

我有一个表,其中一个字段为嵌套表。我在第一个表上有一个触发器,但是它不起作用,并在:ORA-22903:MULTISET表达式上导致结果

CREATE OR REPLACE TYPE DIA_T as object
(dia varchar2(9),
hora varchar2(6));


CREATE OR REPLACE TYPE DIA_TAB IS TABLE OF DIA_T;


CREATE TABLE T_TALLER(
PK NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
...
DIAS DIA_TAB,
FEC_INI DATE NOT NULL,
FEC_FIN DATE NOT NULL,
...
CONSTRAINT CST_PRIMKEY_TALLER PRIMARY KEY (PK),
...
) NESTED TABLE DIAS STORE AS DIAS_TAB;

我的触发条件是:

CREATE OR REPLACE TRIGGER TRG_TALLER_AU_FEC_FIN AFTER UPDATE OF FEC_FIN ON T_TALLER FOR EACH ROW
BEGIN

FOR REC IN (SELECT T.DIA , T.HORA                
            FROM TABLE(:NEW.DIAS) T) LOOP

    dbms_output.put_line(REC.DIA||' '||REC.HORA);


END LOOP;

END;

当我尝试类似的操作时:

update t_taller set fec_fin = fec_fin + 20 where pk = 10;

我收到以下错误:

    ORA-22903: MULTISET expression not allowed
    ORA-06512: at "ESTAMPAS.TRG_TALLER_AU_FEC_FIN", line 3
    ORA-04088: error during execution of trigger 'ESTAMPAS.TRG_TALLER_AU_FEC_FIN'

您能帮我解决这个问题吗?

先谢谢了。 问候

更新

我发布的触发器是一个虚拟触发器,但是我得到的真正触发器的错误是相同的,我的真正触发器是这个

CREATE OR REPLACE TRIGGER TRG_TALLER_AU_FEC_FIN AFTER UPDATE OF FEC_FIN ON T_TALLER FOR EACH ROW
BEGIN

IF :NEW.FEC_FIN >= :OLD.FEC_FIN THEN

    Pkg_Utilidades.p_ins_taller_clase_grupo(:NEW.PK,(:OLD.FEC_FIN) + 1,:NEW.FEC_FIN,:NEW.DIAS,:NEW.AU_USU_INS);

ELSE

    DELETE T_TALLER_CLASE
    WHERE FK_TALLER = :NEW.PK
    AND FEC_CLASE BETWEEN :NEW.FEC_FIN + 1 AND :OLD.FEC_FIN;


END IF;

END;

还有话要说,我有一个“ AFTER INSERT”触发器,它工作正常:

CREATE OR REPLACE TRIGGER TRG_TALLER_AI_CLASE AFTER INSERT ON T_TALLER FOR EACH ROW
BEGIN

DELETE T_TALLER_CLASE WHERE FK_TALLER = :NEW.PK;

Pkg_Utilidades.p_ins_taller_clase_grupo(:NEW.PK,:NEW.FEC_INI,:NEW.FEC_FIN,:NEW.DIAS,:NEW.AU_USU_INS);


END;

过程是:

PROCEDURE p_ins_taller_clase_grupo (p_taller NUMBER,
                                p_fec_ini DATE,
                                p_fec_fin DATE,
                                p_dias DIA_TAB,
                                p_user VARCHAR2) IS
p_output VARCHAR2(100);  
v_dia NUMBER;
BEGIN

FOR REC IN (SELECT p_fec_ini + LEVEL - 1 FECHA,
            DECODE(TO_CHAR(p_fec_ini + LEVEL - 1 , 'DAY'),'MONDAY   ',1,'TUESDAY  ',2,'WEDNESDAY',3,'THURSDAY ',4,'FRIDAY   ',5,'SATURDAY ',6,7) DIA
            FROM DUAL
            CONNECT BY LEVEL <= p_fec_fin - p_fec_ini  + 1) LOOP

    BEGIN

        SELECT D INTO v_dia
        FROM (
            SELECT decode(upper(T.dia),'LUNES',1,'MARTES',2,'MIERCOLES',3,'MIÉRCOLES',3,'JUEVES',4,'VIERNES',5,'SABADO',6,'SÁBADO',6,7) D                
            FROM TABLE(p_dias) T
            )             
        WHERE D = REC.DIA;

        P_INS_TALLER_CLASE (p_taller,REC.FECHA,Pkg_conf.CST_HORA,p_user,p_output);

    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            NULL;
    END;



END LOOP;


END p_ins_taller_clase_grupo;                                   

插入可以正常工作:

SQL> insert into t_taller (FK_profesor,fk_danza,fk_local,fk_periodicidad,fec_ini,fec_fin,dias,AU_USU_INS) values (1,1,1,1,to_date('05/01/2019','dd/mm/yyyy'),to_date('27/01/2019','dd/mm/yyyy'),dia_tab(dia_t('SABADO','10:30'),dia_t('DOMINGO','10:30')),'EP_PL01');

1 row created.

SQL> commit;

Commit complete.

SQL> update t_taller set fec_fin = fec_fin + 20 where pk = 24;
update t_taller set fec_fin = fec_fin + 20 where pk = 24
       *
ERROR at line 1:
ORA-22903: MULTISET expression not allowed
ORA-06512: at "ESTAMPAS.PKG_UTILIDADES", line 451
ORA-06512: at "ESTAMPAS.TRG_TALLER_AU_FEC_FIN", line 5
ORA-04088: error during execution of trigger 'ESTAMPAS.TRG_TALLER_AU_FEC_FIN'

包的第451行位于过程内,恰好在这里:

        SELECT D INTO v_dia
        FROM (
            SELECT decode(upper(T.dia),'LUNES',1,'MARTES',2,'MIERCOLES',3,'MIÉRCOLES',3,'JUEVES',4,'VIERNES',5,'SABADO',6,'SÁBADO',6,7) D                
            FROM TABLE(p_dias) T
            )             
        WHERE D = REC.DIA;

很抱歉没有从一开始就发布所有详细信息,我想总结一下并仅显示错误。

致谢

2 个答案:

答案 0 :(得分:2)

如果在表本身上运行选择查询,则

TABLE表达式将起作用。

类似

SELECT T.DIA , T.HORA                
            FROM T_TALLER ,TABLE(:NEW.DIAS) T

但是,您不允许从触发器所有者中进行选择,因为它会导致“表正在变异”错误( ORA-04091 )。

您可以改为使用简单的for loop遍历嵌套表列。

CREATE OR REPLACE TRIGGER trg_taller_au_fec_fin AFTER
     UPDATE OF fec_fin ON t_taller
     FOR EACH ROW
BEGIN
     FOR i in 1 .. :new.dias.count
     LOOP
          dbms_output.put_line(:new.dias(i).dia || ' ' || :new.dias(i).hora);
     END LOOP;
END;
/

顺便说一句,如@XING所述,触发器中没有使用dbms_output。您应该考虑将它们记录到表中。

Demo

答案 1 :(得分:0)

如我的评论所述Triggers用于处理表to上的事件。尽管您发布的脚本对我来说没有多大意义,但是我正在给出解决方案。 同样,您根本无法从Select表中Nested条记录。您需要使用表运算符来执行此操作。同样在触发器中,如果您在同一表上执行“选择”,则可能会出现mutating, trigger/function。参见下面的演示:

CREATE OR REPLACE TYPE dia_t AS OBJECT (
    dia    VARCHAR2(9),
    hora   VARCHAR2(6)
);


CREATE OR REPLACE TYPE DIA_TAB IS TABLE OF DIA_T;

CREATE TABLE t_taller (
    pk        NUMBER   ,
    dias      dia_tab,
    fec_ini   DATE NOT NULL,
    fec_fin   DATE NOT NULL,
    CONSTRAINT cst_primkey_taller PRIMARY KEY ( pk )
)
NESTED TABLE dias STORE AS dias_tab;

INSERT INTO t_taller VALUES (
    1,
    dia_tab(dia_t(
        'A',
        'B')
    ),
    TO_DATE('10-Dec-2018','DD-Mon-YYYY'),
    TO_DATE('10-Dec-2018','DD-Mon-YYYY')
);

CREATE OR REPLACE TRIGGER trg_taller_au_fec_fin 
AFTER UPDATE OF fec_fin ON t_taller
FOR EACH ROW
BEGIN
    FOR rec IN ( SELECT t.dia,
                        t.hora
                 FROM  t_taller e,TABLE (e.dias ) t) --This is how you select records from nested table 
    LOOP
        dbms_output.put_line(rec.dia || ' ' || rec.hora);
    END LOOP;
END;

输出:

Error starting at line : 40 in command -
update t_taller set fec_fin = fec_fin + 20 where pk = 1
Error report -
ORA-04091: table SYSTM.T_TALLER is mutating, trigger/function may not see it
ORA-06512: at "SYSTM.TRG_TALLER_AU_FEC_FIN", line 2
ORA-04088: error during execution of trigger 'SYSTM.TRG_TALLER_AU_FEC_FIN'

因此,您再次需要重新考虑您的要求。