Oracle - Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

   
Vista:
Imágen de perfil de Lisandro Daniel

Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

Publicado por Lisandro Daniel (4 intervenciones) el 21/06/2015 19:19:42
Buenas tardes, hace poco diseñé la siguiente función, con su respectivo disparador en una base de datos bajo PostgreSQL

CREATE OR REPLACE FUNCTION generar_usuario() RETURNS TRIGGER AS $generar_usuario$
DECLARE
USUARIO text;
CLAVE text;
BEGIN
IF (TG_OP = 'UPDATE') THEN
USUARIO := (SELECT "CODIGO_NACIONALIDAD" FROM "PERSONAS", "NACIONALIDAD" WHERE NEW."NACIONALIDAD" = "NACIONALIDAD"."ID") || NEW."CEDULA";
CLAVE := MD5((SELECT "CODIGO_NACIONALIDAD" FROM "PERSONAS", "NACIONALIDAD" WHERE NEW."NACIONALIDAD" = "NACIONALIDAD"."ID") || NEW."CEDULA");
UPDATE "USUARIOS" SET "USUARIO" = USUARIO, "CLAVE" = CLAVE WHERE OLD."ID" = "USUARIOS"."PERSONA";
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
USUARIO := (SELECT "CODIGO_NACIONALIDAD" FROM "PERSONAS", "NACIONALIDAD" WHERE NEW."NACIONALIDAD" = "NACIONALIDAD"."ID") || NEW."CEDULA";
CLAVE := MD5((SELECT "CODIGO_NACIONALIDAD" FROM "PERSONAS", "NACIONALIDAD" WHERE NEW."NACIONALIDAD" = "NACIONALIDAD"."ID") || NEW."CEDULA");
INSERT INTO "USUARIOS"("ID", "USUARIO", "CLAVE", "PERSONA") VALUES(NEW."ID", USUARIO, CLAVE, NEW."ID");
RETURN NEW;
END IF;
RETURN NULL;
END;
$generar_usuario$ language plpgsql;

CREATE TRIGGER generar_usuario AFTER INSERT OR UPDATE ON "PERSONAS" FOR EACH ROW EXECUTE PROCEDURE generar_usuario();

...dicho código permite generar un insert y/o update en otra tabla llamada "USUARIOS", luego de ser insertados y/o actualizados los datos en la tabla "PERSONAS", proceso que se realiza de forma automatizada sin inconvenientes.
La ayuda que necesito es para convertir este código en una función con disparador, que pueda ser utilizada en Oracle, con el mismo propósito (ya que estoy migrando la base de datos actual bajo postgresql a oracle express)
He intentado utilizar el siguiente código (para probar la parte de eventos de inserción)

CREATE OR REPLACE TRIGGER "GENERAR_USUARIO"
AFTER INSERT ON PERSONAS
FOR EACH ROW
BEGIN
INSERT INTO "USUARIOS"("ID", "USUARIO", "CLAVE", "PERSONA") VALUES(:NEW."ID", (SELECT "CODIGO_NACIONALIDAD" FROM NACIONALIDAD, PERSONAS WHERE :NEW."NACIONALIDAD" = NACIONALIDAD.ID) || :NEW."CEDULA", MD5((SELECT "CODIGO_NACIONALIDAD" FROM NACIONALIDAD, PERSONAS WHERE :NEW."NACIONALIDAD" = NACIONALIDAD.ID) || :NEW."CEDULA"),:NEW."ID");
END "GENERAR_USUARIO";

/
ALTER TRIGGER "GENERAR_USUARIO" ENABLE
/

obtengo como error lo siguiente al insertar un registro en la tabla "PERSONAS"

error ORA-04091: table KRIOS.PERSONAS is mutating, trigger/function may not see it ORA-06512: at "KRIOS.GENERAR_USUARIO", line 2 ORA-04088: error during execution of trigger 'KRIOS.GENERAR_USUARIO'

No logro dar con la falla, luego de evaluar el código con Oracle APEX, me indica "Este disparador no tiene ningún error.". De antemano agradezco la ayuda y orientación que puedan brindarme en mis primeros pasos en Oracle.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

Publicado por Rafael (177 intervenciones) el 22/06/2015 14:46:54
El tema esta en que;

1. Sintacticamente las instrucciones son correctas, es decir NO hay errores de COMPILACION.
2. Solicitas informacion de la misma tabla en la que estas disparando el trigger.
3. Al parecer tendras mas de un problema por que lo que solicitas es un bastante raro....

Veamos lo que tu has escrito:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
CREATE
	OR REPLACE TRIGGER GENERAR_USUARIO AFTER
 
INSERT ON PERSONAS
FOR EACH ROW
 
BEGIN
	INSERT INTO USUARIOS (
		ID
		,USUARIO
		,CLAVE
		,PERSONA
		)
	VALUES (
		:NEW.ID
		,(
			SELECT CODIGO_NACIONALIDAD
			FROM NACIONALIDAD
				,PERSONAS
			WHERE :NEW.NACIONALIDAD = NACIONALIDAD.ID
			) || :NEW.CEDULA
		,MD5((
				SELECT CODIGO_NACIONALIDAD
				FROM NACIONALIDAD
					,PERSONAS
				WHERE :NEW.NACIONALIDAD = NACIONALIDAD.ID
				) || :NEW.CEDULA)
		,:NEW.ID
		);
