You are on page 1of 38

Disparadores en ORACLE

Diseo de Bases de Datos y Seguridad de la Informacin

2008 Beln Vela

PL/SQL-1

Disparadores en ORACLE
PL/SQL: lenguaje de programacin estructurado en bloques Bloques: unidad mnima en PL/SQL
Soportan DML y DDL Annimos / Con nombre
DECLARE optional BEGIN required EXCEPTION optional END; required /

Disparadores (triggers) en Oracle: bloques de cdigo que son implcitamente invocados cuando algo sucede Triggers vs. Procedimientos
Ejecucin implcita: Disparar No admiten argumentos
CREATE TRIGGER NombreTrigger BEFORE INSERT ON StarsIn DECLARE .. END; TRIGGER /

Aplicaciones
Restricciones (Constraints) Auditoras Informar de eventos

2008 Beln Vela

CREATE PROCEDURE Get_emp_rec (Emp_number IN Emp_tab.Empno%TYPE) AS BEGIN - - - - END; PROCEDIMIENTO / PL/SQL-2

Disparadores en ORACLE

3 Tipos de Disparadores: DML (Fila/Sentencia, BEFORE/AFTER) INSTEAD OF (vistas) SYSTEM


2008 Beln Vela

PL/SQL-3

Disparadores en ORACLE Estructura General de un Disparador


CREATE [OR REPLACE] TRIGGER nombre {BEFORE | AFTER | INSTEAD OF} Temporalidad del Evento {INSERT | DELETE | UPDATE [OF <atributo>]} ON <tabla> [FOR EACH ROW | STATEMENT] [WHEN condicin]
[DECLARE ] BEGIN cuerpo del trigger [EXCEPTION ] END; /
2008 Beln Vela

Evento

Granularidad

Condicin

Accin

PL/SQL-4

Disparadores en ORACLE Estructura General de un Disparador Ejemplo


INVENTARIO (num_producto, descripcin, unidades_dispon, punto_pedido, cantidad_pedido)

PEDIDOSPENDIENTES (num_producto, cantidad_pedido, fecha_pedido)

UPDATE Inventario SET unidades_dispon=unidades_dispon-3 WHERE num_producto=10456;


SI el nmero de unidades disponibles de ese producto (num_producto=10456) en el inventario es inferior al punto de pedido ENTONCES: se genera una nueva orden de pedido

INSERT INTO PedidosPendientes VALUES (10456, 100, 1/01/2009 );


2008 Beln Vela

PL/SQL-5

Disparadores en ORACLE Estructura General de un Disparador


CREATE OR REPLACE TRIGGER Disparador atributo tabla AFTER UPDATE OF unidades_dispon ON Inventario FOR EACH ROW WHEN (new.unidades_dispon < new.punto_pedido)

Evento Condicin

Cuando el nmero de unidades en el inventario sea inferior al punto de pedido. DECLARE X NUMBER; Accin BEGIN -- Nmero de pedidos pendientes de ese producto SELECT COUNT(*) INTO X FROM PedidosPendientes WHERE num_producto=:new.num_producto; -- Si no hay ninguna orden de pedido, hacer el pedido IF x = 0 THEN INSERT INTO PedidosPendientes VALUES (:new.num_producto, :new.cantidad_pedido, SYSDATE); END IF; 2008 Beln END; Vela PL/SQL-6

Disparadores en ORACLE Temporalidad del Evento: AFTER / BEFORE


BEFORE Ejecutan la accin asociada antes de que la sentencia sea ejecutada Decidir si la accin debe realizarse o no Utilizar valores alternativos para la sentencia CREATE TRIGGER NombreTrigger BEFORE Insert ON NombreTabla . AFTER Ejecutan la accin asociada despus de que se haya ejecutado la sentencia CREATE TRIGGER NombreTrigger AFTER Insert ON NombreTabla .

2008 Beln Vela

PL/SQL-7

Disparadores en ORACLE Granuralidad del Evento: FOR EACH ROW / STATEMENT


