Sunteți pe pagina 1din 130

Programación ORACLE

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

Por qué PL/SQL

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

CASE - WHEN - THEN - ELSE

Instrucciones iterativas.
LOOP - WHILE - FOR
Cursores

Qué es un Cursor

Declaración

Manipulación: OPEN - FETCH - CLOSE

Atributos de un Cursor

Variables de tipo Registros

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

Qué es una Excepción

Excepciones predefinidas

Excepciones definidas por el usuario

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

Procedural Languaje SQL, que adiciona funcionalidad a


SQL añadiéndole estructuras de control, manipulación de
errores, control transaccional y capacidad de procesar
objetos.
•Soporta SQL
•Soporta POO
•Mejor ejecución
•Alta Productividad
•Totalmente Portable
•Total integración con Oracle
•Alta seguridad
Entornos

PL/SQL es un motor que interpreta y ejecuta


sentencias procedurales. Forma parte de cada
aplicación Cliente y del servidor ORACLE
Estructura en bloque
 PL/SQL en un lenguaje estructurado en bloques

 Esa es su unidad básica, con la que están


compuestos los procedimientos, funciones y bloques
anónimos. Por tanto un programa PL/SQL no es mas
que un bloque con una serie de sub-bloques
anidados.
Estructura y Anidamiento de bloques

Declare Declare
........
declaraciones
Begin
Begin ....
Begin
Cuerpo del bloque ......
End;
Exception

manipuladores de excepciones .................


End;
End;
SQL en PL/SQL
 Soporta los comandos (SELECT, INSERT, UPDATE y DELETE) lo
cual le hace facil la manipulacion de datos almacenados en la
base relacional.
 Soporta los comandos transaccionales (COMMIT, ROLLBACK y
SAVEPOINT) con lo que puedes controlar tus transacciones a
conveniencia.
 Soporta todos los tipos de datos de la base datos por lo que no
necesitas realizar conversiones de tipos entre los datos
almacenados y la aplicasion.
 Soporta SQL dinamico, una tecnica avanzada de programacion,
que hace tus aplicaciones mas flexibles y versatiles. Tu
programa puede construir tanto un comando SQL de cualquier
tipo (DML, DDL y DCL) como un bloque PL/SQL anonimo todo
esto en el aire en tiempo de ejecucion.
El problema de las Consultas

La sintaxis que adquiere el SELECT en un bloque


PL/SQL solo admite que se recupere una Fila de
datos

SELECT tema INTO tesis FROM t;

SELECT tema INTO tesis FROM T where ns = 1;


OO en PL/SQL
 Los tipos objeto (clases), son una
herramienta ideal para el modelado OO. Lo
cual reduce el tiempo y costo para desarrollar
aplicaciones complejas.
 Ademas de las cualidades que conocemos del
modelo OO (modular, mantenible, reusable,
encapsular operaciones con los datos,
evolucionar sin afectar la aplicación cliente)
nos va a permitir modelar las entidades
complejas del mundo real para reflejar mejor
el mundo que tratamos de simular.
Mejor ejecución
 Sin PL/SQL Oracle ejecuta las
sentencias SQL una por vez. Por
tanto cada sentencia genera una
nueva llamada a Oracle.
 Con PL/SQL un bloque de
sentencias es enviado a Oracle de
una vez, esto reduce de forma
drástica la comunicación entre
aplicación y Base Datos.
 Los procedimientos almacenados
son compilados una vez y
almacenados en forma ejecutable,
esto unido a que se almacenan en
la misma BD hace que su ejecución
sea mas rápida y eficiente.
 El código ejecutable es
automáticamente almacenado en la
CACHE y compartido entre los
usuarios. Esto disminuye el
requerimiento de memoria y
sobrecarga en la invocación
Conjunto de caracteres

Letras del alfabeto (mayúsculas y minúsculas)


Dígitos del 0 al 9
Símbolos: ()+-*/<>=!~^;:.'@%,"#$&_|{}?[]

