Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Oracle »

Trigger Oracle se crea pero no Actualiza

Estas en el tema de Trigger Oracle se crea pero no Actualiza en el foro de Oracle en Foros del Web. Hola buenas gente!: Saludos a todos. Estoy trantando de actualizar una tabla en Oracle 11g a treavés de un trigger. El trigger se compila bien. ...
  #1 (permalink)  
Antiguo 13/06/2016, 12:40
Avatar de freddy31DA  
Fecha de Ingreso: junio-2012
Mensajes: 84
Antigüedad: 11 años, 10 meses
Puntos: 2
Busqueda Trigger Oracle se crea pero no Actualiza

Hola buenas gente!:
Saludos a todos.
Estoy trantando de actualizar una tabla en Oracle 11g a treavés de un trigger. El trigger se compila bien. Pero cuando realizo el update en la tabla Prestamo se salta un error que ya vengo soportando:
La tabla:
Código sql:
Ver original
  1. CREATE TABLE Prestamo(
  2.  idLector NUMERIC(10) NOT NULL,
  3.  idLibro NUMERIC(10) NOT NULL,
  4.  FechaPrestamo DATE NOT NULL,
  5.  FechaDev DATE  NULL,
  6.  FechaRealDev DATE NULL,
  7.  Mora NUMBER(19,4) NULL,
  8.  estado NUMBER(1) NULL,
  9.  CONSTRAINT idlectorPrestamo_fk FOREIGN KEY (idLector) REFERENCES Estudiante(idLector),
  10.  CONSTRAINT idLibroPrestamo_fk FOREIGN KEY (idLibro) REFERENCES Libro(idLibro)
  11. );

La cosa es así: Si un lector quiere entregar un libro y este se a pasado de la fecha se le suma 5 de Mora:
Registro 1:
Código sql:
Ver original
  1. INSERT INTO Prestamo VALUES (1,1,'9-6-2016','12-6-2016','','',0);
  2. -- 0 = prestado
  3. -- 1 entregado
  4. --Devuelve:
  5.     UPDATE Prestamo SET estado=1 WHERE idLector=1 AND idLibro=1

Este es el trigger que e creado:
Código sql:
Ver original
  1. CREATE OR REPLACE TRIGGER TR_CALCULARMORA
  2.     AFTER UPDATE
  3.      ON Prestamo
  4.      FOR EACH ROW
  5.     DECLARE
  6.         dias INTEGER;
  7.         fechaDevOriginal DATE;
  8.     BEGIN
  9.          SELECT fechaDev INTO fechaDevOriginal FROM Prestamo WHERE idLector=:OLD.idLector AND idLibro=:OLD.idLibro;
  10.          SELECT trunc(sysdate) - to_date(fechaDevOriginal, 'dd-mm-yyyy') INTO dias FROM dual;
  11.          IF dias > 3 THEN
  12.           UPDATE Prestamo SET Mora=(dias-3)*5, FechaRealDev=sysdate
  13.           WHERE idLector=:OLD.idLector AND idLibro=:OLD.idLibro;
  14.           END IF;
  15.     END;
Como veran estoy tratando de actualizar la tabla Prestamo luego de la entrega - Ahí mismo debe de disparar este trigger comprobando si hay mora o no. Le resto 3 dias por que esos no cuentan solo en adelante. Con ese artilugio estoy contando cuantos dias han pasado luego de la fecha que quedo pendiente en la devolución.

El error que obtengo es:

Código sql:
Ver original
  1. UPDATE Prestamo SET estado=1 WHERE idLector=1 AND idLibro=1
  2. Informe de error -
  3. Error SQL: ORA-04091: TABLE ADMINORACLE11G.PRESTAMO IS mutating, TRIGGER/FUNCTION may NOT see it
  4. ORA-06512: at "ADMINORACLE11G.TR_CALCULARMORA", line 5
  5. ORA-04088: error during execution OF TRIGGER 'ADMINORACLE11G.TR_CALCULARMORA'
  6. 04091. 00000 -  "table %s.%s is mutating, trigger/function may not see it"
  7. *Cause:    A TRIGGER (OR a USER defined plsql FUNCTION that IS referenced IN
  8.            this statement) attempted TO look at (OR MODIFY) a TABLE that was
  9.            IN the middle OF being modified BY the statement which fired it.
  10. *Action:   Rewrite the TRIGGER (OR FUNCTION) so it does NOT READ that TABLE.

La verdad si alguien me puede ayudar con esto etare agradecido.
Gracias
__________________
Creo en Internet.
Amén.