A NIVEL DE FILA: ROW TRIGGERS Ejecutan la accin asociada tantas veces como filas se vean afectadas por la sentencia que lo dispara Si ninguna fila se ve afectada, no se dispara CREATE TRIGGER NombreTrigger BEFORE UPDATE ON NombreTabla FOR EACH ROW [WHEN ]. A NIVEL DE SENTENCIA: STATEMENT TRIGGERS Ejecutan una nica vez la accin asociada, independientemente del nmero de filas que se vean afectadas por la sentencia (incluso si no hay filas afectadas). CREATE TRIGGER NombreTrigger BEFORE INSERT ON NombreTabla 2008 Beln Vela [STATEMENT] . . . opcin por defecto PL/SQL-8

Disparadores en ORACLE
Ejemplo: A NIVEL DE FILA (ROW TRIGGER) Cuando Cuandose seborre borreen enla latabla tablaPersona Personaalguna algunapersona personaque que se sellame llamepepe pepeo ocuya cuyaedad edadsea seamayor mayorde de35 35aos, aos, eliminar eliminartambin tambindicha dichapersona personade dela latabla tablaPersona2. Persona2.

Persona Cod Nombre Edad


C1 C2 C3 C4 C5 Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

Persona2 Cod
C1 C2 C3 C4 C5

Nombre Edad
Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

2008 Beln Vela

DELETE DELETE FROM FROM Persona Persona WHERE cod in WHERE cod in (C1,C3,C4) (C1,C3,C4)

Borra C3 y C4 de Persona2
PL/SQL-9

Disparadores en ORACLE
Ejemplo: A NIVEL DE SENTENCIA (STATEMENT) Cuando Cuandose seborre borreen enla latabla tablaSocio Socioemitir emitirun un mensaje mensajeindicando indicandoque queno nose sedeberan deberanborrar borrarsocios socios

Socio Cod Nombre Fecha_ant


S1 S2 S3 S4 S5 Mara Pepe Pepe Luisa Pepe ...... ...... ...... ...... ......

DELETE DELETE FROM FROM socio socio WHERE nombre WHERE nombre = = Pepe Pepe
2008 Beln Vela

Borra 3 tuplas y se emite un nico mensaje


PL/SQL-10

Disparadores en ORACLE Orden de Ejecucin


Una sentencia SQL puede disparar varios TRIGGERS. La activacin de un trigger puede disparar la activacin de otros triggers.
Triggers Before (a nivel de sentencia) Para cada fila: 1. Trigger Before (a nivel de fila) 2. Ejecuta la Sentencia 3. Triggers After (a nivel de fila) Triggers After (a nivel de sentencia)

1. 2.

3.

Se compromete o se deshace toda la transaccin. El orden de ejecucin de disparadores del mismo tipo es indeterminado.
PL/SQL-11

2008 Beln Vela

Disparadores en ORACLE Condicin


Expresa una condicin que debe cumplirse en el momento de producirse el evento, para que la accin sea ejecutada. Se evala para cada fila.
WHEN old.nombre = pepe OR old.edad > 35

Debe ser una expresin booleana y no puede contener subconsultas. Se puede utilizar cualquier combinacin de operadores lgicos (AND, OR, NOT) y relacionales (< <= > >= = <>). No se puede especificar una condicin para los disparadores a nivel de sentencia (STATEMENT) ni los disparadores INSTEAD OF.
2008 Beln Vela

PL/SQL-12

Disparadores en ORACLE

Correlation Identifiers: Valores OLD y NEW


Tipo especial de variable PL/SQL tratada como un registro de tipo tabla_modificada%ROWTYPE Con OLD.nombre_columna referenciamos:
al valor que tena la columna antes del cambio debido a una modificacin (UPDATE) al valor de una columna antes de una operacin de borrado sobre la misma (DELETE) al valor NULL para operaciones de insercin (INSERT)

Con NEW.nombre_columna referenciamos:


Al valor de una nueva columna despus de una operacin de insercin (INSERT) Al valor de una columna despus de modificarla mediante una sentencia de modificacin (UPDATE) Al valor NULL para una operacin de borrado (DELETE)
SINTAXIS
2008 Beln Vela

Condicin (WHEN .) En el cuerpo del disparador

OLD, NEW :OLD, :NEW


PL/SQL-13

