Documente Academic
Documente Profesional
Documente Cultură
PL/SQL
Contenido del Curso
Introducción
Fundamentos
Estructuras de Control
Cursores
Trabajo Individual 1
Registros y tablas
Funciones y procedimientos
Paquetes
Trabajo Individual 2
Manipulación de errores
PL/SQL avanzado
Introducción
Entornos de ejecución
Estructura de Bloques
SQL en PL/SQL
Fundamentos
Conjunto de caracteres
Identificadores
Declaraciones
Tipos de Datos
Expresiones
Ámbito y visibilidad
Funciones predefinidas
Estructuras de Control
Instrucciones condicionales.
IF - THEN – ELSE
Instrucciones iterativas.
LOOP - WHILE - FOR
Cursores
Qué es un Cursor
Declaración
Atributos de un Cursor
FOR CURSOR
Cursores parametrizados.
Tipo Record y Tablas PL/SQL
Definir un Record
Las Tablas
Atributos de tablas
Funciones y Procedimientos
Declaración
Los Parámetros
Privilegios
Paquetes
Objetivo
El encabezamiento
El cuerpo
Ámbito y visibilidad de las variables
Sobre carga de funciones
Inicialización de un Paquete
Manipulación de Excepciones
Excepciones predefinidas
La instrucción RAISE
Captura de Excepciones
Propagación de Excepciones
PL/SQL Avanzado
SQL Dinámico
Objetos en la BD
Colecciones
Por qué PL/SQL y Ventajas
Declare Declare
........
declaraciones
Begin
Begin ....
Begin
Cuerpo del bloque ......
End;
Exception
Máximo 30 caracteres
No diferencian Mayúsculas/Minúsculas
GetNombre = GETNOMBRE
Identificadores
CHAR(m)
DATE
BOOLEAN
Datos Abstractos
Todos los tipos de datos
Expresiones.
A:=‘Rodríguez’;
Pueden requerir formar parte de alguna instrucción:
Asignación :=
Concatenación ||
LIKE BETWEEN IN
DBMS_OUTPUT.PUT_LINE(‘String’);
SET SERVEROUTPUT ON
Declaraciones dinámicas.
Escenario:
Tabla: Municipio
Nombre:=UPPER(nombre);
Valor:=TO_CHAR(salario);
Apellido:=SUBSTR(generales,15,10);
DECIMAL
INTEGER
SMALLINTEGER
REAL
Condicional IF
CASE
WHEN search_condition1 THEN result1
WHEN search_condition2 THEN result2 ...
WHEN search_conditionN THEN resultN
[ELSE resultN+1]
END;
Ej. CASE para SQL
SELECT cust_last_name, CASE credit_limit
WHEN 100 THEN 'Low'
WHEN 5000 THEN 'High'
ELSE 'Medium' END
FROM customers;
SELECT
AVG(CASE WHEN e.salary > 2000 THEN e.salary ELSE
2000 END) "Average Salary"
from employees e;
Ej. CASE para PL/SQL
DECLARE DECLARE grade CHAR(1);
grade CHAR(1) := 'B'; appraisal VARCHAR2(20);
appraisal VARCHAR2(20); BEGIN
BEGIN ...
appraisal := appraisal :=
CASE grade CASE
WHEN 'A' THEN 'Excellent‘ WHEN grade = 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good‘ WHEN grade = 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good' WHEN grade = 'C' THEN 'Good‘
WHEN 'D' THEN 'Fair' WHEN grade = 'D' THEN 'Fair'
WHEN 'F' THEN 'Poor' WHEN grade = 'F' THEN 'Poor'
ELSE 'No such grade' ELSE 'No such grade'
END; END;
END; ...
END;
Ciclo FOR
<<outer>>
FOR step IN 1..25 LOOP
FOR step IN 1..10 LOOP
...
IF outer.step > 15 THEN
...
END LOOP;
END LOOP outer;
Ejercicio.
Escenario:
Tabla: estudiante
LOOP
LOOP n:=n+1;
< Cuerpo del ciclo > END LOOP;
END LOOP;
LOOP
n:=n+1;
La salida EXIT EXIT;
END LOOP;
El EXIT WHEN LOOP
n:=n+1;
EXIT WHEN n=10;
END LOOP;
Uso de etiqueta
<<outer>>
LOOP
...
LOOP
...
EXIT outer WHEN ... – exit ambos loops
END LOOP;
...
END LOOP outer;
Ciclo WHILE
Sintaxis:
CURSOR cursor_name [(parameter[, parameter]...)]
[RETURN return_type] IS select_statement;
Parametro: nombre [IN] datatype [{:= | DEFAULT} expression]
DECLARE
CURSOR c1 IS
SELECT empno, ename, job, sal FROM emp WHERE sal > 2000;
CURSOR c2
RETURN dept%ROWTYPE IS
SELECT * FROM dept WHERE deptno = 10;
OPEN c;
Acceder al contenido del cursor
%FOUND, %NOTFOUND
Declare
CURSOR c ( n VARCHAR2 ) IS SELECT * FROM estudiante
WHERE nombre = n;
Begin
For est In c ('Juan ') Loop
-- cuerpo del ciclo
End Loop;
End;
Paso de Parametros a un
cursor FOR -LOOP
DECLARE
CURSOR emp_cursor(dnum NUMBER) IS
SELECT sal, comm FROM emp WHERE deptno = dnum;
total_wages NUMBER(11,2) := 0;
high_paid NUMBER(4) := 0;
higher_comm NUMBER(4) := 0;
BEGIN
FOR emp_record IN emp_cursor(20) LOOP
emp_record.comm := NVL(emp_record.comm, 0);
total_wages := total_wages + emp_record.sal + emp_record.comm;
IF emp_record.sal > 2000.00 THEN
high_paid := high_paid + 1;
END IF;
IF emp_record.comm > emp_record.sal THEN
higher_comm := higher_comm + 1;
END IF;
END LOOP;
INSERT INTO temp VALUES (high_paid, higher_comm, 'Total Wages: ' ||
TO_CHAR(total_wages));
COMMIT;
END;
Cursores anidados con paso
de parametros
DECLARE
CURSOR dept(dnum NUMBER) IS
SELECT DEPARTMENT_NAME, manager_id FROM emp
WHERE deptno = dnum;
CURSOR emp(mn NUMBER) is
select first_name from employees
where manager_id=mn;
BEGIN
FOR cur1 in dept(20) LOOP
For cur2 in emp(cur1.manager_id) loop
…
End loop;
End loop;
END;
Variables de Cursor
Son variables dinámicas que apuntan siempre a la fila actual del
cursor y pueden estar asociadas a cualquier “query” compatible
con el que se uso para definirla.
Pueden usarse para pasar como parámetro un cursor de un
procedimiento a otro.
Oracle las define como un puntero (igual que el C) donde se
almacenará una dirección de memoria a un objeto (una
referencia), en este caso del tipo “REF CURSOR”.
Oracle al abrir un cursor reserva un área de trabajo donde
almacena el procesamiento de la información. Para acceder a
esta usa un cursor explicito para nombrar esta área de trabajo o
usa una variable de cursor que apunte a esta área. Por tanto
con un cursor solo se puede acceder a un área de trabajo
mientras que con una variable puede accederse a varias
Definir TIPOS de referencia a
CURSOR
Para crear variables de cursor se
realizan 2 pasos.
Definir un tipo REF CURSOR.
TYPE ref_type_name IS REF CURSOR [RETURN return_type];
Ej.
DECLARE
TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE; -- fuerte (restrictiva)
Ej.
…
LOOP
FETCH emp_cv INTO my_ename, my_sal; -- proxima fila
EXIT WHEN emp_cv%NOTFOUND; -- salir si llego al final
-- procesar las filas
END LOOP;
CLOSE {cursor_variable | :host_cursor_variable};
Ej.
…
LOOP
FETCH emp_cv INTO my_ename, my_sal;
EXIT WHEN emp_cv%NOTFOUND;
-- process row
END LOOP;
CLOSE emp_cv; -- close cursor variable I
Ej.
DECLARE
TYPE EmpCurTyp IS REF CURSOR;
emp_cv EmpCurTyp;
emp_rec emp%ROWTYPE;
sql_stmt VARCHAR2(200);
my_job VARCHAR2(15) := 'CLERK';
BEGIN
sql_stmt := 'SELECT * FROM emp WHERE job = :j';
OPEN emp_cv FOR sql_stmt USING my_job;
LOOP
FETCH emp_cv INTO emp_rec;
EXIT WHEN emp_cv%NOTFOUND;
-- process record
END LOOP;
CLOSE emp_cv;
END;
Repetir el ejercicio anterior con FOR LOOP
El tipo RECORD
Registro.campo
estudiante.Nombre:=‘Juan’;
Tablas PL/SQL
Munic tMunic;
Munic(1):=‘Lisa’;
estudiante generales;
Testudiante curso;
Algunas propiedades de las tablas
Cursos recibidos
Declare
num estudiante.numero%type;
nomb estudiante.nombre%type;
apel estudiante.apellido%type;
id estudiante.identid%type;
sx estudiante.sexo%type;
mn municipio.descripcion%type;
cursor c is select nest,titulo,fechaini,fechafin,evaluacion,creditos,nombre
from est_curso ec,curso c,profesor p
where ec.ncurso = c.ncurso and
c.nprof = p.nprof;
Begin
dbms_output.put_line('Datos del estudiante');
dbms_output.put_line('Número Nombre Apellido Identid Sexo Municipio');
dbms_output.put_line('------ --------------- --------------- ----------- ---- --------------------------
');
select numero,nombre,apellido,e.identid,sexo,descripcion
into num,nomb,apel,id,sx,mn
from estudiante e, municipio m,
(select max(identid) identid from estudiante ) j
where e.identid = j.identid and
e.municipio = m.codigo;
dbms_output.put_line(rpad(num,6) ||' '|| rpad(nomb,15) ||' '|| rpad(apel,15) ||' '|| id ||' '||
rpad(sx,4) ||' '|| mn);
dbms_output.put_line('Cursos recibidos');
dbms_output.put_line('Titulo Fechaini Fechafin Evaluacion Creditos Profesor');
dbms_output.put_line('-------------------- ---------- ---------- ---------- -------- ----------------------
----');
FOR rec_C IN C LOOP
if rec_C.nest = num then
dbms_output.put_line(rpad(rec_C.titulo,20) ||' '|| to_char(rec_C.fechaini,'DD/MM/YYYY')
||' '|| to_char(rec_C.fechafin,'DD/MM/YYYY') ||' '|| rpad(rec_C.evaluacion,10) ||' '||
rpad(rec_C.creditos,8) ||' '|| rec_C.nombre);
end if;
END LOOP;
End;
Ejercicio
Declare
cursor c is select numero,nombre,apellido,identid,evaluacion
from estudiante e,est_curso ec
where ec.nest = e.numero
order by numero;
TYPE datos IS record (num estudiante.numero%type,
nom estudiante.nombre%type,
ape estudiante.apellido%type,
ide estudiante.identid%type,
eva est_curso.evaluacion%type);
TYPE dt is TABLE OF datos INDEX BY BINARY_INTEGER;
dt1 dt;
i pls_integer:=1;
suma pls_integer:=0;
cont pls_integer:=0;
Begin
FOR rec_C IN C LOOP
dt1(i):=rec_C;
i:=i+1;
end loop;
for j in 1..dt1.count loop
suma:=suma+dt1(j).eva;
cont:=cont+1;
if j = dt1.count or
dt1(dt1.next(j)).num <> dt1(j).num then
if suma/cont =5 then
dbms_output.put_line('Insertar profesor ' || dt1(j).nom);
insert into profesor values(seq_profesor.nextval,dt1(j).nom,'No
categorizado');
end if;
suma:=0;
cont:=0;
end if;
end loop;
commit;
Procedimientos y Funciones
getEstad(6);
CREATE OR REPLACE
PROCEDURE prcName ( lista de parámetros ) IS
<sección declarativa>
BEGIN
<sección ejecutable>
EXCEPTION
<manipuladores de excepciones>
END;
Funciones
Edad:=getEdad(‘Ramon’);
CREATE OR REPLACE
FUNCTION prcName ( lista de parámetros )
RETURN tipo IS
<sección declarativa>
BEGIN
<sección ejecutable>
EXCEPTION
<manipuladores de excepciones>
END;
Instrucción RETURN
llamado
Por posicion:P(pa1,pa2,pa3);
Por nombre:P(pf3 => pa3, pf1 => pa1, pf2 => pa2);
Parámetros implícitos
P (pa1);
Paquete.funcion;
Paquete.variable;
Sobrecarga de métodos
Exception
WHEN NO DATA FOUND THEN …….
WHEN TOO MANY ROWS THEN ……
WHEN OTHERS THEN ….
End;
Propagación
UNHANDLED EXCEPTION
Un ejemplo
Declare
num number(2);
Begin
SELECT numero INTO num
FROM estudiante
WHERE generales = ‘….’;
UPDATE estudiante SET tema = ‘ORACLE’
WHERE numero = num;
Exception
When NO DATA FOUND THEN
INSERT INTO estudiante
VALUES( num,’generales’,’ORACLE’);
End;
Otro ejemplo
Declare
num number(2);
Begin
Begin
SELECT ns INTO numero …….
UPDATE estudiante SET tema = ‘ORACLE’
WHERE numero = num;
print “Actualizado el estudiante….”;
Exception
When NO DATA FOUND THEN
INSERT INTO estudiante
VALUES( num,’generales’,’ORACLE’);
End;
-- Continúa la ejecución del programa
End;
Forzar una Excepción
estudianteSuspenso EXCEPTION;
Disparar excepciones definidas por el programador
RAISE nombre_excepción;
RAISE estudianteSuspenso;
Manipulación de los errores
RAISE_APPLICATION_ERROR(n_error,mensaje);
Cadena caracteres
Entero negativo hasta 2048
-20000 .. -20999
SQLCODE
SQLERRM(nerror)
Pragma EXCEPTION_INIT
DECLARE
tablaInvalida EXCEPTION;
PRAGMA EXCEPTION_INIT(tablaInvalida, -942);
SQL Dinámco
DECLARE
stmSQL VARCHAR2(200);
total PLS_INTEGER;
BEGIN
stmSQL:='SELECT count(*) FROM municipio';
EXECUTE IMMEDIATE stmSQL INTO total;
dbms_output.put_line('Total de municipios: ' || total);
END;
Ejercicio
END;
Extraer filas del cursor
LOOP
FETCH c INTO nombre,edad;
EXIT WHEN c%NOTFOUND;
nombre.....
edad.....
END LOOP;
Ejercicio