Última edición por freddy31DA; 13/06/2016 a las 13:03
  #2 (permalink)  
Antiguo 13/06/2016, 14:13
Avatar de freddy31DA  
Fecha de Ingreso: junio-2012
Mensajes: 84
Antigüedad: 11 años, 10 meses
Puntos: 2
Respuesta: Trigger Oracle se crea pero no Actualiza

UPDATE: la condición es dias > 0 puesto que se coge la fecha quedo en devolver y demas ya no se resta solo directo Mora=dias*5 puesto que se coge la fechaDev
__________________
Creo en Internet.
Amén.

Última edición por freddy31DA; 13/06/2016 a las 14:49
  #3 (permalink)  
Antiguo 14/06/2016, 05:13
Avatar de AVBorland  
Fecha de Ingreso: marzo-2016
Ubicación: Moscu
Mensajes: 42
Antigüedad: 8 años, 1 mes
Puntos: 4
Respuesta: Trigger Oracle se crea pero no Actualiza

Hola!
No puede usted utilizar select, insert, update, delete una fila en tabla cuando realiza trigger de fila nivel (FOR EACH ROW) en esta tabla. Puede utilizar tabla rowindex y varios triggeros de operación nivel (solo before insert, update, delete y after insert, update, delete)

Última edición por AVBorland; 14/06/2016 a las 05:26
  #4 (permalink)  
Antiguo 14/06/2016, 06:00
Avatar de AVBorland  
Fecha de Ingreso: marzo-2016
Ubicación: Moscu
Mensajes: 42
Antigüedad: 8 años, 1 mes
Puntos: 4
Respuesta: Trigger Oracle se crea pero no Actualiza

Cita:
Iniciado por AVBorland Ver Mensaje
Puede utilizar tabla rowindex
Perdone, por favor...Tabla PL/SQL
  #5 (permalink)  
Antiguo 14/06/2016, 07:51
Avatar de huesos52
Colaborador
 
Fecha de Ingreso: febrero-2009
Ubicación: Manizales - Colombia
Mensajes: 5.980
Antigüedad: 15 años, 2 meses
Puntos: 360
Respuesta: Trigger Oracle se crea pero no Actualiza

Efectivamente, no es posible hacer este tipo de operaciones sobre un trigger que afecta directamente la misma tabla.
A esto, se le conoce como tablas mutantes. Sin embargo, para lograr tu objetivo, pudes jugar un poco con las variables OLD y NEW.

Prueba este treigger:
Código SQL:
Ver original
  1. CREATE OR REPLACE TRIGGER TR_CALCULARMORA
  2. BEFORE UPDATE
  3. ON Prestamo
  4. FOR EACH ROW
  5. DECLARE
  6.   dias INTEGER;
  7. BEGIN
  8.   DIAS := TRUNC(SYSDATE) - :OLD.FECHADEV;
  9.   IF dias > 3 THEN
  10.     :NEW.MORA:=(DIAS-3)*5;
  11.     :NEW.FECHAREALDEV:=SYSDATE;        
  12.   END IF;
  13. END;
  14. /


De esta forma, no se realizan operaciones sobre la tabla, solo se aprovechan los valores actuales reales de la tabla.

Nos cuentas
__________________
Without data, You are another person with an opinion.
W. Edwads Deming
  #6 (permalink)  
Antiguo 14/06/2016, 08:23
Avatar de AVBorland  
Fecha de Ingreso: marzo-2016
Ubicación: Moscu
Mensajes: 42
Antigüedad: 8 años, 1 mes
Puntos: 4
Respuesta: Trigger Oracle se crea pero no Actualiza

Cita:
Iniciado por huesos52 Ver Mensaje
Código SQL:
Ver original
  1. CREATE OR REPLACE TRIGGER TR_CALCULARMORA
  2. BEFORE UPDATE
  3. ON Prestamo
Por que BEFORE UPDATE?
Yo creo que:
Utilizar
Código SQL:
Ver original
  1. CREATE OR REPLACE package test_Package AS
  2.   TYPE TTmpRec IS record (id_lib INTEGER, Mora INTEGER);
  3.   TYPE TTmpTabla IS TABLE OF TTmpRec INDEX BY binary_integer;
  4.  
  5.   TempTabla TTmpTabla;
  6.   Latch BOOLEAN:=FALSE;
  7.   PROCEDURE Update_Data;
  8. END;
  9. /
  10.  
  11. CREATE OR REPLACE TRIGGER TR_CALCULARMORA_TMP
  12.     AFTER UPDATE
  13.      ON Prestamo
  14.      FOR EACH ROW
  15.     DECLARE
  16.         dias INTEGER;
  17.         fechaDevOriginal DATE;
  18.     BEGIN
  19.          SELECT fechaDev INTO fechaDevOriginal FROM Prestamo WHERE idLector=:OLD.idLector AND idLibro=:OLD.idLibro;
  20.          SELECT trunc(sysdate) - to_date(fechaDevOriginal, 'dd-mm-yyyy') INTO dias FROM dual;
  21.          IF dias > 3 THEN
  22.           Test_Package.TempTabla(:OLD.idLector).id_lib:=:OLD.idLibro;
  23.           Test_Package.TempTabla(:OLD.idLector).Mora:=(dias-3)*5;
  24.          END IF;
  25.     END;
  26. /
  27.  
  28. CREATE OR REPLACE TRIGGER TR_CALCULARMORA
  29. After INSERT OR UPDATE OR DELETE ON Prestamo
  30. BEGIN  IF test_Package.Latch THEN
  31.     Test_Package.Update_Data;
  32.   END IF;
  33. END;
  34. /
Yo escribo procedure Update_Data mas tarde (pordegracias, no tengo tiempo ahora)
  #7 (permalink)  
Antiguo 14/06/2016, 08:36
Avatar de huesos52
Colaborador
 
Fecha de Ingreso: febrero-2009
Ubicación: Manizales - Colombia
Mensajes: 5.980
Antigüedad: 15 años, 2 meses
Puntos: 360
Respuesta: Trigger Oracle se crea pero no Actualiza

Cita:
Por que BEFORE UPDATE?
Creo que para la necesidad de freddy31DA, es indiferente si se hace antes, en el instante o después de la ejecución de la sentencia.

Saludos
__________________
Without data, You are another person with an opinion.
W. Edwads Deming
  #8 (permalink)  
Antiguo 14/06/2016, 17:17
Avatar de AVBorland  
Fecha de Ingreso: marzo-2016
Ubicación: Moscu
Mensajes: 42
Antigüedad: 8 años, 1 mes
Puntos: 4
Respuesta: Trigger Oracle se crea pero no Actualiza

Buenos noches!

1. Datos inicialos:

Código SQL:
Ver original
  1. CREATE TABLE Prestamo(
  2.  idLector NUMERIC(10) NOT NULL,
  3.  idLibro NUMERIC(10) NOT NULL,
  4.  FechaPrestamo DATE NOT NULL,
  5.  FechaDev DATE  NULL,
  6.  FechaRealDev DATE NULL,
  7.  Mora NUMBER(19,4) NULL,
  8.  estado NUMBER(1) NULL
  9. );
  10. INSERT INTO Prestamo VALUES (1,1,to_date('09-06-2016','DD-MM-YYYY'),to_date('12-06-2016','DD-MM-YYYY'),'','',0);
  11. INSERT INTO Prestamo VALUES (1,2,to_date('09-06-2016','DD-MM-YYYY'),to_date('12-06-2016','DD-MM-YYYY'),'','',0);
  12. INSERT INTO Prestamo VALUES (1,3,to_date('09-06-2016','DD-MM-YYYY'),to_date('12-06-2016','DD-MM-YYYY'),'','',0);
  13.  
  14. SQL> SELECT * FROM prestamo;
  15.  
  16.   IDLECTOR    IDLIBRO FECHAPRES FECHADEV  FECHAREAL       MORA     ESTADO
  17. ---------- ---------- --------- --------- --------- ---------- ----------
  18.          1          1 09-JUN-16 12-JUN-16                               0
  19.          1          2 09-JUN-16 12-JUN-16                               0
  20.          1          3 09-JUN-16 12-JUN-16                               0
  21.  
  22. SQL>

2. Realizo triggeros:
Código SQL:
Ver original
  1. CREATE OR REPLACE package Test_Package AS
  2.   TYPE TTmpRec IS TABLE OF INTEGER INDEX BY Binary_integer;
  3.   TYPE TTmpTabla IS TABLE OF TTmpRec INDEX BY binary_integer;
  4.  
  5.   TempTabla TTmpTabla;
  6.   Latch BOOLEAN:=FALSE;
  7.   PROCEDURE Update_Data;
  8. END;
  9. /
  10.  
  11. CREATE OR REPLACE package body Test_Package AS
  12.  i INTEGER;
  13.  j INTEGER;
  14.  PROCEDURE Update_Data AS
  15.   BEGIN
  16.    latch := TRUE;
  17.    IF test_Package.TempTabla.Count>0 THEN
  18.      i:=test_Package.TempTabla.FIRST;
  19.      while i IS NOT NULL loop
  20.        j:=test_Package.TempTabla(i).FIRST;
  21.        while j IS NOT NULL loop
  22.          UPDATE Prestamo SET Mora=test_Package.TempTabla(i)(j) WHERE idLector=i AND idLibro=j;
  23.          j:=test_Package.TempTabla(i).NEXT(j);
  24.        END loop;
  25.        i:=test_Package.TempTabla.NEXT(i);
  26.      END loop;
  27.    END IF;
  28.    latch := FALSE;
  29.   exception WHEN others THEN  
  30.   latch := FALSE;
  31.   raise;
  32.    latch := FALSE;
  33.   END;
  34. END;
  35. /
  36.  
  37. CREATE OR REPLACE TRIGGER TR_CALCULARMORA_TMP
  38.     AFTER UPDATE
  39.      ON Prestamo
  40.      FOR EACH ROW
  41.     DECLARE
  42.         dias INTEGER;
  43.     BEGIN
  44.          DIAS := TRUNC(SYSDATE) - :NEW.FECHADEV;
  45.          IF dias > 3 THEN
  46.           Test_Package.TempTabla(:OLD.idLector)(:OLD.idLibro):=(dias-3)*5;
  47.          END IF;
  48.     END;
  49. /
  50.  
  51. CREATE OR REPLACE TRIGGER TR_CALCULARMORA
  52. After INSERT OR UPDATE OR DELETE ON Prestamo
  53. BEGIN  
  54.   IF NOT test_Package.Latch THEN
  55.     Test_Package.Update_Data;
  56.   END IF;
  57. END;
  58. /
  59.  
  60. CREATE OR REPLACE TRIGGER Init_TEST
  61. BEFORE INSERT OR UPDATE OR DELETE ON Prestamo
  62. BEGIN
  63.   IF NOT Test_Package.latch THEN
  64.     Test_Package.TempTabla.DELETE();
  65.   END IF;
  66. END;
  67. /

3. Resultado:
Código BASH:
Ver original
  1. SQL> select * from prestamo;
  2.  
  3.   IDLECTOR    IDLIBRO FECHAPRES FECHADEV  FECHAREAL       MORA     ESTADO
  4. ---------- ---------- --------- --------- --------- ---------- ----------
  5.          1          1 09-JUN-16 12-JUN-16                               0
  6.          1          2 09-JUN-16 12-JUN-16                               0
  7.          1          3 09-JUN-16 12-JUN-16                               0
  8.  
  9. SQL> UPDATE Prestamo SET FECHADEV=to_date('10-06-2016','DD-MM-YYYY') WHERE idLector=1 ;
  10.  
  11. 3 rows updated.
  12.  
  13. SQL> commit;
  14.  
  15. Commit complete.
  16.  
  17. SQL> select * from prestamo;
  18.  
  19.   IDLECTOR    IDLIBRO FECHAPRES FECHADEV  FECHAREAL       MORA     ESTADO
  20. ---------- ---------- --------- --------- --------- ---------- ----------
  21.          1          1 09-JUN-16 10-JUN-16                   10          0
  22.          1          2 09-JUN-16 10-JUN-16                   10          0
  23.          1          3 09-JUN-16 10-JUN-16                   10          0
  24.  
  25. SQL> select to_char(sysdate,'DD-MM-YYYY HH24:MI:SS') from dual;
  26.  
  27. TO_CHAR(SYSDATE,'DD
  28. -------------------
  29. 15-06-2016 02:16:46
  30.  
  31. SQL>SQL> UPDATE Prestamo SET FECHADEV=to_date('11-06-2016','DD-MM-YYYY') WHERE idLeсtor=1;
  32.  
  33. 3 rows updated.
  34.  
  35. SQL> commit;
  36.  
  37. Commit complete.
  38.  
  39. SQL> select * from prestamo;
  40.  
  41.  IDLECTOR    IDLIBRO FECHAPRES FECHADEV  FECHAREAL       MORA     ESTADO
  42. ---------- ---------- --------- --------- --------- ---------- ----------
  43.         1          1 09-JUN-16 11-JUN-16                    5          0
  44.         1          2 09-JUN-16 11-JUN-16                    5          0
  45.         1          3 09-JUN-16 11-JUN-16                    5          0
  46.  
  47. SQL>

Última edición por AVBorland; 15/06/2016 a las 04:22

Etiquetas: bases-de-datos-general, trigger
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 01:40.