Disparadores en ORACLE
Ejemplo: A NIVEL DE FILA (ROW TRIGGER) Cuando Cuandose seborre borreen enla latabla tablaPersona Personaalguna algunapersona personaque que se sellame llamepepe pepeo ocuya cuyaedad edadsea seamayor mayorde de35 35aos, aos, eliminar eliminartambin tambindicha dichapersona personade dela latabla tablaPersona2. Persona2.

Persona Cod Nombre Edad


C1 C2 C3 C4 C5 Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

Persona2 Cod
C1 C2 C3 C4 C5

Nombre Edad
Mara Pepe Pepe Luisa Pepe 25 40 45 48 22

2008 Beln Vela

DELETE DELETE FROM FROM Persona Persona WHERE cod in WHERE cod in (C1,C3,C4) (C1,C3,C4)

Borra C3 y C4 de Persona2
PL/SQL-14

Disparadores en ORACLE
Ejemplo: A NIVEL DE FILA (ROW TRIGGER)

CREATE OR REPLACE TRIGGER Disparador AFTER DELETE ON Persona FOR EACH ROW WHEN old.Nombre=Pepe OR old.Edad>35 BEGIN DELETE FROM Persona2 Cod WHERE Cod=:old.Cod; END Disparador; NEW NULL /

Nombre
NULL

Edad
NULL

OLD

2008 Beln Vela

PL/SQL-15

Disparadores en ORACLE Triggers DML Disparados por sentencias DML (de varios tipos): INSERT or UPDATE or DELETE Todas las filas o slo algunas (WHEN)
LIBROS ESTADSTICAS

ISBN 100-09-89 -----

GNERO Novela ----

TTULO El Quijote ----

GNERO Novela Infantil

TOTAL_LIBROS 50 15

CREATE OR REPLACE TRIGGER UpdateEstadisticasGenero AFTER INSERT OR DELETE OR UPDATE ON Libros DECLARE BEGIN CASE UPDATE Estadisticas SET ---------------------END UpdateEstadisticasGenero;
2008 Beln Vela

PL/SQL-16

Disparadores en ORACLE Funciones del Cuerpo del Disparador


Inserting, Deleting, Updating CREATE OR REPLACE TRIGGER Ejemplo BEFORE INSERT OR UPDATE OR DELETE ON tabla BEGIN IF DELETING THEN Acciones asociadas al borrado ELSIF INSERTING THEN Acciones asociadas a la insercin ELSIF UPDATING(COL1) Acciones asociadas a la modificacin ELSIF UPDATING(COL2) Acciones asociadas a la modificacin END IF; END Ejemplo; /
2008 Beln Vela

PL/SQL-17

Disparadores en ORACLE Triggers INSTEAD OF


Slo sobre VISTAS
EMPLEADO
DNI 11111111 ----NOMBRE Jos Garca ---DEPARTAMENTO CT-1 ----

DEPARTAMENTO
NOMBRE Contabilidad - 1 Recursos Humanos CDIGO CT-1 RRHH

CREATE VIEW EmpleadoDpto as SELECT E.DNI, D.Nombre FROM Empleado E, Departamento D WHERE E.Departamento = D.Cdigo; CREATE OR REPLACE TRIGGER InsertEmpleadoDpto INSTEAD OF INSERT ON EmpleadoDpto DECLARE V_Cod Departamento.Cdigo%TYPE; BEGIN SELECT Cdigo INTO V_Cod FROM DEPARTAMENTO Where Nombre= :NEW.Nombre; INSERT INTO Departamento VALUES(:NEW.Nombre, V_Cod); INSERT INTO Empleado VALUES(:NEW.DNI,NULL,V_Cod); END; PL/SQL-18 /

INSERT INTO EmpleadoDpto VALUES (11111111', Contabilidad-1); ERROR en lnea 1: ORA-01779: no se puede modificar una columna que se corresponde con una tabla no reservada por clave
2008 Beln Vela

Disparadores en ORACLE Elevar excepciones en el cuerpo del Disparador


RAISE_APPLICATION_ ERROR (nmero_error, mensaje); Nmero error en el rango: [-20000 y -20999] CREATE OR REPLACE TRIGGER Ejemplo BEFORE DELETE ON tabla FOR EACH ROW BEGIN IF :OLD.columna= valor_no_borrable THEN RAISE_APPLICATION_ERROR(-20000, La fila no se puede borrar); END IF; ... END ejemplo; /
2008 Beln Vela

PL/SQL-19

Disparadores en ORACLE Triggers de Sistema


Disparados por eventos del Sistema o eventos relacionados con las acciones de los Usuarios Sistema CREATE OR REPLACE TRIGGER LogCreations Arranque y parada de BD AFTER CREATE ON SCHEMA BEGIN Transacciones INSERT INTO LogCreates (user_id, object_type, object_name, object_owner, creation_date) Errores VALUES (USER, ORA_DCIT_OBJ_TYPE, ORA_DICT_OBJ_NAME,ORA_DICT_OBJ_OWNER, Usuarios SYSDATE) END LogCreations; Login / Logoff / Sentencias DDL: CREATE, ALTER, DROP,

2008 Beln Vela

PL/SQL-20

Disparadores en ORACLE Declaracin de Variables


CREATE... BEFORE | AFTER ... [FOR EACH ROW ...] DECLARE Declaracin de variables BEGIN

nombre nombre nombre nombre


2008 Beln Vela

CONSTANT NUMBER:=valor; TIPO; nombretabla.nombrecolumna%TYPE; nombretabla%ROWTYPE

PL/SQL-21

Disparadores en ORACLE Activar/Desactivar Disparadores Todos los disparadores asociados a una tabla:
ALTER TABLE nombre_tabla ENABLE ALL TRIGGERS; ALTER TABLE nombre_tabla DISABLE ALL TRIGGERS;
(Por defecto: Todos estn Activados al crearse)

Un disparador especfico:
ALTER TRIGGER nombre_disparador ENABLE; ALTER TRIGGER nombre_disparador DISABLE;

Borrar un Disparador
DROP TRIGGER nombre_disparador;

2008 Beln Vela

PL/SQL-22

Disparadores en ORACLE Consultar informacin sobre los disparadores


Ver todos los disparadores y su estado SELECT TRIGGER_NAME , STATUS FROM USER_TRIGGERS; Ver el cuerpo de un disparador SELECT TRIGGER_BODY FROM USER_TRIGGERS WHERE TRIGGER_NAME=nombre_disparador; Ver la descripcin de un disparador SELECT DESCRIPTION FROM USER_TRIGGERS WHERE TRIGGER_NAME= nombre_disparador;

2008 Beln Vela

PL/SQL-23

Disparadores en ORACLE Ejemplo


CREATE OR REPLACE TRIGGER Reorder AFTER UPDATE OF Parts_on_hand ON Inventory FOR EACH ROW WHEN (new.Parts_on_hand < new.Reorder_point) DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; END;
TRIGGER_BODY -------------------------------------------DECLARE x NUMBER; BEGIN SELECT COUNT(*) INTO x FROM Pending_orders WHERE Part_no = :new.Part_no; IF x = 0 THEN INSERT INTO Pending_orders VALUES (:new.Part_no, :new.Reorder_quantity, sysdate); END IF; END;

SELECT Trigger_body FROM USER_TRIGGERS WHERE Trigger_name = 'REORDER';

SELECT Trigger_type, Triggering_event, Table_name FROM USER_TRIGGERS WHERE Trigger_name = 'REORDER'; TYPE ---------------AFTER EACH ROW TRIGGERING_STATEMENT -------------------------UPDATE TABLE_NAME -----------INVENTORY

2008 Beln Vela

PL/SQL-24

Disparadores en ORACLE Restricciones: Tablas Mutantes Tabla mutante (mutating)


tabla que est siendo modificada por una operacin DML tabla que se ver afectada por los efectos de un DELETE CASCADE debido a la integridad referencial (hasta Oracle8i).

Las rdenes del cuerpo de un disparador no pueden:


Leer o actualizar una tabla mutante que est en la propia declaracin del disparador a nivel de fila (ROW TRIGGER) MUTATING TABLE ERROR RUNTIME ERROR

2008 Beln Vela

PL/SQL-25

Disparadores en ORACLE Estructura General de un Disparador


Ejemplo
Asignaturas (nombre_A, descripcin, DNI_Profesor)

Profesores (DNI, nombre, apellidos)

SI el nmero de asignaturas que imparte un profesor es mayor que 10 ENTONCES se debe impedir dicha asignacin y se sacar un mensaje para decir que el profesor est sobrecargado.

2008 Beln Vela

PL/SQL-26

Disparadores en ORACLE Tablas Mutantes: ejemplo


CREATE OR REPLACE TRIGGER trigger_asignaturas BEFORE INSERT OR UPDATE ON Asignaturas FOR EACH ROW DECLARE v_total BEGIN SELECT COUNT(*) INTO v_total FROM Asignaturas -- ASIGNATURAS est MUTANDO WHERE DNI_Profesor = :NEW.DNI_Profesor; -- comprueba si el profesor est sobrecargado IF v_total >= 10 THEN SELECT nombre||' '||apellidos INTO v_nombre FROM Profesores WHERE DNI = :NEW.DNI_Profesor; RAISE_APPLICATION_ERROR (-20000, El profesor '||v_nombre||', est sobrecargado'); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20001,Datos de profesor incorrectos'); END;
2008 Beln Vela /

NUMBER;

v_nombre VARCHAR2(30);

PL/SQL-27

Disparadores en ORACLE Tablas Mutantes: ejemplo


UPDATE Asignaturas SET DNI_Profesor = 000000000 WHERE nombre_A = BD;

UPDATE section * ERROR at line 1:

SELECT COUNT(*) INTO v_total FROM Asignaturas WHERE DNI_Profesor = :NEW.DNI_Profesor;

ORA-04091: table BD_XX.ASIGNATURAS is mutating, trigger/function may not see it ORA-06512: at "BD_XX.TRIGGER_ASIGNATURAS", line 5 ORA-04088: error during execution of trigger 'BD_XX.TRIGGER_ASIGNATURAS'

2008 Beln Vela

PL/SQL-28

Disparadores en ORACLE Tablas Mutantes: solucin Crear 2 disparadores En el disparador a nivel de fila (for each row) almacenamos los datos que queremos consultar (los que provocan el error de tabla mutante) En el disparador a nivel de orden (statement) realizamos la consulta (sobre los datos almacenados en lugar de sobre la tabla) La mejor forma de almacenar los valores es utilizar un paquete (opcionalmente, podramos utilizar una tabla)

2008 Beln Vela

PL/SQL-29

Disparadores en ORACLE Tablas Mutantes: solucin


Trigger a nivel de fila: necesitamos 2 variables globales creamos un paquete guardamos el DNI y el nombre del profesor en estas variables
CREATE OR REPLACE PACKAGE pck_profesores AS v_DNI_profesor Profesores.DNI%TYPE; v_nombre_profesor varchar2(50); END;

2008 Beln Vela

PL/SQL-30

Disparadores en ORACLE Tablas Mutantes: solucin


CREATE OR REPLACE TRIGGER trigger_asignaturas BEFORE INSERT OR UPDATE ON Asignaturas FOR EACH ROW BEGIN IF :NEW.DNI_Profesor IS NOT NULL THEN BEGIN pck_profesores.v_DNI_profesor := :NEW.DNI_Profesor; SELECT nombre||' '||apellidos INTO pck_profesores.v_nombre_profesor FROM Profesores WHERE DNI = pck_profesores.DNI; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001, Este profesor no existe'); END; END IF;
2008 Beln Vela

Asignamos el DNI a la variable del paquete

Buscamos el nombre del profesor y lo metemos en la variable del paquete

END;

PL/SQL-31

Disparadores en ORACLE Tablas Mutantes: solucin


TRIGGER a nivel de sentencia
realizamos la consulta utilizando las variables globales
CREATE OR REPLACE TRIGGER trigger_asignaturas_statement AFTER INSERT OR UPDATE ON Asignaturas DECLARE v_total INTEGER; BEGIN SELECT COUNT(*) INTO v_total FROM Asignaturas WHERE DNI_Profesor = pck_profesores.v_DNI_profesor; -- comprobamos si el profesor aludido est sobrecargado IF v_total >= 10 THEN RAISE_APPLICATION_ERROR (-20000, 'El profesor '|| pck_profesores.v_nombre_profesor || ' est sobrecargado'); END IF; END;
2008 Beln Vela

PL/SQL-32

Disparadores en ORACLE Tablas Mutantes: solucin


UPDATE asignaturas SET DNI = 000000000 WHERE asignaturas_id = BD;

UPDATE asignaturas * ERROR at line 1: ORA-20000: El profesor Carlos Romero est sobrecargado ORA-06512: at "BD_XX.TRIGGER_ASIGNATURAS_STATEMENT", line 11 ORA-04088: error during execution of trigger 'BD_XX.TRIGGER_ASIGNATURAS_STATEMENT'

2008 Beln Vela

PL/SQL-33

Disparadores en ORACLE Tablas Mutantes: solucin cuando hay ms de una fila afectada por la instruccin
Trigger a nivel de fila: necesitamos una tabla para almacenar las filas modificadas creamos un paquete guardamos el DNI y el nombre del profesor en la variable tipo tabla
create or replace package pck_profesores as type datos_profesor is record( v_DNI_profesor Profesores.DNI%Type, v_nombre_profesor VARCHAR(50) ); type T_prof is table of datos_profesor index by binary_integer; tabla_profesores T_prof; end pck_profesores;
2008 Beln Vela

PL/SQL-34

Disparadores en ORACLE Tablas Mutantes: solucin cuando afecta a ms de 1 fila


CREATE OR REPLACE TRIGGER trigger_asignaturas BEFORE INSERT OR UPDATE ON Asignaturas FOR EACH ROW DECLARE Insertamos el Indice binary_integer; DNI y Nombre BEGIN en la variable IF :NEW.DNI_Profesor IS NOT NULL THEN tabla BEGIN Indice:= pck.profesores.tabla_profesores.COUNT+1; pck_profesores.tabla_profesores(Indice).DNI := :NEW.DNI_Profesor; SELECT nombre||' '||apellidos INTO pck_profesores.tabla_profesores(Indice).v_nombre_profesor FROM Profesores WHERE DNI = :NEW.DNI_Profesor; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001,'Este profesor no existe'); END; END IF; 2008 Beln Vela END;

PL/SQL-35

Disparadores en ORACLE Tablas Mutantes: solucin cuando afecta a ms de 1 fila


TRIGGER a nivel de sentencia:se consulta recorriendo la variable tabla
CREATE TRIGGER trigger_asignaturas_statement AFTER INSERT OR UPDATE ON Asignaturas DECLARE v_total INTEGER; Vaciamos tabla temporal para que sea usado por Indice binary_integer; la siguiente ejecucin del nombre_prof varchar(50); disparador BEGIN FOR Indice in 1..pck_profesores.tabla_profesores.count loop SELECT COUNT(*) INTO v_total FROM Asignaturas WHERE DNI_Profesor = pck_profesores.tabla_profesores(Indice).v_DNI_profesor; -- comprobamos si el profesor aludido est sobrecargado IF v_total >= 10 THEN nombre_prof:=pck_profesores.tabla_profesores(Indice).v_nombre_profesor; pck_profesores.tabla_profesores.delete; -- vaciar tabla RAISE_APPLICATION_ERROR (-20000, Profesor '||nombre_prof|| 'sobrecargado'); END IF; END LOOP; pck_profesores.tabla_profesores.delete; -- vaciar tabla 2008 Beln Vela PL/SQL-36 END;

Bibliografa
Bibliografa Bsica
Abbey, Corey y Abramson. ORACLE8i: Gua de Aprendizaje (versiones 7.x, 8 y 8i). McGraw-Hill. Urman S. ORACLE 8: Programacin PL/SQL. McGraw-Hill. Urman S., Hardman, R., y McLaughlin, M. ORACLE DATABASE 10g. PL/SQL Programming. Oracle Press, 2004.

Bibliografa Complementaria
Elmasri, R. y Navathe, S. B. Fundamentos de Sistemas de Bases de Datos. Tercera Edicin. Addison-Wesley Iberoamericana, 2000.

2008 Beln Vela

PL/SQL-37

Introduccin al lenguaje PL/SQL

Diseo de Bases de Datos y Seguridad de la Informacin

2008 Beln Vela

PL/SQL-38

You might also like