END GENERAR_USUARIO;/
 
ALTER TRIGGER GENERAR_USUARIO ENABLE /

Errores a la vista
1. En un FROM mencionas dos tablas distintas y no haces un JOIN, el resultado es producto cartesiano, N valores en A POR X valores en Y...

2. Estas Ejecutando 2 Queries para traer el MISMO DATO, es un error o cuando menos MALA practica ya que si realizas Miles de inserciones ejecutas la consulta DOS MILES de veces, espero haberme dado a entender...

Te dejo algo que espero te sirva:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE OR REPLACE TRIGGER GENERAR_USUARIO AFTER
INSERT ON PERSONAS
FOR EACH ROW
BEGIN
	INSERT INTO USUARIOS (
		ID
		,USUARIO
		,CLAVE
		,PERSONA
		)
	VALUES
	SELECT :NEW.ID
	     , CODIGO_NACIONALIDAD||:NEW.CEDULA
             , MD5(CODIGO_NACIONALIDAD||:NEW.CEDULA)
	     , :NEW.ID
    FROM   NACIONALIDAD
	WHERE  NACIONALIDAD.ID = :NEW.NACIONALIDAD;
END GENERAR_USUARIO;/
 
ALTER TRIGGER GENERAR_USUARIO ENABLE /
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Lisandro Daniel

Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

Publicado por Lisandro Daniel (4 intervenciones) el 25/06/2015 02:48:24
b]Buenas noches, Rafael... Te cuento que al fin encontré el modo de solventarlo... Comencé creando un paquete:[/b]

CREATE OR REPLACE PACKAGE pck_usuarios AS
v_id PRUEBA1.ID%TYPE;
v_usuario VARCHAR2(50);
END;

Posteriormente generé los triggers aislando cada proceso, sin usar "for each row" para no generar el error de tabla mutante...

Solución por proceso de inserción:
CREATE OR REPLACE TRIGGER GENERAR_USUARIO AFTER INSERT ON PRUEBA1
BEGIN
SELECT NAC.CN || CEDULA INTO pck_usuarios.v_usuario FROM NAC, PRUEBA1 WHERE NACIONALIDAD = NAC.ID;
INSERT INTO PRUEBA2(USUARIO) VALUES(pck_usuarios.v_usuario);
END;

Solución por proceso de actualización:

CREATE OR REPLACE TRIGGER ACTUALIZAR_USUARIO AFTER UPDATE OF NACIONALIDAD, CEDULA ON PRUEBA1
BEGIN
SELECT NAC.CN || CEDULA INTO pck_usuarios.v_usuario FROM NAC, PRUEBA1 WHERE NACIONALIDAD = NAC.ID;
UPDATE PRUEBA2 SET USUARIO = pck_usuarios.v_usuario WHERE ID = PRUEBA2.ID;
END;

Solución por proceso de eliminación:

CREATE OR REPLACE TRIGGER ELIMINAR_USUARIO AFTER DELETE ON PRUEBA1

BEGIN
DELETE FROM PRUEBA2 WHERE ID = PRUEBA2.ID;
END;

Por último unifique todo bajo un mismo trigger.

Solución por integración de procesos:


CREATE OR REPLACE TRIGGER PROCESAR_USUARIO AFTER INSERT OR UPDATE OR DELETE ON PRUEBA1
BEGIN
IF INSERTING THEN
SELECT ID INTO pck_usuarios.v_ID FROM PRUEBA1;
SELECT NAC.CN || CEDULA INTO pck_usuarios.v_usuario FROM NAC, PRUEBA1 WHERE NACIONALIDAD = NAC.ID;
INSERT INTO PRUEBA2(USUARIO, PRUEBA1) VALUES(pck_usuarios.v_usuario, pck_usuarios.v_id);
ELSIF UPDATING THEN
SELECT NAC.CN || CEDULA INTO pck_usuarios.v_usuario FROM NAC, PRUEBA1 WHERE NACIONALIDAD = NAC.ID;
UPDATE PRUEBA2 SET USUARIO = pck_usuarios.v_usuario WHERE ID = PRUEBA2.ID;
ELSIF DELETING THEN
DELETE FROM PRUEBA2 WHERE ID = PRUEBA2.ID;
END IF;
END;

Y así logré salir del atasco. En estos momentos solo me falta ver lo del proceso de encriptación del campo "password" del usuario.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Lisandro Daniel

Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

Publicado por Lisandro Daniel (4 intervenciones) el 25/06/2015 03:09:03
Rafael, me sirvió lo que me comentaste, aparte de lo que estuve investigando en la documentación técnica oficial de la oracle respecto a tablas mutantes.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Lisandro Daniel

Ayuda para crear un trigger a partir de otro trigger utilizado en postgresql

Publicado por Lisandro Daniel (4 intervenciones) el 25/06/2015 05:56:28
AH SI... el código anterior solo funciona para insertar una fila, ahora debo generar un array o cursor para que sirva la insercion con varias filas, es decir cada nuevo registro insertado....
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar