Plsql Triggers

March 19, 2018 | Author: Eberthy | Category: Pl/Sql, Sql, Computer Data, Software Engineering, Databases


Comments



Description

Oracle PL/SQLMiguel Rodríguez Penabad Laboratorio de Bases de Datos Universidade da Coruña Curso 2011-2012 Estructura Bloques anónimos DECLARE /* Sección declarativa - variables PL/SQL, tipos, cursores, subprogramas locais */ BEGIN /* Sección executable - ordes PL/SQL */ EXCEPTION /* Sección de manexo de excepcións */ END; Exemplo mínimo BEGIN NULL; -- Necesitamos polo menos unha sentencia. -- NULL é unha sentencia que non fai nada END; / Oracle PL/SQL [Curso 2011-2012] 2 / 49 Exemplo 1: Ver a data actual SET SERVEROUTPUT ON DBMS_OUTPUT.PUT_LINE Acabamos o bloque con . e executamos (R ou RUN) Se acabamos con /, executa directamente SQL> BEGIN 2 DBMS_OUTPUT.PUT_LINE(SYSDATE); 3 END; 4 . SQL> R 02/04/06 Procedimiento PL/SQL terminado correctamente. Oracle PL/SQL [Curso 2011-2012] 3 / 49 Variables e tipos Tipos predenidos Tipos de SQL máis BOOLEAN, BINARY_INTEGER DECLARE Nome VARCHAR2 (20); " Unha variable cun nome rarísimo" NUMBER(1); Contador BINARY_INTEGER; ProcesoFinalizado BOOLEAN; Tipos denidos polo usuario (rexistros) DECLARE TYPE t_RexistroEstudiante IS RECORD ( Nome VARCHAR2(20), Apelido1 VARCHAR2(20), Apelido2 VARCHAR2(20) ); variable_Estudiante t_RexistroEstudiante; Oracle PL/SQL [Curso 2011-2012] 4 / 49 Variables e tipos (ii) Sintaxe completa <nome_variable> [CONSTANT] <tipo> [NOT NULL] [{:=|DEFAULT} <valor por defecto>]; DECLARE num1 NUMBER; fecha1 DATE :=SYSDATE; num3 NUMBER DEFAULT 3; num4 CONSTANT NUMBER:=4; num5 NUMBER NOT NULL DEFAULT 5; num6 CONSTANT NUMBER NOT NULL := 6; Usar o tipo doutra variable, dun atributo ou dunha táboa DECLARE salario NUMBER(7,2); -- Problema se cambia a definición na táboa Mellor: DECLARE salario EMP.SAL%TYPE; soldo salario%TYPE; rEmp EMP%ROWTYPE; Oracle PL/SQL [Curso 2011-2012] 5 / 49 Sección executable Manipular variables Asignación: := upper, length, ...) Dependendo do tipo: Operacións matemáticas (+,-,*,/,...), concatenación (||) Funcións (power, etc. DECLARE n BINARY_INTEGER; string VARCHAR(20); BEGIN n := 3; DBMS_OUTPUT.PUT_LINE('n vale '||n); n := power(2,3); DBMS_OUTPUT.PUT_LINE('n vale 2 elvado a 3: '||n); string := 'Un tExTo'; DBMS_OUTPUT.PUT_LINE(string||' en maiúsculas é '|| upper(string)); END; / n vale 3 n vale 2 elvado a 3: 8 Un tExTo en maiúsculas é UN TEXTO Oracle PL/SQL [Curso 2011-2012] 6 / 49 SQL en bloques PL/SQL Podemos incluir variables na sentencia SQL Podemos usar DML Insert, delete, update Para o SELECT teremos varios casos O uso de DDL será de forma distinta A execución dun bloque PL/SQL é atómica Igual que a execución dunha sentencia SQL. Ex: se nun bloque hai 2 inserts e o segundo falla, o primeiro non se conserva. Oracle PL/SQL [Curso 2011-2012] 7 / 49 SQL en bloques PL/SQL (ii) Exemplo Crea unha táboa PERSOA(IDPERSOA,NOME,IDADE) Crea un bloque de código para insertar datos Directamente Lendo os datos e almacenándoos nun rexistro create table persoa(idpersoa char(12) not null primary key, nome char(20), idade number(3)); DECLARE rPersoa persoa%ROWTYPE; BEGIN INSERT INTO PERSOA(IDPERSOA,NOME,IDADE) VALUES ('01234567T', 'Carpanta', 50); INSERT INTO PERSOA(IDPERSOA,NOME,IDADE) VALUES ('3456789B', 'Sacarino', 17); rPersoa.idpersoa := '12345678A'; rPersoa.nome := 'Matusalén'; rPersoa.idade := 850; INSERT INTO PERSOA VALUES rPersoa; END; Oracle PL/SQL [Curso 2011-2012] 8 / 49 Campos individuais UPDATE PERSOA SET IDADE = IDADE + 1. engadindo un ano declare rPersoa persoa%ROWTYPE. Borra as persoas cun identicador que acabe en T begin end.nome := 'Matusalén'. -. / 12345678A Oracle PL/SQL Matusalén 851 10 / 49 [Curso 2011-2012] .PUT_LINE(rPersoa. BEGIN SELECT * INTO rPersoa FROM PERSOA WHERE IDPERSOA='12345678A'...SQL en bloques PL/SQL (iii) Exemplo Actualiza a idade de todas as persoas. INTO Con variables ou rexistros PL/SQL Obtén e imprime información da persoa con IDPERSOA '12345678A' DECLARE rPersoa PERSOA%ROWTYPE. [Curso 2011-2012] 9 / 49 SQL en bloques PL/SQL (iv) Selección de datos Uso da cláusula SELECT . end. DBMS_OUTPUT. rPersoa. Oracle PL/SQL DELETE FROM PERSOA WHERE IDPERSOA LIKE '%T'.NOME ||' '|| rPersoa. rPersoa.Toda a fila rPersoa.idade := 850.IDPERSOA ||' '|| rPersoa. END.IDADE). UPDATE PERSOA SET ROW = rPersoa WHERE idpersoa = '12345678A'.idpersoa := '12345678A'. begin -. NO_DATA_FOUND ERROR en línea 1: ORA-01403: no se han encontrado datos ORA-06512: en línea 4 Excepción Oracle PL/SQL [Curso 2011-2012] 11 / 49 SQL en bloques PL/SQL (v) Selección de datos (cont.PUT_LINE(rPersoa. DBMS_OUTPUT.) Obtén e imprime información da(s) persoa(s) de máis de 15 anos DECLARE rPersoa PERSOA%ROWTYPE. BEGIN SELECT * INTO rPersoa FROM PERSOA WHERE IDADE = 101.IDPERSOA ||' '|| rPersoa.IDADE).IDPERSOA ||' '|| rPersoa.PUT_LINE(rPersoa.NOME ||' '|| rPersoa.IDADE). BEGIN SELECT * INTO rPersoa FROM PERSOA WHERE IDADE > 15. DBMS_OUTPUT.NOME ||' '|| rPersoa. TOO_MANY_ROWS ERROR en línea 1: ORA-01422: la recuperación exacta devuelve un número mayor de filas que el solicitado ORA-06512: en línea 4 Excepción Oracle PL/SQL [Curso 2011-2012] 12 / 49 .SQL en bloques PL/SQL (vi) Selección de datos (cont.) Obtén e imprime información da(s) persoa(s) de 101 anos DECLARE rPersoa PERSOA%ROWTYPE. END. END. . DBMS_OUTPUT... END. COUNT.PUT_LINE('Hai '|| numero || ' persoas').. Oracle PL/SQL [Curso 2011-2012] 14 / 49 .) O SELECT .) DECLARE numero NUMBER.PUT_LINE('A idade media é de '|| numero || ' anos')... AVG.SQL en bloques PL/SQL (vii) Selección de datos (cont. / Hai 3 persoas A idade media é de 3 anos Oracle PL/SQL [Curso 2011-2012] 13 / 49 Estructuras de Control Condicional Simple IF <condición> THEN <secuencia que se executa si condición é certa> END IF. BEGIN SELECT COUNT(*). INTO só pode usarse se sabemos que imos recuperar unha la Exemplos: funcións de agregación (SUM. . ] [ELSE /* Accións se todas as condicións anteriores non son certas */ ] END IF. media NUMBER. media FROM PERSOA. Sintaxe completa IF <cond1> THEN /* Accións */ [ELSIF <cond2> THEN /* Accións */ . AVG(IDADE) INTO numero. DBMS_OUTPUT. Bucle infinito! DBMS_OUTPUT. Exercicio Escribe un bloque de código que indique se a media de idade é superior ou non a 25 anos. BEGIN LOOP -.PUT_LINE(contador).. INTO DECLARE media NUMBER. END. END. / Idade media superior a 25 Oracle PL/SQL [Curso 2011-2012] 15 / 49 Estructuras de Control (iii) Bucles Simple: LOOP .Estructuras de Control (ii) Condicionais. contador := contador + 1..PUT_LINE('Non é superior a 25')....PUT_LINE('Idade media superior a 25'). ELSE DBMS_OUTPUT. BEGIN SELECT AVG(IDADE) INTO media FROM PERSOA. END LOOP DECLARE contador BINARY_INTEGER := 1. IF media > 25 THEN DBMS_OUTPUT.)? SELECT . END LOOP. Funciona Non Hai que usar IF (SELECT AVG(IDADE) . Oracle PL/SQL [Curso 2011-2012] 16 / 49 ... END IF. PUT_LINE(contador). DECLARE cont1 BINARY_INTEGER := 1. cont2 BINARY_INTEGER := 1. BEGIN <<externo>> LOOP DBMS_OUTPUT. END LOOP. END LOOP. cont2:=cont2+1. BEGIN LOOP IF contador > 10 THEN EXIT.. DBMS_OUTPUT. .NEW_LINE. cont2:=1. 17 / 49 Oracle PL/SQL [Curso 2011-2012] Estructuras de Control(iv) Bucles anidados. EXIT interno WHEN cont2>cont1. END. contador := contador + 1. END LOOP. END IF. END LOOP. DBMS_OUTPUT.PUT(' Int:'||cont2). EXIT externo WHEN cont1 > 10. Oracle PL/SQL [Curso 2011-2012] 18 / 49 . Etiquetas Etiqueta: <<nome_etiqueta>> Localiza a seguinte liña de código. END.PUT_LINE('Bucle externo: '||cont1). <<interno>> LOOP DBMS_OUTPUT.. cont1 := cont1 + 1.Estructuras de Control(iv) Bucles Introducir unha condición e usar DECLARE contador BINARY_INTEGER := 1. Mellor: Usar EXIT EXIT WHEN <condicion> LOOP EXIT WHEN contador > 10. END LOOP.1 loop sería incorrecto! FOR contador IN REVERSE 1..Imprimirá os números do 10 ó 1 -.Estructuras de Control(v) Bucles WHILE Sintaxe: WHILE <condicion> LOOP .. END LOOP.. <lim_sup> LOOP /* Sentencias */ END LOOP. END LOOP.10 LOOP DBMS_OUTPUT.PUT_LINE(contador). A variable do FOR é local e non se declara Sempre <lim_inf> .½for contador in 10. Oracle PL/SQL [Curso 2011-2012] 19 / 49 Estructuras de Control(vi) Bucles FOR numéricos Sintaxe: FOR <variable> IN [REVERSE] <lim_inf> .O seguinte contador é "distinto" -.10 LOOP DBMS_OUTPUT. END.PUT_LINE(contador). BEGIN WHILE contador <= 10 LOOP DBMS_OUTPUT... -. Oracle PL/SQL [Curso 2011-2012] 20 / 49 . <lim_sup> (incluso con reverse) BEGIN FOR contador IN 1... contador := contador + 1. END LOOP: Comproba a condición antes de entrar no bucle Exemplo: DECLARE contador BINARY_INTEGER := 1. END.PUT_LINE(contador). CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade. SELECT <lista_de_atributos> INTO <rexistro PL/SQL>. <nome_cursor>%ROWTYPE. -. Abrir cursor 3.IDADE%TYPE. limiteIdade PERSOA. Declarar cursor 2. Cerrar cursor Oracle PL/SQL [Curso 2011-2012] 21 / 49 Consultas e cursores (ii) Declaración Na sección de declaración de variables Sintaxe: Aparece o tipo CURSOR <nome_cursor> IS <consulta>. A consulta pode incluir variables Exemplos DECLARE CURSOR c_xente IS SELECT * FROM PERSOA. CURSOR c_xubilados IS SELECT * FROM PERSOA WHERE IDADE >= 65.Consultas e cursores (i) Unha la Se sabemos a priori que a consulta devolve exactamente unha la: SELECT <lista_de_atributos> INTO <lista_de_variables>. Número indeterminado de las Uso de CURSORes 1. (Bucle) Procesar las 4. rPersoa c_xente_maior_de%ROWTYPE.Sería igual que PERSOA%ROWTYPE Oracle PL/SQL [Curso 2011-2012] 22 / 49 . IDADE%TYPE.. Oracle executa a consulta e usa a área e contexto Información sobre a consulta Os datos obtidos da consulta (conxunto activo) OPEN <nome_cursor>. Oracle PL/SQL [Curso 2011-2012] 23 / 49 Consultas e cursores (iv) Cerre do cursor Cerrar o cursor: CLOSE <nome_cursor>.. BEGIN limiteIdade := 35. END. . CLOSE c_xente_maior_de.. Se a consulta incluía variables debemos darlles o valor antes de Exemplo DECLARE limiteIdade PERSOA. OPEN c_xente_maior_de. OPEN c_xente_maior_de.. END.Consultas e cursores (iii) Apertura do cursor Abrir o cursor: abrir o cursor. Oracle libera a área de contexto asociada Exemplo DECLARE limiteIdade PERSOA. . CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade. CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade. Oracle PL/SQL [Curso 2011-2012] 24 / 49 .IDADE%TYPE. rPersoa c_xente_maior_de%ROWTYPE. BEGIN limiteIdade := 65. %ROWCOUNT Número de las procesadas actualmente.nome||'. podemos consultar as seguintes propiedades. BEGIN limiteIdade := 35. EXIT WHEN c_xente_maior_de%NOTFOUND. OPEN c_xente_maior_de. 851 Oracle PL/SQL [Curso 2011-2012] 26 / 49 . DBMS_OUTPUT. CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade. Se <nomecursor>%ISOPEN é certo. As tres últimas propiedades tenen un signicado especial para o cursor Oracle PL/SQL SQL 25 / 49 [Curso 2011-2012] Consultas e cursores (vi) Procesar las (bucle estándar) DECLARE limiteIdade PERSOA. END LOOP.IDADE%TYPE. END.idpersoa||'. Carpanta . 51 . non obtivo ningunha la. '||rPersoa. Matusalén . CLOSE c_xente_maior_de.idade). LOOP FETCH c_xente_maior_de INTO rPersoa. Normalmente dentro dun bucle Propiedades dos cursores %ISOPEN: Indica se o cursor está aberto. rPersoa c_xente_maior_de%ROWTYPE. %FOUND O último %NOTFOUND O último FETCH FETCH obtivo unha la. / 01234567T 12345678A .PUT_LINE(rPersoa. '||rPersoa.Consultas e cursores (v) Procesar las Sentencia para obter unha la: FETCH <nome_cursor> INTO {<lista de variables>|<rexistro PL/SQL>}. END LOOP. END LOOP.IDADE%TYPE.idade).IDADE%TYPE. CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade. WHILE c_xente_maior_de%FOUND LOOP DBMS_OUTPUT. '||rPersoa. OPEN c_xente_maior_de.Consultas e cursores (vii) Procesar las (bucle while) Lectura adiantada: DECLARE limiteIdade PERSOA. BEGIN limiteIdade := 35. END. FETCH c_xente_maior_de INTO rPersoa.PUT_LINE(rPersoa.idpersoa||'.nome||'.idade). CLOSE c_xente_maior_de. FETCH c_xente_maior_de INTO rPersoa. END. '||rPersoa. CURSOR c_xente_maior_de IS SELECT * FROM PERSOA WHERE IDADE >= limiteIdade.idpersoa||'. Oracle PL/SQL [Curso 2011-2012] 28 / 49 .nome||'. Consideracións importantes Non abrimos (OPEN) o cursor antes do bucle Non facemos O <rexistro> non se declara. Oracle PL/SQL [Curso 2011-2012] 27 / 49 Consultas e cursores (viii) Procesar las (bucle for con cursor explícito) Sintaxe: FOR <rexistro> IN <nome_cursor> LOOP /* Procesar fila actual */ END LOOP. BEGIN limiteIdade := 35. FOR rPersoa IN c_xente_maior_de LOOP DBMS_OUTPUT. rPersoa c_xente_maior_de%ROWTYPE. '||rPersoa.PUT_LINE(rPersoa. '||rPersoa. é interno ó FOR Non cerramos (CLOSE) o cursor despois do bucle FETCH dentro do bucle Non facemos comprobación ( %NOTFOUND) de nalización DECLARE limiteIdade PERSOA. idpersoa||'. BEGIN limiteIdade := 35. Se non hai ningunha. DECLARE limiteIdade PERSOA. IF SQL%NOTFOUND THEN DBMS_OUTPUT. Consideracións Comportamento similar ó bucle A consulta FOR con cursor explícito. Non declaramos o cursor. END. nin facemos FETCH Podemos consultar as propiedades SQL%FOUND: hai las afectadas SQL%NOTFOUND: non hai las afectadas SQL%ROWCOUNT: no de las afectadas (SQL%ISOPEN sempre é falso) Exemplo Borra todas as persoas que teñan menos de 10 anos. END IF. Oracle PL/SQL [Curso 2011-2012] 29 / 49 Consultas e cursores (x) Cursor implícito SQL Usado para Non INSERT.idade). '||rPersoa. END. BEGIN DELETE FROM PERSOA WHERE IDADE <10. END LOOP. Oracle PL/SQL [Curso 2011-2012] 30 / 49 . usamos directamente a consulta. cerramos. DELETE e SELECT INTO abrimos. '||rPersoa.PUT_LINE('Non hai persoas menores de 10 anos').Consultas e cursores (ix) Procesar las (bucle for con cursor implícito) Sintaxe: FOR <rexistro> IN (<consulta>) LOOP /* Procesar fila actual */ END LOOP. UPDATE.nome||'. amosa unha mensaxe indicándoo.IDADE%TYPE. debe ir entre parénteses.PUT_LINE(rPersoa. FOR rPersoa IN (SELECT * FROM PERSOA WHERE IDADE >= limiteIdade) LOOP DBMS_OUTPUT. Consultas e cursores (xi) Cursores actualizables Declaramos o cursor Especicando Usamos FOR UPDATE [NOWAIT] obtemos excepción se non pode como condición Bloquéanse todas as las recuperadas (ata o commit). END LOOP. NOWAIT bloquear as las. DECLARE CURSOR c_persoas IS SELECT * FROM PERSOA FOR UPDATE NOWAIT. END. EXECUTE IMMEDIATE comando. Exemplo DECLARE comando char(150). WHERE CURRENT OF <nome_cursor> para actualizar a la actual Exemplo Restar 1 á Idade das persoas con 77 anos. END. Oracle PL/SQL [Curso 2011-2012] 32 / 49 . Oracle PL/SQL [Curso 2011-2012] 31 / 49 SQL dinámico (i) Sentencias DDL Sintaxe: BEGIN EXECUTE IMMEDIATE <cadena de caracteres>. END IF. END.idade = 77 THEN UPDATE PERSOA SET IDADE = IDADE . EXECUTE IMMEDIATE 'create index idxcampo on tabla(campo)'. BEGIN FOR rPersoa in c_persoas LOOP IF rPersoa.1 WHERE CURRENT OF c_persoas. BEGIN comando := 'create table tabla (campo char)'. EXECUTE IMMEDIATE 'INSERT INTO TABLA VALUES(''A'')'. BEGIN comando := 'create table tabla (campo char)'. DECLARE comando char(150).SQL dinámico (ii) Exemplo Problemas mezclando SQL estático e dinámico: O bloque PL/SQL non compila se tratamos de usar a táboa que se vai crear con SQL dinámico. columna 4: PL/SQL: SQL Statement ignored Oracle PL/SQL [Curso 2011-2012] 33 / 49 SQL dinámico (iii) Exercicio Modica o código anterior de forma que funcione correctamente. Oracle PL/SQL [Curso 2011-2012] 34 / 49 . EXECUTE IMMEDIATE 'create index idxcampo on tabla(campo)'.Fallará INSERT INTO TABLA VALUES('A'). EXECUTE IMMEDIATE 'create index idxcampo on tabla(campo)'. DECLARE comando char(150). / INSERT INTO TABLA VALUES('A'). END. * ERROR en línea 8: ORA-06550: línea 8. BEGIN comando := 'create table tabla (campo char)'. EXECUTE IMMEDIATE comando. END. -. EXECUTE IMMEDIATE comando. columna 16: PL/SQL: ORA-00942: la tabla o vista no existe ORA-06550: línea 8. Oracle PL/SQL [Curso 2011-2012] 35 / 49 Excepcións (i) SQLCODE Informa sobre a última operación SQL do bloque de código PL/SQL SQLCODE = 0 SQLCODE < 0 SQLERRM : última operación con éxito : Erro na última operación Mensaxe de erro correspondente ó SQLCODE BEGIN DBMS_OUTPUT.SQL dinámico (iv) Variables tipo cursor Tipo xenérico: SYS_REFCURSOR ou REF CURSOR Poden usarse con SQL dinámico. '||rex. / Código: 0 Mensaxe: ORA-0000: normal. successful completion Oracle PL/SQL [Curso 2011-2012] 36 / 49 .PUT_LINE(rex.refc ref cursor. Tipo especíco: REF CURSOR RETURN <tipo> Uso: paso de coleccións de datos como parámetros en subprogramas.PUT_LINE('Código: '||SQLCODE). END. END. DBMS_OUTPUT. '||rex. END LOOP. BEGIN OPEN c_xente FOR 'SELECT * FROM PERSOA'. rex PERSOA%ROWTYPE.idade). c_xente refc. EXIT WHEN c_xente%NOTFOUND.nome||'. DBMS_OUTPUT. (Non sirven para SQL dinámico) (Non os estudiaremos) Declaramos cursor dese tipo especíco Construimos a cadea de caracteres da sentencia Abrimos o cursor para a sentencia DECLARE -. c_xente SYS_REFCURSOR. CLOSE c_xente.Definición alternativa: -. LOOP FETCH c_xente INTO rex.idpersoa||'.PUT_LINE('Mensaxe: '||SQLERRM). TOO_MANY_ROWS. ..Accións se ocurriu excepcion2 ] [ WHEN OTHERS THEN -.Excepcións (ii) Estrutura dun bloque PL/SQL BEGIN /* Código problemático */ EXCEPTION [ WHEN <nome_excepcion1> THEN -.PUT_LINE('Erro: '||SQLCODE). Oracle PL/SQL [Curso 2011-2012] DECLARE NOME PERSOA.) Usamos OTHERS para o caso xenérico Usamos o nome da excepción Compróbanse por orde Dentro de cada excepción. 38 / 49 .Accións se ocurriu calquera excepcion ] END. ZERO_DIVIDE. escribimos código PL/SQL normal RAISE Oracle PL/SQL relanza a excepción.NOME%TYPE.. END.PUT_LINE('Mensaxe: '||SQLERRM). WHEN OTHERS THEN DBMS_OUTPUT. DUP_VAL_ON_INDEX.PUT_LINE('Non atopei persoas de 101 anos'). 37 / 49 [Curso 2011-2012] Excepcións (iii) Exemplo / Non atopei persoas de 101 anos Procedimiento PL/SQL terminado correctamente.Accións se ocurriu excepcion1 ] [ WHEN <nome_excepcion2> THEN -. BEGIN SELECT NOME INTO NOME FROM PERSOA WHERE IDADE = 101. DBMS_OUTPUT. (NO_DATA_FOUND... Necesitamos polo menos un WHEN . EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT. non se fai a inserción) BEGIN INSERT INTO PERSOA(IDPERSOA. END.'persoa que existe'. de xeito que non dea erro se o identicador (clave primaria) existe (por suposto. IDADE) VALUES('1'.Excepcións (iv) Exemplo Crea un bloque de código que trate de insertar unha persoa. menor que -20000 Oracle PL/SQL [Curso 2011-2012] 40 / 49 . NOME.1).Exercicio: comprobar sen usar DUP_VAL_ON_INDEX Oracle PL/SQL [Curso 2011-2012] 39 / 49 Excepcións (v) Excepcións de usuario Hai 2 formas: Excepcións con nome Declarar variable de tipo Pode ser capturada con Elevar (RAISE) a excepción baixo certas condicións EXCEPTION WHEN <nome_excepcion> THEN Excepción sen nome. -. EXCEPTION WHEN DUP_VAL_ON_INDEX THEN NULL. con SQLCODE e SQLERR RAISE_APPLICATION_ERROR(<codigo>.<mensaxe>) O <codigo> debe ser negativo. DECLARE demasiados_xubilados EXCEPTION. EXCEPTION WHEN demasiados_xubilados THEN DBMS_OUTPUT. END. numero NUMBER. elevar unha excepción e xestionala indicando que hai demasiados. DBMS_OUTPUT. END IF.PUT_LINE('Hai '||numero||' xubilados. Non xestiones esa excepción. IF rPersoa. rPersoa. Se hai máis de 100. xenera unha excepción con código -20001 e mensaxe 'Idade inválida'. END. Se a idade é negativa. para que a execución do bloque falle. BEGIN rPersoa.'Idade inválida').NOME := 'nome'. IF numero > 100 THEN RAISE demasiados_xubilados. / ERROR en línea 1: ORA-20001: Idade inválida ORA-06512: en línea 9 Oracle PL/SQL [Curso 2011-2012] 42 / 49 .'). INSERT INTO PERSOA VALUES rPersoa.IDPERSOA := '32233223K'. DECLARE rPersoa PERSOA%ROWTYPE.Excepcións (vi) Excepcións de usuario: exemplos Amosar o número de xubilados. BEGIN SELECT COUNT(*) INTO numero FROM persoa WHERE idade>65. Oracle PL/SQL [Curso 2011-2012] 41 / 49 Excepcións (vii) Excepcións de usuario: exemplos Engade unha persoa.IDADE < 0 THEN RAISE_APPLICATION_ERROR(-20001.IDADE := -1. rPersoa.PUT_LINE('Hai demasiados xubilados'). END IF. TABLE OF ..Coleccións en PL/SQL Tipos de datos en Oracle Tipos predenidos Tipos estruturados (clases) Rexistros (RECORD) PL/SQL Coleccións: VARRAY.. pero non son realmente táboas Persistencia a nivel de sesión Non admite sentencias DDL nin DML Non hai transaccións Son coleccións dispersas (sparse) en memoria Oracle PL/SQL [Curso 2011-2012] 43 / 49 Coleccións en PL/SQL Táboas PL/SQL Creación TYPE <tipo_taboa> IS TABLE OF <tipo_elemento> [NOT NULL] [INDEX BY {BINARY_INTEGER|VARCHAR2(<n>)}].. Créase primeiro o tipo e logo as variables O <tipo_elemento> pode ser un rexistro PL/SQL (a partir de PL/SQL 2. Táboas PL/SQL..: array asociativo Índice numérico/carácter (admite %type) Créase a táboa baleira (pero inicializada) Podemos asignar directamente novos elementos do array Omitindo INDEX BY .3) Indexada por números ou por cadeas de caracteres Especicando INDEX BY .: crea unha nested table Índice numérico Créase a táboa sen inicializar Hai que xestionar a asignación de novos elementos (extender táboa) Oracle PL/SQL [Curso 2011-2012] 44 / 49 ... TABLE OF ... <variable_taboa> <tipo_taboa>. empregados(17) := rex_emp. un_nome_de_empregado EMP.Excepción NO_DATA_FOUND: non hai o índice 3 Oracle PL/SQL [Curso 2011-2012] 46 / 49 . un_nome_de_empregado := nomes_empregados(2). -. rex_emp EMP%ROWTYPE. TYPE taboadeemps IS TABLE OF EMP%ROWTYPE INDEX BY BINARY_INTEGER.ename. Oracle PL/SQL [Curso 2011-2012] 45 / 49 Coleccións en PL/SQL Táboas PL/SQL Acceso  Exemplos <variable_taboa> (<indice>) nomes_clientes(23) := 'Cliente Novo'. -. empregados(1). -.ENAME%TYPE INDEX BY BINARY_INTEGER.Coleccións en PL/SQL Táboas PL/SQL Creación  Exemplos DECLARE TYPE taboadenomes IS TABLE OF EMP. empregados taboadeemps. .ENAME%TYPE.ename := 'ANA'.ename := 'PEPE'.. rex_emp := empregados(1).empno := 2434. empregados(15).<campo> empregados(1). para acceder a un campo: <variable_taboa> (<indice>). un_nome_de_empregado := empregados(1). nomes_clientes taboadenomes. un_nome_de_empregado := nomes_clientes(23). nomes_empregados taboadenomes..Funciona rex_emp := empregados(3).Excepción NO_DATA_FOUND: non hai o índice 2 Se é unha táboa de rexistros. for indice_int in nt_int. valor: 666 Hai 1 elementos Hai 0 elementos Oracle PL/SQL [Curso 2011-2012] 48 / 49 .PUT_LINE('=== ARRAY ASOCIATIVO (INDEX BY VARCHAR) ==='). e vale '||nt_int(4)). nt_int(nt_int.put_line('Hai '||nt_int. nt_int.last loop dbms_output.last) := 666. / Hai 3 elementos Hai 4 elementos O elemento 4 existe..put_line('O elemento 4 existe.put_line('Índice: '||indice_int||'. Exists(<indice>) Delete. Navegación: First. indice_char := array_char. valor: Primeiro Índice: 3. un elemento ó DECLARE TYPE nestedtable_int_t IS TABLE OF varchar2(100).count||' elementos'). indice_char := array_char. 76.put_line('Hai '||nt_int. dbms_output. nt_int nestedtable_int_t. end. indice_char varchar2(20).put_line('Hai '||nt_int.delete(2.first .exists(4) then dbms_output. -. engade Consulta: Borrado: nal da táboa. valor: 76 Índice: un. valor: Segundo Índice: 1. nt_int nestedtable_int_t. nt_int := nestedtable_int_t(101. non é nested table array_char('un'):= 'Primeiro'. valor: '|| nt_int(indice_int)). nt_int. Delete(<indice_inf>. TYPE nestedtable_int_t IS TABLE OF varchar2(100). valor: 22 Índice: 4. array_char('dous') := 'Segundo'. / === ARRAY ASOCIATIVO (INDEX BY VARCHAR) === === NESTED TABLE (INDICE NUM??RICO) === Índice: dous. if nt_int.Non podo usar o constructor.last loop -. valor: Terceiro Índice: 2. Delete(<indice>). 22). Last: Devolven un índice DECLARE TYPE arrayasoc_char_t IS TABLE OF varchar2(100) index by varchar2(20). valor: 76 Índice: 3.put_line('Índice: '||indice_int||'.count||' elementos'). nt_int. dbms_output.PUT_LINE('=== NESTED TABLE (INDICE NUMÉRICO) ==='). 76. array_char('tres') := 'Terceiro'.first . valor: '|| nt_int(indice_int)).count||' elementos'). valor: '|| array_char(indice_char)). end.3). nt_int.first. end if. Prior(<indice>).Coleccións en PL/SQL Táboas PL/SQL Métodos aplicables (i) Constructor: <tipo_taboa>() ou <tipo_taboa>(<valores>): Só para nested tables.put_line('Hai '||nt_int. dbms_output. while indice_char is not null loop dbms_output.next(indice_char).Só podo usar FOR se non hai ocos! dbms_output. valor: 22 Oracle PL/SQL [Curso 2011-2012] 47 / 49 Coleccións en PL/SQL Táboas PL/SQL Métodos aplicables (ii) Count. end loop. nt_int.<indice_sup>) Outros: Extend: só para nested tables. valor: 101 Índice: 2. Next(<indice>). valor: 101 Índice: tres. dbms_output.delete(1). array_char arrayasoc_char_t. 22).. e vale 666 Índice: 1.count||' elementos').put_line('Índice: '||indice_char||'. begin DBMS_OUTPUT. DBMS_OUTPUT. end loop.delete. nt_int. begin nt_int := nestedtable_int_t(101. end loop.extend. for indice_int in nt_int. taboa_emps taboa_emps_t := taboa_emps_t(). DBMS_OUTPUT. end.PUT_LINE('Cargados ' || taboa_emps.. DECLARE TYPE taboa_emps_t IS TABLE OF EMP%ROWTYPE.Coleccións en PL/SQL Táboas PL/SQL BULK COLLECT Permite cargar unha táboa PL/SQL directamente a partir dunha consulta Sintaxe: select <expresións> BULK COLLECT INTO <variable_taboa> FROM . begin SELECT * BULK COLLECT INTO taboa_emps FROM EMP..count ||' empregados na táboa PL/SQL. Oracle PL/SQL [Curso 2011-2012] 49 / 49 . / Cargados 14 empregados na táboa PL/SQL.'). nas vistas (entre outras) USER_OBJECTS (OBJ). funcións e paquetes Miguel Rodríguez Penabad Laboratorio de Bases de Datos Universidade da Coruña Curso 2011-2012 Bloques de código en PL/SQL Bloques anónimos (xa vistos no punto anterior) Rutinas almacenadas (SQL/PSM: Persistent Stored Modules en SQL:2003) Procedementos (PROCEDURE) Non devolve ningún valor Funcións (FUNCTION) Devolve un valor Paquetes (PACKAGE) Permite construir bibliotecas de procedementos e funcións Información no catálogo de Oracle. ALL_SOURCE Orde de SQL*Plus DESC[RIBE] <modulo> PL/SQL: Procedementos. ALL_PROCEDURES USER_SOURCE. funcións e paquetes [Curso 2011-2012] 2 / 10 .PL/SQL: Procedementos. ALL_OBJECTS USER_PROCEDURES. NOME%TYPE.Procedementos Creación CREATE [OR REPLACE] PROCEDURE <nome_proc> (<lista de parámetros>) [AUTHID {DEFINER|CURRENT_USER}] {IS|AS} <bloque PL/SQL> Parámetros: <nome> <especificacion E/S> <tipo> [<valor predeterminado>] A especicación de entrada/saída pode ser IN (predeterminado). OUT. ou en DECLARE antes da declaración de variables END <nome_proc>.ex. END InsPersoa. CHAR. 3 / 10 PL/SQL: Procedementos.IDPERSOA%TYPE. non CHAR(10)) Derivado dun atributo dunha táboa (p. INSERT INTO PERSOA (IDPERSOA. DataNac DATE) IS aIdade NUMBER(3). nome e data de nacemento. funcións e paquetes [Curso 2011-2012] Procedementos (ii) Exemplo Engadir unha persoa da que sabemos o identicador.IDPERSOA%TYPE) DEFINER: cos permisos do creador (predeterminado) CURRENT_USER: cos permisos do usuario que o executa Non inclúe a palabra END.aIdade). PL/SQL: Procedementos.ex. BEGIN aIdade := MONTHS_BETWEEN(SYSDATE. / Procedimiento creado. funcións e paquetes [Curso 2011-2012] 4 / 10 .DataNac)/12. CREATE OR REPLACE PROCEDURE InsPersoa(oID IN PERSOA.oNome. Authid: ¾Con que permisos se executa? Bloque PL/SQL: Acaba en PERSOA. IN OUT O tipo dos argumentos pode ser Xenérico (p. oNome IN PERSOA.NOME.IDADE) VALUES(oID. v1 => 10).put_line('v1: '||v1||'. pordefecto(v2 => 77). v2: 4 Novidade Oracle 11g: indicar os nomes dos argumentos na chamada (pre 11: só en packages) Calquera argumento pode ter valor predeterminado Reordenamos/omitimos parámetros / begin pordefecto(v2 => 77. que se expande a BEGIN InsPersoa('5'.'21/12/1900'). v2 int default 4) IS BEGIN dbms_output. pordefecto(). Os argumentos con valores predeterminados ó nal. / v1: 1.'21/12/1900'). v2: 4 v1: 3. END. pordefecto(1). Omitindo un parámetro na chamada. borrado. o argumento toma o valor predeterminado. begin pordefecto(1. v2: 77 PL/SQL: Procedementos. e uso Se Oracle nos di "Creado con errores de compilación" SHOW ERRORS. chámase directamente.'2'.'21/12/1900'). v2: '||v2). v2: 2 v1: 1. non PL/SQL) CALL InsPersoa('5'.Procedementos (iii) Creación.2). ou SHOW ERRORS PROCEDURE <nome_proc> Para borrar o procedemento: DROP PROCEDURE <nome_proc> Para executar directamente o procedemento: Nun bloque PL/SQL. funcións e paquetes [Curso 2011-2012] 5 / 10 Procedementos (iv) Valores predeterminados e chamadas CREATE OR REPLACE PROCEDURE pordefecto(v1 int default 3.'2'. END. Desde SQL*Plus (modo SQL. end.'2'. EXEC[UTE] InsPersoa('5'. v1: 10. v2: 77 v1: 3. end. PL/SQL: Procedementos. funcións e paquetes [Curso 2011-2012] 6 / 10 . .idade.Funcións Creación CREATE [OR REPLACE] FUNCTION <nome_func> (<lista de parámetros>) RETURN <tipo> [AUTHID {DEFINER|CURRENT_USER}] {IS|AS} <bloque PL/SQL> Debemos indicar o tipo (xenérico) que devolve Bloque PL/SQL: Debe incluir RETURN <valor> Se a creamos con erros de compilación: SHOW ERRORS.) PL/SQL: Procedementos.) a partir da idade..'yyyy')) .IDADE%TYPE) RETURN NUMBER IS BEGIN RETURN to_number(to_char(sysdate. / Función creada. funcións e paquetes [Curso 2011-2012] 7 / 10 Funcións (ii) Exemplo Función que calcula o ano de nacemento (aprox. CREATE OR REPLACE FUNCTION AnoNac(idade IN PERSOA.------------51 1957 851 1157 17 1991 PL/SQL: Procedementos.. END AnoNac. funcións e paquetes [Curso 2011-2012] 8 / 10 . AnoNac(Idade) FROM PERSOA. IDADE ANONAC(IDADE) ---------. SELECT Idade. ou SHOW ERRORS FUNCTION <nome_func> Para borrar unha función: DROP FUNCTION <nome_func> Para executar: Non se pode directamente como os procedementos En sentencias SELECT En PL/SQL (variable (Excepto cando a función usa DML que modica datos) := funcion(argumentos). Declaración de variables globais do paquete ... PROCEDURE <nome_proc1>(<parámetros>) IS <bloque PL/SQL> FUNCTION <nome_func1>(<parámetros>) RETURN <tipo> IS <bloque PL/SQL> .Implementación de procedementos e funcións PROCEDURE <proc_privado>(<parámetros>) IS <bloque PL/SQL> . . NOME.... END <nome_paquete>...Prototipos de procedementos e funcións PROCEDURE <nome_proc1>(<parámetros). Denición da implementación CREATE [OR REPLACE] PACKAGE BODY <nome_paquete> {IS|AS} -.PUT_LINE('texto') PL/SQL: Procedementos.<nome_proc1>(<args>) Exemplo: DBMS_OUTPUT. AnoNac(IDADE) ANO_NAC FROM PERSOA. END <nome_paquete>.. -... FUNCTION <nome_func1> (<parámetros>) RETURN <tipo>. -.Declaración de variables privadas do paquete .Funcións (iii) Uso en vistas CREATE VIEW V_PERSOA AS SELECT IDPERSOA. Uso en condicionais Función que modica datos Devolve BOOLEAN true se foi posible false se non o foi PL/SQL: Procedementos. funcións e paquetes [Curso 2011-2012] 9 / 10 Paquetes Denición da interfaz CREATE [OR REPLACE] PACKAGE <nome_paquete> {IS|AS} -. funcións e paquetes [Curso 2011-2012] 10 / 10 . Uso <nome_paquete>. ] ON <Tabla> [ REFERENCING [NEW AS tupla_nova] [OLD AS tupla]_vella] ] [FOR EACH ROW] [WHEN (<Condicion_SQL_simple>)] { <Bloque PL/SQL> | CALL <procedemento(argumentos)> } Para borrar: DROP TRIGGER <nome_trigger> Para activar ou desactivar: Triggers individuais ALTER TRIGGER nome_trigger> {ENABLE|DISABLE} Todos os triggers asociados a unha táboa ALTER TABLE <táboa> {ENABLE|DISABLE} ALL TRIGGERS Triggers en Oracle [Curso 2011-2012] 2 / 21 ..Triggers en Oracle Miguel Rodríguez Penabad Laboratorio de Bases de Datos Universidade da Coruña Curso 2011-2012 Creación de triggers Para crear ou modicar: CREATE [OR REPLACE] TRIGGER <nome_trigger> {BEFORE|AFTER|INSTEAD OF} <Evento> [OR <Evento>.. DELETING Momento de activación BEFORE. . . status from user_triggers where table_name='EMP2'.------.) Número de eventos que controla un trigger Oracle permite controlar máis dun evento (usando OR) Co mesmo tempo de activación e a mesma granularidade Podemos saber o evento que o disparou: Usamos os predicados INSERTING.--------------. UPDATE.--------------.. Triggers en Oracle [Curso 2011-2012] 3 / 21 Comparación co estándar SQL:2003 Evento Tipos de evento Eventos DML (INSERT.Creación de triggers Para consultar os existentes: Táboas ALL_TRIGGERS. UPDATING.SAL<0 ENABLED 1 fila seleccionada. USER_TRIGGERS Tipo ------------VARCHAR2(30) VARCHAR2(16) VARCHAR2(227) VARCHAR2(30) VARCHAR2(16) VARCHAR2(30) VARCHAR2(4000) VARCHAR2(128) VARCHAR2(4000) VARCHAR2(8) VARCHAR2(4000) VARCHAR2(11) LONG SQL> desc user_triggers Nombre ¾Nulo? ----------------------------.. when_clause.. triggering_event. TRIGGER_NAME TRIGGER_TYPE TRIGGER WHEN_CLAUSE STATUS --------------. AFTER (como SQL:2003) INSTEAD OF (só para vistas) Táboas e variables de transición: Non usa táboas de transición (old/new table) Si que usa variables de transición (old/new row) Nomes por defecto: new/old Poden usarse na condición e na acción do trigger. 4 / 21 Triggers en Oracle [Curso 2011-2012] . trigger_type.-------TRIGGER_NAME TRIGGER_TYPE TRIGGERING_EVENT TABLE_OWNER BASE_OBJECT_TYPE TABLE_NAME COLUMN_NAME REFERENCING_NAMES WHEN_CLAUSE STATUS DESCRIPTION ACTION_TYPE TRIGGER_BODY select trigger_name. SERVERERROR. DELETE) (como SQL:2003) Eventos DDL (CREATE ON SCHEMA.) Eventos de base de datos (LOGON..-------EMP_SAL_POS BEFORE EACH ROW UPDATE nova. OLD será NULL En triggers de borrado. e OLD o antigo Coñécese o valor nos triggers BEFORE e AFTER OLD nunca pode ser modicado NEW pode modicarse nos triggers BEFORE En triggers de inserción. Triggers en Oracle [Curso 2011-2012] 6 / 21 . CREATE TABLE LINA( NUMFAC CHAR(5). . CONSTRAINT FK_FAC FOREIGN KEY(NUMFAC) REFERENCES FACTURA(NUMERO) ON DELETE CASCADE. TOTAL NUMERIC(7.2).2). CODPROD NUMERIC(3)..) As variables de transición son consideradas bind variables Irán precedidas do símbolo dous puntos (:NEW e :OLD se non usamos nomes alternativos) Denidas para todos os tipos de trigger a nivel de la NEW contén o valor novo. PREZO NUMERIC(6. ROLLBACK. NUMLI NUMERIC(3). Non se permiten sentencias de control transaccional (COMMIT. CONSTRAINT PK_FACTURA PRIMARY KEY(NUMERO) ). CREATE TABLE FACTURA( NUMERO CHAR(5). CONSTRAINT PK_PRODUTO PRIMARY KEY(CODPROD) ). CONSTRAINT FK_PROD FOREIGN KEY(CODPROD) REFERENCES PRODUTO(CODPROD) ON DELETE CASCADE ).. DATA DATE DEFAULT SYSDATE. PREZO NUMERIC(6. CANTIDADE NUMERIC(2).2). NOMPROD VARCHAR(40). NEW será NULL Triggers en Oracle [Curso 2011-2012] 5 / 21 Exemplos Táboas de referencia CREATE TABLE PRODUTO( CODPROD NUMERIC(3) NOT NULL. CONSTRAINT PK_LINA PRIMARY KEY(NUMFAC.2).NUMLI).) Condición Podemos usar as variables de transición Non admite sentencias Solución: SELECT NEW e OLD Omitir condición (omitir cláusula WHEN) Incluir a condición nun IF na acción Acción Bloque PL/SQL (ou chamada a un procedemento). SUBTOTAL NUMERIC(7.Comparación co estándar SQL:2003 (cont. ELSE :tupla_nova. SQL> INSERT INTO PRODUTO VALUES(2.Prezo := :tupla_vella.-------------------.Prezo. SQL> SELECT * FROM PRODUTO. SQL> SELECT * FROM PRODUTO.Prezo < 0) BEGIN IF UPDATING THEN :tupla_nova. 1 fila actualizada.---------1 TORNILLO . CREATE OR REPLACE TRIGGER prod_prezo_positivo BEFORE UPDATE ON PRODUTO REFERENCING NEW AS tupla_nova OLD AS tupla_vella FOR EACH ROW WHEN (tupla_nova.Prezo < 0) BEGIN :tupla_nova. CODIGO NOME PREZO ---------.---------1 TORNILLO . SQL> select * from produto. END. CREATE OR REPLACE TRIGGER prod_prezo_positivo BEFORE UPDATE OR INSERT ON PRODUTO REFERENCING NEW AS tupla_nova OLD AS tupla_vella FOR EACH ROW WHEN (tupla_nova.23 SQL> UPDATE PRODUTO SET PREZO=-2. END IF. 1 fila creada. CODIGO NOME PREZO ---------. CODIGO NOME PREZO ---------.Prezo.---------1 TORNILLO . Triggers en Oracle [Curso 2011-2012] 8 / 21 .Prezo := 0. Tampouco permitimos a inserción de prezos negativos.Exemplos Actualización de prezos Non se permite que unha actualización asigne un prezo negativo a un produto. END.-------------------.Prezo := :tupla_vella. -2).-------------------.23 Triggers en Oracle [Curso 2011-2012] 7 / 21 Exemplos Actualización de prezos + inserción Non se permite que unha actualización asigne un prezo negativo a un produto.23 2 TUERCA 0 2 filas seleccionadas. Se se intenta. 'TUERCA'. o prezo queda en 0. END. 10 / 21 . O trigger créase correctamente. pero: SQL> insert into produto values(4. BEGIN SELECT COUNT(*) INTO N FROM LINA.PROD_PREZO_POSITIVO_FALLA". a la non se insertará.codprod. CREATE OR REPLACE TRIGGER prod_prezo_positivo_falla AFTER INSERT ON PRODUTO FOR EACH ROW WHEN (new. END. puede que el disparador/la función no puedan verla ORA-06512: en "MIGUEL. -10). -. END.Exemplos Problemas: táboas mutantes Actualización de prezos (evitar inserción) Non se permite unha inserción de produtos con prezos negativos. Se se intenta. Triggers en Oracle [Curso 2011-2012] CREATE TRIGGER trigger_falla2 AFTER DELETE ON LINA FOR EACH ROW DECLARE N NUMBER. línea 1 ORA-04088: error durante la ejecución del disparador 'MIGUEL. -10) * ERROR en línea 1: ORA-04091: la tabla MIGUEL. DELETE. Non podemos acceder mediante SQL (SELECT. -. á táboa mutante. UPDATE) INSERT.O seguinte DELETE falla delete from produto where codigo=1.'Erro'. BEGIN SELECT COUNT(*) INTO N FROM PRODUTO.Prezo < 0) BEGIN DELETE FROM PRODUTO WHERE codprod = :new.'Erro'. insert into produto values(4.O seguinte DELETE falla delete from produto where codigo=1. Exemplos de triggers que fallan prod_prezo_positivo_falla (transparencia anterior): PRODUTO está sendo modicado trigger_falla1: LINA está mutando (por FK_PRODUTO) trigger_falla2: PRODUTO está mutando (por FK_PRODUTO) CREATE TRIGGER trigger_falla1 AFTER DELETE ON PRODUTO FOR EACH ROW DECLARE N NUMBER.PRODUTO está mutando.PROD_PEZO_POSITIVO_FALLA' Triggers en Oracle [Curso 2011-2012] 9 / 21 O problema das táboas mutantes Unha táboa está mutando Está modicándose actualmente por unha sentencia DML Triggers a nivel la (FOR EACH ROW) Excepto BEFORE INSERT en insercións de 1 la Está léndose ou modicándos para garantir integridade referencial. 'non se inserta'. END.O problema das táboas mutantes Posibles solucións 1.) Opción 2: Convertir a trigger de sentencia A condición pode variar O trigger pode non ser totalmente equivalente ¾Que pasa se había prezos negativos anteriores? CREATE OR REPLACE TRIGGER prod_prezo_positivo3 AFTER INSERT ON PRODUTO BEGIN DELETE FROM PRODUTO WHERE Prezo<0. END. línea 1 ORA-04088: error durante la ejecución del disparador 'MIGUEL. insert into produto values(22.'non se inserta'.'NON SE INSERTA'. COUNT(*) ---------2 Triggers en Oracle [Curso 2011-2012] 12 / 21 .PROD_PEZO_POSITIVO2' Triggers en Oracle [Curso 2011-2012] 11 / 21 O problema das táboas mutantes Posibles solucións (cont. 'Prezo inválido'). Cambiar a acción (se é posbile) 2. SQL> insert into produto values(22. 1 fila creada. Simular táboas de transición (combinación de varios triggers e procedementos en packages) Opción 1: Cambiar acción CREATE OR REPLACE TRIGGER prod_prezo_positivo2 AFTER INSERT ON PRODUTO FOR EACH ROW WHEN (new.PROD_PREZO_POSITIVO2". SQL> select count(*) from produto.Prezo < 0) BEGIN RAISE_APPLICATION_ERROR(-20002. -2) * ERROR en línea 1: ORA-20002: Prezo inválido ORA-06512: en "MIGUEL. Convertir en trigger a nivel de sentencia 3. SQL> select count(*) from produto. -2).-2). COUNT(*) ---------2 SQL> INSERT INTO PRODUTO VALUES(3. last LOOP DELETE FROM PRODUTO WHERE CODPROD = tab_prod(i). END.Codprod%TYPE. pre IN PRODUTO. END EVITAR_MUTANTES.) 2.prezo := pre. Crear paquete package CREATE OR REPLACE PACKAGE EVITAR_MUTANTES AS PROCEDURE proc_ins_row(cod IN PRODUTO.O problema das táboas mutantes Posibles solucións (cont. tab_prod.codprod. tab_prod tab_prod_t := tab_prod_t(). END LOOP.Prezo%TYPE). Triggers en Oracle [Curso 2011-2012] 13 / 21 O problema das táboas mutantes Posibles solucións (cont.Prezo%TYPE) IS BEGIN tab_prod.Codprod%TYPE.Codprod%TYPE. tab_prod(tab_prod.codprod := cod.. END EVITAR_MUTANTES. pre IN PRODUTO. tab_prod(tab_prod.last). PROCEDURE proc_ins_row(cod IN PRODUTO.) Opción 3: Simular táboas de transición Trigger de la (FOR BEFORE <evento> ou AFTER <evento> Almacena as las nunha táboa temporal AFTER <evento> Recorre a táboa temporal procesando as las Remata borrando a táboa temporal EACH ROW) Trigger de sentencia Uso de Para declarar a táboa temporal Procedementos almacenar e recorrer as las 1. Crear corpo do paquete CREATE OR REPLACE PACKAGE BODY EVITAR_MUTANTES AS TYPE rex_prod IS RECORD( codigo PRODUTO.Prezo%TYPE ).) Opción 3: Simular táboas de transición (cont. Triggers en Oracle [Curso 2011-2012] 14 / 21 .delete. END proc_ins_row. TYPE tab_prod_t IS TABLE OF rex_prod.first .last). PROCEDURE proc_after_insert IS BEGIN FOR i in tab_prod. tab_prod. PROCEDURE proc_after_insert.extend. prezo PRODUTO. -------------------. Exemplo CREATE TABLE EMP2 AS SELECT * FROM EMP. SQL> INSERT INTO PRODUTO VALUES(4.) 3.---------3 INSERTADO -2 Triggers en Oracle [Curso 2011-2012] 15 / 21 Triggers non estándar Triggers INSTEAD OF Non forman parte do estándar SQL:2003 Só poden denirse sobre vistas Usados para poder actualizar vistas non actualizables. 1 fila creada. -4). SQL> INSERT INTO PRODUTO VALUES(3. 1 fila creada.) Opción 3: Simular táboas de transición (cont. DNAME.PROC_AFTER_INSERT / SQL> ALTER TABLE PRODUTO DISABLE ALL TRIGGERS. Crear os triggers CREATE OR REPLACE TRIGGER prezopos_fila BEFORE INSERT ON PRODUTO FOR EACH ROW WHEN (new.-------------------.-2). LOC.DEPTNO=D. DEPTNO -----20 10 30 DNAME -------------RESEARCH ACCOUNTING SALES LOC EMPS ------------. SQL> SELECT * FROM PRODUTO.:new.PROC_INS_ROW(:new.Prezo) / CREATE OR REPLACE TRIGGER prezopos_sentencia AFTER INSERT ON PRODUTO CALL EVITAR_MUTANTES.DEPTNO. 'NON INSERTADO'.O problema das táboas mutantes Posibles solucións (cont.DEPTNO.DEPTNO GROUP BY D. SQL> SELECT * FROM PRODUTO. DNAME. LOC.codprod. Sempre son a nivel de la.Prezo < 0) CALL EVITAR_MUTANTES. CODPROD NOMPROD PREZO ---------. CREATE VIEW EMPS_POR_DEP AS SELECT D.---------3 INSERTADO -2 SQL> ALTER TABLE PRODUTO ENABLE ALL TRIGGERS. COUNT(*) EMPS FROM EMP2 E JOIN DEPT D ON E. SQL> SELECT * FROM EMPS_POR_DEP. CODPROD NOMPROD PREZO ---------.---------DALLAS 5 NEW YORK 3 CHICAGO 6 16 / 21 Triggers en Oracle [Curso 2011-2012] .'INSERTADO'. OBXECTO CHAR(20)).ORA_DICT_OBJ_TYPE. TIPO CHAR(12)). SYSDATE.data.TIPO) VALUES (USER. Triggers en Oracle [Curso 2011-2012] 17 / 21 Triggers non estándar Eventos DDL e de base de datos Eventos que non controlan modicación de datos Usados en auditoría de base de datos CREATE TABLE LOGCREACIONS( USUARIO CHAR(20). DELETE FROM EMPS_POR_DEP WHERE DNAME='SALES' * ERROR en línea 1: ORA-01732: operación de manipulación de datos no válida en esta vista Podemos denir a regra de actualización co trigger. SQL> DELETE FROM EMPS_POR_DEP WHERE DNAME='SALES'.) A vista non é actualizable. 1 fila suprimida. DATA DATE.ORA_DICT_OBJ_NAME). CREATE OR REPLACE TRIGGER BORRAR_EN_EMPS_POR_DEP INSTEAD OF DELETE ON EMPS_POR_DEP FOR EACH ROW BEGIN DELETE FROM EMP2 WHERE DEPTNO = :OLD.tipo_obx. END LogCreacions.) Exemplo (cont.Triggers non estándar Triggers INSTEAD OF (cont. 'CONEXIÓN'). END LOG_CONEXION. CREATE TRIGGER LOG_CONEXION AFTER LOGON ON DATABASE BEGIN INSERT INTO CONEXIONS(USUARIO. SQL> DELETE FROM EMPS_POR_DEP WHERE DNAME='SALES'.SYSDATE. END. TIPO_OBX CHAR(20). CREATE OR REPLACE TRIGGER LogCreacions AFTER CREATE ON SCHEMA BEGIN INSERT INTO LogCreacions(usuario. / CREATE TABLE CONEXIONS( USUARIO CHAR(20).DATA_HORA. / Triggers en Oracle [Curso 2011-2012] 18 / 21 . DATA_HORA DATE.obxecto) VALUES(USER.DEPTNO. . END trigger_2.O trigger_2 executarase despois do trigger_1.. AFTER EACH ROW IS BEGIN <acción> END AFTER EACH ROW.Non é necesario incluir os seguintes catro bloques BEFORE STATEMENT IS BEGIN <acción> END BEFORE STATEMENT.. END trigger_comp. -. END trigger_1. Triggers en Oracle [Curso 2011-2012] 19 / 21 Novidades Oracle 11g Triggers compostos (compound triggers) Permite establecer varias accións Con distinta granularidade Con distinto tempo de activación CREATE OR REPLACE TRIGGER trigger_comp FOR <evento> ON <táboa> COMPOUND TRIGGER <Declaracións (opcionais)> -..despois de actualizar cada fila de t CREATE OR REPLACE TRIGGER trigger_2 AFTER UPDATE ON t FOR EACH ROW FOLLOWS trigger_1 BEGIN . AFTER STATEMENT IS BEGIN <acción> END AFTER STATEMENT.Novidades Oracle 11g Ordenación da execución de triggers Útil se existen varios triggers para o mesmo evento/granularidade/tempo activación Cláusula FOLLOWS CREATE OR REPLACE TRIGGER trigger_1 AFTER UPDATE ON t FOR EACH ROW BEGIN . -. Triggers en Oracle [Curso 2011-2012] 20 / 21 . BEFORE EACH ROW IS BEGIN <acción> END BEFORE EACH ROW. AFTER STATEMENT IS BEGIN FOR i in tab_prod. BEFORE EACH ROW IS BEGIN IF :new. END AFTER STATEMENT.codprod.last) := :new. tab_prod. END LOOP.exemplo -.first . tab_prod tab_prod_t := tab_prod_t().extend. END trigger_comp.Similar ó exemplo que usa un package CREATE OR REPLACE TRIGGER trigger_comp FOR INSERT ON PRODUTO COMPOUND TRIGGER TYPE tab_prod_t IS TABLE OF PRODUTO.Novidades Oracle 11g Triggers compostos (compound triggers) .last LOOP DELETE FROM PRODUTO WHERE codprod = tab_prod(i)..prezo<0 THEN tab_prod. Triggers en Oracle [Curso 2011-2012] 21 / 21 . tab_prod(tab_prod.Codprod%TYPE. END IF. END BEFORE EACH ROW.
Copyright © 2024 DOKUMEN.SITE Inc.