Está en la página 1de 26

UNIVERSIDAD NACIONAL MAYOR DE SAN MARCOS

(Universidad del Perú, DECANA DE AMÉRICA)

FACULTAD DE CIENCIAS MATEMÁTICAS


Escuela Profesional de Estadística

2020-I

Base de Datos

PL/SQL

Prof. Lam Zhing Fong


Unidades

Bloque Anónima

Función Select * from all_objects

Librería where object_type in ('FUNCTION', 'PROCEDURE',
'PACKAGE', 'PACKAGE BODY', 'TRIGGER',

Paquete 'LIBRARY', 'TYPE', 'TYPE BODY' )

Cuerpo de Paquete and owner = 'LIBRERIA';

Procedimiento select * from all_procedures where owner = 'LIBRERIA'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE', 'TRIGGER', 'TYPE' );

Trigger select * from all_triggers where owner = 'LIBRERIA';
select * from all_types where owner = 'LIBRERIA';

Tipo

Cuerpo de Tipo
Bloque
<<demo1>> --etiqueta, opcional

Unidad básica de un declare
programa PL/SQL num number;
result number;

Declare(opc), begin,
exception(opc), end. function factorial(n number) return number is
begin

Puede ser ejecutado: if n < 2 then
return 1;
– Individualmente else
return n * factorial(n-1);
– Como parte de un programa. end if;
end;

No son almacenados (bloque
anónimo, así tuviera una begin
etiqueta). num := 5;
result := factorial(num);
Nota: para poder visualizar la salida de dbms, en dbms_output.put_line('Result= ' || result);
sqldeveloper, ir a menu ver, salida de dbms, y hacer clik end;
en el iconito de mas para seleccionar una conexión.
/
Bloque
<<compute_ratio>>
<<another_label>>
DECLARE
numerator NUMBER := 22;
denominator NUMBER := 7;
BEGIN
<<another_label>>
DECLARE
denominator NUMBER := 0;
BEGIN
DBMS_OUTPUT.PUT_LINE('Ratio with compute_ratio.denominator = ');
DBMS_OUTPUT.PUT_LINE(numerator/compute_ratio.denominator);

DBMS_OUTPUT.PUT_LINE('Ratio with another_label.denominator = ');


DBMS_OUTPUT.PUT_LINE(numerator/another_label.denominator);

EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Divide-by-zero error: can''t divide '
|| numerator || ' by ' || denominator);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Unexpected error.');
END inner_label;
END compute_ratio;
/
Bloque
DECLARE
cursor c1 (user varchar2) is
select table_name from all_tables
where owner = user;
BEGIN
for tabla IN c1('LIBRERIA')
loop
execute immediate 'drop table ' || usuario || '.' || tabla.table_name || ' cascade constraints';
end loop;
END;
/
Subprogramas

Procedimientos y funciones

Definido a nivel de:
– Paquete. (almacenado)
– Esquema(Standalone, almacenado)
– Bloque(Anidada, almacenado si que es anidada dentro de un subprograma de paquete o standalone).

Invocación: nombre_subprograma(parámetros), ejm:
– Result := factorial(5);
– dbms_output.put_line('Result= ' || result);

Los parámetros pueden ser
– In (por defecto)
– Out
– In out

Se pueden overloaded.

Para salir de un subprograma o bloque: return.
declare
cantidadAntes Number;
Subprogramas
cantidadDespues Number;
A que nivel están definidos?
function cantidadTabla(usuario varchar2) return number is Son almacenado?
cantidad Number;
begin
select count(*) into cantidad from all_tables Notas:
where owner = usuario;
return cantidad; 1.- Puede usar is o as
end;
2.- En las funciones pueden usar result_cache (se
procedure eliminarTablasDe(usuario varchar2) as invalidan cuando los fuentes cambian, o el tiempo
cursor c1 (user varchar2) is expira entre otros factores).
select table_name from all_tables 3.- Se puede declarar y definir mas
where owner = user; adelante(forward declaration, necesario en
begin
algunas situaciones).
for tabla IN c1(usuario)
loop
execute immediate 'drop table ' || usuario || '.' ||tabla.table_name || ' cascade constraints';
end loop;
end;

begin
cantidadAntes := cantidadTabla('TESTUSER');
eliminarTablasDe('TESTUSER');
cantidadDespues := cantidadTabla('TESTUSER');
dbms_output.put_line('Antes: ' || cantidadAntes || ', despues: ' || cantidadDespues);
end;
/
Subprogramas
Create or replace function cantidadTabla(usuario varchar2) return number is A que nivel están definidos?
cantidad Number;
Son almacenado?
begin
select count(*) into cantidad from all_tables Como se invoca?
where owner = usuario;
return cantidad;
end;
/

Create or replace procedure eliminarTablasDe(usuario varchar2) as


cursor c1 (user varchar2) is
select table_name from all_tables
where owner = user;
begin
for tabla IN c1(usuario)
loop
Notas:constraints';
execute immediate 'drop table ' || usuario || '.' ||tabla.table_name || ' cascade
end loop;
end;
/
Paquetes

Colección de objetos de programa relacionados.

Objetos de programa
– Procedimientos.
– Funciones.
– Variables
– Constantes
– Cursores.
– Excepciones.

No se pueden
– ser invocado.
– parametrizada
– anidada.
Paquete - Estructura

Especificación(obligatoria) y
cuerpo(caso necesario).
CREATE PACKAGE nombre AS

Especificación -- declaración de tipos e items públicos
– visibles(publicas) -- especificaciones de subprogramas
END [nombre];

Cuerpo
CREATE PACKAGE BODY nombre AS
– No visibles. -- declaración de tipos e items públicos
– Declaraciones privadas -- cuerpos de subprogramas
[BEGIN
– Implementación de especificación -- sentencias de inicializacion]
END [nombre;
Ejemplo
create or replace package gestion_empleado as
function nuevo(apellido varchar, nombre varchar, local_id number, cargo_id number) return number;
procedure darDeBaja(empid number);
End;

create or replace package body gestion_empleado as

function nuevo(apellido varchar, nombre varchar, local_id number, cargo_id number) return number is
empId number;
Begin
select nvl(max(id),0)+1 into empId from empleado;
dbms_output.put_line('Ante de insertar: ' || empId);
insert into empleado(id, apellido, nombre, local_id, cargo_id) values (empId, apellido, nombre, local_id, cargo_id);
return (empId);
End;

procedure darDeBaja(empid number) as


Begin
Delete empleado where id = empid;
End;

End gestion_empleado;
Invocación
declare
empId number;
begin
empId := gestion_empleado.nuevo('Perez', 'Juan', 1, 1);
DBMS_OUTPUT.PUT_LINE('Se ha insertado un registro con id ' || empId);
gestion_empleado.darDeBaja(empId);
DBMS_OUTPUT.PUT_LINE('Se ha eliminado un registro con id ' || empId);
end;
Variables
declare
x number := 10;
y number := 20;
limite constant real := 5000.00;
max_num number; -- Si no se inicializa es null
apellido cliente.apellido%type; -- mismo tipo que una columna
nombre apellido%type; -- mismo tipo que otra variable
cliente_rec cliente%rowtype; -- un registro completo
Begin
If x > y then
max_num := x;
else
max_num := y;
end if;
cliente_rec.apellido := 'Perez';
select apellido, nombre into apellido, nombre from cliente where id = 1;
dbms_output.put_line('Valores:' || apellido || ', ' || nombre);
select * into cliente_rec from cliente where id = 1;
dbms_output.put_line('Valores:' || cliente_rec.id || ', ' || cliente_rec.apellido || ', ' || cliente_rec.nombre);
End;
Tipo de Datos SQL

Oracle built-in
– Carácter: char, varchar2, nchar, nvarchar2
– Numero: number, float, binary_float, binary_double
– Long y raw: long, long raw, raw
– Datetime: date, timestamp, interval year, interval day
– Large object: blob, clob, nclob, bfile
– Rowid: Rowid, urowid

ANSI suportado:
– Character, char, nchar, varchar, national(character y char)
– Numeric, decimal, dec, integer, int, smallint, float, double, real

User defined

Oracle supplied
– any_types
– xml_types
– spatial_types
– media_types
Tipo de Datos (escalar) PL/SQL

Tipo de Datos SQL SUBTYPE Balance IS NUMBER;
SUBTYPE Counter IS NATURAL;


Boolean SUBTYPE Balance IS NUMBER(8,2);
SUBTYPE Word IS CHAR(6);


PLS_INTEGER subtype REAL is FLOAT; -- FLOAT(63)
subtype "DOUBLE PRECISION" is FLOAT;

BINARY_INTEGER subtype INTEGER is NUMBER(38,0);
subtype INT is INTEGER;
subtype SMALLINT is NUMBER(38,0);

REF CURSOR
subtype DECIMAL is NUMBER(38,0);
subtype NUMERIC is DECIMAL;

Subtipo user-defined subtype DEC is DECIMAL;
Control de Flujo – selección
condicional
case grado
If x > y then when ‘A’ then dbms_output.put_line(‘Excelente’);
result := 1; when ‘B’ then dbms_output.put_line(‘Bueno’);
elsif x = y then else dbms_output.put_line(‘Deficiente’);
result := 0; end case;
else
result := -1; case
end if; when grado = ‘A’ then dbms_output.put_line(‘...’);
when grado = ‘B’ then dbms_output.put_line(‘...’);
else dbms_output.put_line(‘...’);
end case;
Notas:
Comparación de igualdad es =(no==)
Es elsif (no elseif)
Las sintaxis de las sentencias simple Case y searched case casi son idénticas a sus pares
en funciones.
Control de Flujo – Iterativas
1.- Básico 2.- For loop 4.- While loop

Loop For index in [reverse] limiteinf..limitesup loop while condicion loop


sentencias Sentencias Sentencias
End loop; End loop; End loop;
3.- Cursor for loop

For item in cursor1 loop


Sentencias
End loop;
Notas:

Para salir de un bucle: exit o exit when condicion

Para continuar a la siguiente iteración: continue o continue when condicion.

Puede etiquetar los loop y referirlo en exit (por ejemplo, usado en varios niveles de anidamiento).

También soporta goto y null(que no hace nada).

Para salir de un procedimiento, función, bloque anonimo(cualq. nivel de anidamiento): return o
return valor (caso funciones).
Ejemplos
for item in
( Cursor implícito
select * from all_objects where owner = 'LIBRERIA'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'TRIGGER' )
)
loop
dbms_output.put_line(item.object_name || '-' || item.object_type || '-' || item.status);
end loop;
declare
item all_objects%rowtype;
cursor c1 is select * from all_objects where owner = 'LIBRERIA'
and object_type in ('FUNCTION', 'PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'TRIGGER');
begin
open c1;
loop
fetch c1 into item;
exit when c1%notfound;
dbms_output.put_line(item.object_name || '-' || item.object_type || '-' || item.status);
end loop;

end;
/
Sql estático
declare
testvalor number;
testid number;
begin
--execute immediate 'create table temp1 (id number, valor varchar(10))';
--execute immediate 'create sequence temp1_seq start with 1';

insert into temp1 values (temp1_seq.nextval, '111');


insert into temp1 values (temp1_seq.nextval, '222');
insert into temp1 values (temp1_seq.nextval, '333');

testid := temp1_seq.currval;
select valor into testvalor from temp1 where id = testid;

update temp1 set valor = testvalor || '***' where id = testid;


delete from temp1 where id < testid;
DBMS_OUTPUT.PUT_LINE('Cantidad eliminada: ' || SQL%ROWCOUNT);
end;
/
Notas:
1.- Similar a SQL%ROWCOUNT, otras propiedades del SQL cursor son:
SQL%IFOPEN, SQL%FOUND, SQL%NOTFOUND,

2.- nexval, currval son seudocolumnas de una sequencia. Rowid, rownum son seudocolumnas de una fila arbitratia.
Sql estático
declare

select into cli cliente%rowtype;
cursor clienteConDni is

DML select * from cliente where doc_tipo = 'D';
begin
– Update
open clienteConDni;
– Insert loop
fetch clienteConDni into cli;
– Delete exit when clienteConDni%notfound;
– Merge DBMS_OUTPUT.PUT_LINE('Cliente: ' || cli.apellido || ' ' || cli.nombre );
end loop;

TCL close clienteConDni;
end;
– Commit /
– Rollback
Cual seria la versión usando for cursor?
– Savepoint Necesita hacer open, fetch y close?
– Set transaction
Desarrolle la versión con parámetro cursor

Cursor clienteConDoc (docTipo cliente.doc_tipo%type) is ...
– Implícito (SQL Cursor, se genera por cada select y DML)
– Explicito (declara y define, open, fetch, close) (atributos notfound,
rowcount, etc igual que SQL Cursor)
SQL Dinámico

Cuando usar?
– SQL cuyo texto se desconoce en tiempo de compilacion.
– SQL no soportado en SQL Estático (DDL por ejemplo).

Maneras de ejecutar.
– Nativa

Execute immediate.

Open for, fetch y close
– Paquete DBMS_SQL
Execute immediate
create or replace procedure crearEmpleado(newid in out number, apellido varchar2, nombre varchar2,
local_id number, cargo_id number) as
begin
newid := empleado_seq.nextval;
insert into empleado (id, apellido, nombre, local_id, cargo_id, usuario_id)
values (newid, apellido, nombre, local_id, cargo_id, null);
end;
/

declare
newid number;
apellido varchar2(50) := 'aaa';
nombre varchar2(50) := 'bbb';
local_id number := 1;
cargo_id number := 1;
sql_block VARCHAR2(500);
begin
sql_block := 'begin crearEmpleado(:a, :b, :c, :d, :e); end;';
execute immediate sql_block using in out newid, apellido, nombre, local_id, cargo_id;
DBMS_OUTPUT.PUT_LINE('id: ' || newid );
end;
Variables de Cursor declare
type clientecur is ref cursor return cliente%rowtype;
declare clientes clientecur;
type clientecur is ref cursor return cliente%rowtype; c cliente%rowtype;
clientes clientecur;
c cliente%rowtype; procedure imprimir(clie clientecur) as
begin
begin loop
open clientes for select * from cliente where doc_tipo = 'D'; fetch clie into c;
exit when clie%notfound;
loop DBMS_OUTPUT.PUT_LINE(c.apellido || ' ' || c.nombre );
fetch clientes into c; end loop;
exit when clientes%notfound; end;
DBMS_OUTPUT.PUT_LINE('Cliente: ' || c.apellido || ' ' || c.nombre );
end loop; begin
close clientes; open clientes for select * from cliente where doc_tipo = 'D';
imprimir(clientes);
open clientes for select ... close clientes;
open clientes for select * from cliente where doc_tipo = 'C';
end; imprimir(clientes);
/ close clientes;

Notas: end;

No se puede hacer for cursor para las variables de cursor. /

Pueden ser simplemente ref cursor o mas estricto ref cursor tipofila.

En oracle también puede usar cursor expresión para tener cursor anidado.
Execute immediate
q := 'begin select max(id) into :a from ' || tabla || '; end;';
execute immediate q using out testid;

q := 'select max(id) from ' || tabla;


execute immediate q into testid; declare
tabla varchar(50) := 'cliente';
q varchar(200);
testid int;
begin
--q := 'begin select max(id) into :a from ' || tabla || '; end;';
--execute immediate q using out testid;
q := 'select max(id) from ' || tabla;
execute immediate q into testid;
dbms_output.put_line(testid);
end;
Variables Record
DECLARE
TYPE name_rec IS RECORD (
ape cliente.apellido%TYPE,

3 maneras: );
nom cliente.nombre%TYPE

TYPE contact IS RECORD (


– var1 rectype nombre name_rec,
fono varchar2(100)
);
– var2 tabla%rowtype friend contact;

BEGIN
– var3 var1%type friend.nombre.ape:= 'John';
friend.nombre.nom := 'Smith';
friend.fono := '1-650-555-1234';

DBMS_OUTPUT.PUT_LINE (
friend.nombre.ape || ' ' ||
friend.nombre.nom || ', ' ||
friend.fono
);

select apellido, nombre into friend.nombre


from cliente where id = 1;
END;
/
Open for
declare
type ClieCur is ref cursor;
clies ClieCur;
item cliente%rowtype;
q varchar2(500);
begin

q := 'select * from cliente where apellido like :valor';


open clies for q using '%a%';
loop
fetch clies into item;
exit when clies%notfound;
DBMS_OUTPUT.PUT_LINE('id: ' || item.id || ' apellido: ' || item.apellido);
end loop;
close clies;
end;
/

También podría gustarte