Tabulaciones, espacio, cambio de línea


IF x>y THEN max:=x;ELSE max:=y;END IF; | IF x > y THEN
| max := x;
| ELSE
| max := y;
| END IF;
Identificadores

Comienzan con letra $Nombre 1apell

Incluyen letras, números y los signos $ # _ M@sol

Máximo 30 caracteres

No diferencian Mayúsculas/Minúsculas

GetNombre = GETNOMBRE
Identificadores

Conjunto se palabras reservadas: BEGIN EXCEPTION END ...

Las comillas “” se utilizan para resolver identificadores:


“Exception”
"last name"
Literales de Cadena: ‘PEREZ’ <> ‘Perez’

Literales numéricos: 5 -3 +17 ....

Literales Booleanos TRUE FALSE


Delimitadores
 := Asignación
 => Asociar parámetro
 || Concatenar cadenas
 ** Exponencial
 << >> Delimitar etiquetas
 /* */ Delimitar comentarios multilíneas
 .. Operador de rango
 <> Desigualdad
 != Desigualdad
 ~= Desigualdad
 ^= Desigualdad
 <= Menor igual
 >= Mayor igual
 -- Comentario de una linea
Declaraciones

Los objetos deben ser declarados antes de la referencia


Una declaración por línea en la sección declarativa
Las variables no inicializadas se asumen NULL
DECLARE
pDireccion VARCHAR2(45);
salario PLS_INTEGER := 0;
edad PLS_INTEGER DEFAULT 20;
dpto VARCHAR2(20):=‘CIDP’;
salMinimo CONSTANT PLS_INTEGER := 198;
acct_id INTEGER(4) NOT NULL := 9999;
BEGIN

Tipos de Datos simples.

Todos los tipos SQL:


VARCHAR2(n)

CHAR(m)

NUMBER(n,m) PLS_INTEGER BINARY_INTEGER

DATE
BOOLEAN

Datos Abstractos
Todos los tipos de datos
Expresiones.

Cualquier combinación de variables, literales y operadores


que determinan un valor.
El operador determina el tipo de expresión

Pueden tener significado autónomo:

A:=‘Rodríguez’;
Pueden requerir formar parte de alguna instrucción:

IF A = ‘Rodríguez’ THEN .....


Operadores.

Asignación :=

Concatenación ||

Relación < > <> = != <= >=

Lógicos NOT AND OR

LIKE BETWEEN IN

IS NULL IS NOT NULL


ej
 SELECT last_name FROM employees
WHERE last_name LIKE '%A\_B%'
ESCAPE '\';
Ámbito y Visibilidad.

Las variables son LOCALES y están en ámbito en el


bloque donde se declaran
Son GLOBALES y están en ámbito en todos los bloques
anidados
Las declaraciones LOCALES tienen precedencia sobre
las GLOBALES
Los bloques se pueden NOMBRAR y las variables
CUALIFICAR para hacerse VISIBLES.
<<Dpto>>
DECLARE
sexo CHAR(1);
salario PLS_INTEGER:=100;
edad PLS_INTEGER:=41;
BEGIN
dbms_output.put_line( salario);
dbms_output.put_line(edad);
dbms_output.put_line(sexo);
DECLARE
sexo CHAR(1):=‘M ‘;
salario PLS_INTEGER;
BEGIN
salario:=200;
dbms_output.put_line( salario);
dbms_output.put_line(edad);
dbms_output.put_line(sexo);
dbms_output.put_line(Dpto.salario);
END;
END;
Visualizar Variables.

El paquete predefinido DBMS_OUTPUT permite


visualizar cadenas de caracteres por el display.

DBMS_OUTPUT.PUT_LINE(‘String’);

Bajo la herramienta SQLPLUS se debe habilitar la


visualización

SET SERVEROUTPUT ON
Declaraciones dinámicas.

El atributo %TYPE permite declara una variable del


tipo de una columna de datos de una tabla.
Ventajas:
El programa se adapta dinámicamente a los posibles
cambios que sufra el modelo de datos.
municTexto municipio.descripcion%TYPE;

Pueden declararse registros del tipo de una tabla, para


eso se utiliza el atributo %ROWTYPE
generales estudiante%ROWTYPE;
Ejercicio.

Escenario:

Tabla: Municipio

Construir un Bloque que obtenga la descripción del


código 1
Declare
municTexto municipio.descripcion%TYPE;
Begin
SELECT descripcion INTO municText
FROM municipio WHERE codigo = 1;
DBMS_OUTPUT.PUT_LINE(‘Municipio’ || municTexto);
End;
Funciones predefinidas.

Se pueden utilizar todas las funciones definidas en


SQL formando parte de expresiones

Nombre:=UPPER(nombre);
Valor:=TO_CHAR(salario);
Apellido:=SUBSTR(generales,15,10);

Excepto las funciones agrupadoras


Sub Tipos

Restringen el conjunto de valores válidos para una


variable o sirven de seudónimos para un tipo

DECIMAL

INTEGER

SMALLINTEGER

REAL
Condicional IF

IF expresion THEN .....


END IF;

IF expresion THEN .....


ELSE ......
END IF;

IF expresion1 THEN .....


ELSIF expresion2 THEN ....
ELSIF expresion3 THEN .....
ELSE .....
END IF;
Condicional CASE
CASE selector
WHEN expression1 THEN result1
WHEN expression2 THEN result2 ...
WHEN expressionN THEN resultN
[ELSE resultN+1]
END;

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

FOR i IN [REVERSE] li..ls LOOP


< Cuerpo del ciclo >
END LOOP;

i variable de ciclo, no hay que declararla, tiene ámbito


y visibilidad sólo en el cuerpo del ciclo.
Declare
H number:=0;
Begin
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE(‘Iteración #’ || TO_CHAR(i));
h:=i;
END LOOP;
DBMS_OUTPUT.PUT_LINE(‘Tot iteraciones: ’ || TO_CHAR(h));
END;
Ej.
Selección dinámica del Rango

SELECT COUNT(empno) INTO emp_count
FROM emp;

FOR i IN 1..emp_count LOOP


...
END LOOP;

Ej.
Referenciar Variables Globales
<<main>>
DECLARE
ctr INTEGER;
...
BEGIN
...
FOR ctr IN 1..25 LOOP
...
IF main.ctr > 10 THEN – referencia variable global
...
END IF;
END LOOP;
END main;

<<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

Obtener un listado con el total de estudiantes


por cada municipio.
Solución SQL

SELECT descripcion || ‘:’, count(*) total


FROM estudiante e, municipio m
WHERE e.municipio = m.codigo
GROUP BY descripcion
ORDER BY DESC Total;
Ciclo LOOP

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

WHILE < condicion > LOOP


< cuerpo del ciclo >
END LOOP;
Cursores

Un cursor pudiera definirse como un fichero virtual


donde su contenido se crea dinámicamente en el run
time cuando se ejecuta el Query asociado.

Explícitamente se declaran cuando se necesita


procesar un Query que retorna múltiples filas

Los cursores deben ser declarados en la sección


declarativa de un bloque
Declaración de un cursor

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;

CURSOR c3 (low INTEGER DEFAULT 0, high INTEGER DEFAULT 99) IS


SELECT ...
En un bloque se pueden declarar tantos cursores como sean necesarios
Operaciones sobre un Cursor
OPEN – FETCH - CLOSE

Los cursores se abren para determinar el conjunto


activo ( filas que cumplen la condicion )

La operación OPEN ejecuta el Query asociado

OPEN c;
Acceder al contenido del cursor

Para extraer las filas del conjunto activo de un


Cursor se utiliza la operación FETCH

FETCH va retornando, de una en una, las filas del


cursor y depositando su contenido en variables para
su posterior manipulación

Si comparamos con un fichero es el equivalente al GET

FETCH c INTO <lista de variables>;


Cerrar CURSOR
CLOSE nombre_cursor;
 Con esta sentencia se cierra un cursor
abierto y de esta forma se libera el
espacio reservado de memoria.
Atributos de un cursor

Comunmente el FETCH se ubica en alguna estructura


iterativa: LOOP – WHILE - FOR

Los atributos asociados a un cursor permiten obtener


información sobre el mismo

Determinar si el último FETCH recuperó o no alguna fila

%FOUND, %NOTFOUND

Obtener el acumulado de filas procesadas: %ROWCOUNT


Ej.
DECLARE
nombre estudiante.nombre%TYPE;
municipio estudiante.municipio%TYPE;
CURSOR c IS SELECT nombre,municipio
FROM estudiante;
BEGIN
OPEN c;
LOOP
FETCH c INTO nombre,municipio;
EXIT WHEN c%NOTFOUND;
END LOOP;
CLOSE c;
END;
---------------------------------------------------------
DECLARE
CURSOR c1 IS SELECT ename FROM emp;
name1 emp.ename%TYPE;
name2 emp.ename%TYPE;
name3 emp.ename%TYPE;
BEGIN
OPEN c1;
FETCH c1 INTO name1; -- this fetches first row
FETCH c1 INTO name2; -- this fetches second row
FETCH c1 INTO name3; -- this fetches third row ...
CLOSE c1;
END;
Ejercicio

Escribir un programa que muestre un listado por la


pantalla con las generales y el municipio de
residencia de cada estudiante. El municipio se debe
decodificar a partir de la tabla ”municipio”. AL final
imprimir una fila resumen con el total de alumnos.
FOR LOOP CURSORES

Simplifican la codificación de un programa al


unificar las operaciones OPEN-FETCH-CLOSE
FOR rec_C IN C LOOP
< cuerpo del ciclo >
END LOOP;

Rec_C se declara dinámicamente y tiene ámbito y visibilidad


en el cuerpo del ciclo.
Uso de alias en un cursor
DECLARE
CURSOR c1 IS SELECT empno, sal+NVL(comm,0) wages, job
FROM ...

BEGIN

FOR cur IN c1 LOOP

IF cur.wages < 1000 THEN ...

END LOOP
END;
Subquery en vez de
Declaración Explicita
BEGIN
FOR rec_C IN (SELECT …) -- declaracion explicita
LOOP
< cuerpo del ciclo >
END LOOP;
END;

 Con este tipo de declaración no es necesario la definición previa


del cursor.
 Este cursor solo tiene visibilidad dentro del FOR-LOOP.
Ej.
DECLARE
result temp.col1%TYPE;
CURSOR c1
IS SELECT n1, n2, n3 FROM data_table WHERE exper_num = 1;
BEGIN
FOR c1_rec IN c1 LOOP
/* calculate and store the results */
result := c1_rec.n2 / (c1_rec.n1 + c1_rec.n3);
INSERT INTO temp VALUES (result, NULL, NULL);
END LOOP;
COMMIT;
END;
----------------------------------------------------------------------------------------------
DECLARE
bonus REAL;
BEGIN
FOR emp_rec IN (SELECT empno, sal, comm FROM emp)
LOOP
bonus := (emp_rec.sal * 0.05) + (emp_rec.comm * 0.25);
INSERT INTO bonuses VALUES (emp_rec.empno, bonus);
END LOOP;
COMMIT;
END;
Cursores con parámetros

Al igual que las funciones, a los cursores se le


pueden pasar parámetros.

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)

TYPE GenericCurTyp IS REF CURSOR; -- devil (no restrictiva)



Declaracion de
variables de cursor
 Declarar una variable del tipo definido.
Ej.
DECLARE
TYPE DeptCurTyp IS REF CURSOR RETURN dept%ROWTYPE;
dept_cv DeptCurTyp; -- declaracion de variable

my_cursor SYS_REFCURSOR; -- Tipo cursor definido por Oracle


Ej.
Usando %ROWTYPE como tipo de retorno
DECLARE
TYPE TmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE;
tmp_cv TmpCurTyp; -- declare cursor variable
TYPE EmpCurTyp IS REF CURSOR RETURN tmp_cv%ROWTYPE;
emp_cv EmpCurTyp; -- declare cursor variable

Usando una variable de tipo %TYPE como tipo de retorno


DECLARE
dept_rec dept%ROWTYPE; -- declare record variable
TYPE DeptCurTyp IS REF CURSOR RETURN dept_rec%TYPE;
dept_cv DeptCurTyp; -- declare cursor variable

Usando un tipo RECORD como retorno


DECLARE
TYPE EmpRecTyp IS RECORD (
empno NUMBER(4),
ename VARCHAR2(1O),
sal NUMBER(7,2)
);
TYPE EmpCurTyp IS REF CURSOR RETURN EmpRecTyp;
emp_cv EmpCurTyp; -- declare cursor variable

Pasando como parametro a un procedimiento


DECLARE
TYPE EmpCurTyp IS REF CURSOR RETURN emp%ROWTYPE;
PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp) IS ...
Manipular variable de cursor
OPEN-FOR, FETCH y CLOSE

OPEN {cursor_variable | :host_cursor_variable} FOR


dynamic_string [USING bind_argument[, bind_argument]...];
Ej.
DECLARE
TYPE EmpCurTyp IS REF CURSOR; -- define weak
REF CURSOR type emp_cv EmpCurTyp; -- declare cursor variable
my_ename VARCHAR2(15);
my_sal NUMBER := 1000;
BEGIN
OPEN emp_cv FOR -- open cursor variable
'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal;
...
END;
FETCH {cursor_variable | :host_cursor_variable}
INTO {define_variable[, define_variable]... | record};

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

En PL/SQL se pueden declarar TIPOS de datos


compuestos o REGISTROS. Un registro está formado
por campos, cada uno de un tipo específico.
Se pueden declarar variables de los tipos definidos
TYPE generales IS RECORD (
nombre estudiante.nombre%TYPE,
Apellidos estudiante.apellidos%TYPE
municipio persona.municipio%TYPE);
Estudiante generales;
FETCH c INTO estudiante;
Referenciar campos de un Record

Similar a una estructura “C” utilizando notación de punto

Registro.campo

IF estudiante.municipio = ‘Lisa’ THEN .....

Un campo de un registro puede aparecer en la parte


izquierda de una expresión

estudiante.Nombre:=‘Juan’;
Tablas PL/SQL

Con las tablas PL/SQL se implementa la


manipulación de arreglos

TYPE type_name IS TABLE OF element_type [NOT NULL]


INDEX BY BINARY_INTEGER;
Tablas PL/SQL

TYPE tMunic IS TABLE OF VARCHAR2(25)


INDEX BY BINARY_INTEGER;

Munic tMunic;

Munic(1):=‘Lisa’;

FOR i IN 1..15 LOOP


IF Munic(i) = ‘Playa’ THEN .....
Tablas Complejas

TYPE generales IS TABLE OF estudiante%ROWTYPE


INDEX BY BINARY_INTEGER;

estudiante generales;

SELECT * INTO estudiante(9) FROM estudiante


WHERE numero=9;

IF estudiante(9).municipio = ‘PLAZA’ THEN .....


Tablas Complejas

TYPE generales IS RECORD ( nombre VARCHAR2(15),


municipio number(2));

TYPE curso IS TABLE OF generales


INDEX BY BINARY_INTEGER;

Testudiante curso;
Algunas propiedades de las tablas

No tienen definido un límite

No se almacenan en algún orden determinado,


pueden no ser consecutivas

La memoria de una tabla se va asignando en la


medida en que se “insertan” filas

Un elemento de tabla se crea cuando se utiliza


en una parte izquierda de una asignación
Atributos de una Tabla

Con los atributos de una tabla se obtiene información


asociada

Un atributo se referencia con la sintaxis tabla.atributo

COUNT: número de filas de una tabla

DELETE: elimina elementos de una tabla


DELETE
DELETE(i)
DELETE(i,j)
EXISTS: retorna TRUE si el elemento i-esimo existe
Atributos de una Tabla

FIRST y LAST retornan el índice de la primera y última


fila de una tabla

NEXT y PRIOR retornan el índice del siguiente/anterior


elemento de una tabla
Ejercicio

Escenario: Todas las tablas del esquema

Obtener toda la información del estudiante más joven, con el


siguiente formato:

Datos del estudiante

Número Nombre Apellido Identid Sexo Municipio(descripción)


--------- ---------- --------- -------- ------ --------------------------

Cursos recibidos

Titulo FechaIni FechaFin Evaluación Creditos Profesor


------ ---------- ----------- ------------ ---------- ---------
Solución

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

Escenario: Tablas estudiante,est_curso y profesor

Una vez que se ha obtenido la información de los cursos


vencidos por los estudiantes. Insertar en la tabla de
profesores a aquellos que tengan 5 de promedio.
Solución

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

Constituyen la forma primaria de rehusar código

Se pueden almacenar en la BD (stored procedures)

Al almacenarlos en la BD comenzamos a hacer


“programación en la BD”. Los clientes solo hacen un
llamado. El motor de la BD es quien interpreta y ejecuta el
procedimiento

Para almacenar un procedimiento/función en la BD se utiliza


el comando SQL CREATE PROCEDURE/FUNCTION
Algunas ventajas

Extienden la funcionalidad de un lenguaje

Permiten modularizar un diseño

Garantizan el rehuso y simplifican los mantenimientos

Ofrecen un nivel de abstracción


Procedures

Un procedimiento es un bloque PL/SQL con nombre que puede


aceptar parámetros y retorna valores a través de estos.
( void function en “C”, SUBROUTINES en VB, etc)
Se invocan como una sentencia independiente, no pueden
formar parte de una expresión

getEstad(6);

IF getEstad(6) = ..... -- Ilegal


Como se declara un procedimiento

CREATE OR REPLACE
PROCEDURE prcName ( lista de parámetros ) IS
<sección declarativa>
BEGIN
<sección ejecutable>
EXCEPTION
<manipuladores de excepciones>
END;
Funciones

Un bloque PL/SQL con nombre que puede aceptar


parámetros y retorna un valor

Se invoca en el contexto de alguna expresión

Edad:=getEdad(‘Ramon’);

El tipo de la función se deriva del tipo del retorno

Las funciones también pueden retornar valores a


través de parámetros;
Como se declara una función

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

Termina la ejecución de un procedimiento o función. En el


caso de una función debe contener una expresión
create or replace FUNCTION getEdad ( id varchar2) RETURN NUMBER IS
e NUMBER(3);
BEGIN
select trunc((SYSDATE - TO_DATE(SUBSTR(ID,5,2) || '/' ||
SUBSTR(ID,3,2) || '/' ||
DECODE(SUBSTR(ID,7,1),'5','20','6','20',
'7','20', '8','20', '9','18', '19') ||
SUBSTR(ID,1,2),'DD/MM/YYYY'))/365)
into e FROM dual;
RETURN e;
END;
Parámetros

Pueden existir cualquier cantidad de parámetros, pero no


es buena práctica definir muchos. Mejor pensar en una lista
de atributos que se pasen como un RECORD

PROCEDURE p ( p1 t1,p2 t2,p3 t3,.....pn tn) IS...

TYPE t IS RECORD ( p1 t1,p2 t2,p3 t3,....pn tn);

PROCEDURE p ( parmList t ) IS ...


Tipos de parámetros

PUEDEN ser de entrada(solo lectura), de salida(solo


escritura) o de entrada/salida (lectura/escritura)

Procedure p ( p1 IN t1, p2 OUT t2) IS ....

Procedure p ( p1 IN OUT t1) IS ....


Sustitución de parámetros

En un llamado los parámetros se pueden sustituir por


posición o por nombre ( o ambos )

Procedure p ( pf1 t1,pf2 t2, pf3 t3 )

llamado

Por posicion:P(pa1,pa2,pa3);

Por nombre:P(pf3 => pa3, pf1 => pa1, pf2 => pa2);
Parámetros implícitos

Al declarar un parámetro se le puede definir un valor por


defecto. En estos caso el parámetro actual puede ser
omitido en el llamado.

PROCEDURE p ( pf1 t1,pf2 t2:=valor) is ....

P (pa1);

Para omitir parámetros a la izquierda en el llamado


hay que usar sustitución por nombres
Ejercicio

Crear una función que retorne los estudiantes de un


municipio dado
Paquetes

Construcción que permite agrupar funciones y


procedimientos relacionados. Los paquetes permiten
igualmente declarar variables GLOBALES a una
sesión.

Tienen dos partes: el encabezamiento (spec) y el


cuerpo (body)

En la declaración se admiten variables y firma de


procedimientos públicos.
Encabezamiento

CREATE PACKAGE estudiante IS


edad number(2);
FUNCTION getEdad ( id VARCHAR2);
FUNCTION getEdad ( num NUMBER );
END;
Cuerpo

En el cuerpo se admiten declaraciones, bloques


ejecutables y manipuladores de excepciones para cada
una de las funciones y/o procedimientos declarados en el
encabezamiento

En el cuerpo se implementan las funciones.

Todo lo que se declare en el cuerpo es invisible


fuera del paquete
Inicialización

El cuerpo del paquete puede tener una sección de


inicialización (constructor) que se ejecuta la primera vez que
se hace referencia al mismo. Puede utilizarse para inicializar
variables GLOBALES dinámicamente en tiempo de ejecución.

Puede existir un paquete sin cuerpo. Las variables GLOBALES


se consideran de sesión. Cada sesión mantiene una copia
propia. Son persistentes a la sesión.
Ventajas

Mejoran el rendimiento pues ante la primera


referencia se carga completo en memoria

Facilitan la administración y el mantenimiento


Referencia

Los datos públicos de un paquete se referencian


utilizando notación de punto

Paquete.funcion;

Paquete.variable;
Sobrecarga de métodos

Se redefinen métodos a partir de su firma

Function GetCreditos( ne number) return integer;

Function GetCreditos return integer;


Excepciones

Una Exception es una condición errónea que se dispara


durante la ejecución de un bloque PL/SQL

El disparo de una excepción resume la ejecución del


bloque en el punto en que ocurrió; el control pasa a un
manipulador si existiera.

Las excepciones se manipulan por su nombre en la


sección correspondiente de un bloque.
Excepciones predefinidas

Existe un conjunto de excepciones predefinidas que se


asocian con condiciones erróneas del lenguaje o la
Base de Datos y forman parte del lenguaje
NO_DATA_FOUND
TOO_MANY_ROWS
INVALID_NUMBER
INVALID_CURSOR
Captura de excepciones

Se capturan en la sección Exception del bloque

Exception
WHEN NO DATA FOUND THEN …….
WHEN TOO MANY ROWS THEN ……
WHEN OTHERS THEN ….
End;
Propagación

Las excepciones se van propagando desde el bloque en


que se dispara hacia los bloques más externos, hasta
que aparezca un manipulador. El flujo de ejecución
continúa en la sentencia correspondiente del siguiente
bloque de la jerarquía. Si no aparece un manipulador
se completa de forma anormal la ejecució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

Se puede forzar el disparo de una excepción, para


esto se utiliza la sentencia RAISE
RAISE estudianteSuspenso;

El programador puede definir sus propias excepciones


para gestionar errores lógicos de su aplicación.

Por ejemplo: Un estudiante en el último mes de la


maestría no puede tener asignado un tema de tesis
Excepciones definidas por el programador

Las excepciones que define el programador no se


disparan automáticamente, hay que forzarlas con
RAISE.

Se definen en la parte declarativa de un bloque y se


le aplican los mismos criterios de ámbito y visibilidad
que a las variables

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

raise_application_error(-20101, 'Estudiante suspenso');

SQLCODE

SQLERRM(nerror)
Pragma EXCEPTION_INIT

Puede asociar o redefinir un Nombre de Excepción


para cualquier ORACLE que necesite manipular

Se define la excepción y con el PRAGMA EXCEPTION_INIT


Se le asocia el código correspondiente

DECLARE
tablaInvalida EXCEPTION;
PRAGMA EXCEPTION_INIT(tablaInvalida, -942);
SQL Dinámco

Utilizamos SQL Dinámico cuando es necesario construir


consultas que referencian objetos desconocidos hasta el
tiempo de corrida

Cuando se necesita ejecutar alguna instrucción DDL,


CREATE TABLE... DROP TABLE... Etc.
EXECUTE IMMEDIATE

Ejecuta una instrucción almacenada en un String

EXECUTE IMMEDIATE str


[INTO {variable[, variable]... | record}]
[USING argumento [, [argumento]...];
EXECUTE IMMEDIATE

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

Escribir una función que retorne el total de filas


de una tabla dada.
Parámetros

Los comandos SQL se pueden codificar utilizando


parámetros que se pueden sustituir en el momento de
la ejecución

stmSQL:='SELECT count(*) FROM municipio


WHERE codigo = :cod';
EXECUTE IMMEDIATE stmSQL INTO total USING mun;

El contenido de la variable “mun” sustituye al parámetro


:cod
Algunos ejemplos

EXECUTE IMMEDIATE 'DELETE FROM municipio


WHERE codigo = :1' USING 3;

EXECUTE IMMEDIATE 'DELETE FROM municipio


WHERE codigo = ' || '3';
Ejercicio

Escribir un procedimiento que borre de una tabla dada


todas las filas pertenecientes a un municipio
SQL Dinámico en consultas multi filas

OPEN variable_cursor FOR string [USING argument];


TYPE EstCurTyp IS REF CURSOR;
c EstCurTyp;
nombre VARCHAR2(15);
edad NUMBER(3);
BEGIN
OPEN c FOR
'SELECT nombre,edad FROM estudiante WHERE edad > :s'
USING salario;
........

END;
Extraer filas del cursor

LOOP
FETCH c INTO nombre,edad;
EXIT WHEN c%NOTFOUND;
nombre.....
edad.....
END LOOP;
Ejercicio

Implementar la “clase” CODIF para cualquiera sea el


codificador

−Dado un código, obtener la descripción


−Dada una descripción, obtener el código correspondiente
−Obtener la cantidad de códigos en el codificador
−Implementar un caché del codificador en memoria
• Llevar el codificador a memoria si hace falta
• Obtener las descripciones ordenadas ascendentemente
• Obtener las descripciones ordenadas descendentemente
Trabajo Individual 1

Obtener automatizadamente un script para


crear todas la tablas del esquema
Trabajo Individual 2

1. El numero en la tabla “estudiante” puede no ser


consecutivo. Obtener un reporte con los “huecos” o rango
de valores existente.

2. Implementar una “clase” IDENTIDAD que facilite la


obtención de toda la información que ofrece el número de
identidad:
− Fecha de nacimiento completa
− Sexo
− Edad
− Validación usando el dígito de control
− Todos los estudiantes nacidos en un an o dado
− Los datos del estudiante más joven
− Los datos del estudiante más viejo

S-ar putea să vă placă și