Download - PL/SQL*

Transcript
Page 1: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

1

PL/SQL*PL/SQL*

*Tomado del curso de Francisco Moreno*Tomado del curso de Francisco Moreno

Page 2: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

2

Funciones

Cuando un subprograma posea exactamente un argumento de salida, es mejor crear una función que un procedimiento y así se puede involucrar directamente en expresiones

Sintaxis:

CREATE [OR REPLACE] FUNCTIONFUNCTION nombre_función[ ( arg1 [modo] tipo [, arg2 [modo] tipo ...] ) ]RETURN tipo_de_datoRETURN tipo_de_datoISBloque de PL/SQL

Page 3: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

3

Ejemplo

CREATE OR REPLACE FUNCTION area_circulo (radio IN NUMBER) RETURN NUMBER IS pi CONSTANT NUMBER(5,4) := 3.1416;BEGIN RETURN ( radio * radio * pi );END;/Invocación en SQL*Plus: VAR a NUMBER; EXECUTE :a := area_circulo(3); PRINT a;

Page 4: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

4

Ejercicio: Elaborar una función que devuelva el factorial de un número.

n > 0 n*(n-1)! n! = n = 0 1 n < 0 error (-1)

- Elaborarlo recursivo - Elaborarlo no recursivo

Recursividad

Page 5: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

5

Solución recursiva

CREATE OR REPLACE FUNCTION factorialr(n NATURAL) RETURN NUMBER ISBEGIN IF n=0 THEN RETURN 1; ELSE RETURN n*factorialr(n-1); END IF;END;/

Rango: 0,1,…2147’

Page 6: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

6

Solución iterativa

CREATE OR REPLACE FUNCTION factorialnr(n NATURAL) RETURN NUMBER IS fact NUMBER := 1;BEGIN FOR k IN 1..n LOOP fact := fact * k; END LOOP; RETURN fact;END;/

Page 7: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

7

Las funciones se pueden usar en las consultas así:

CREATE TABLE numero( num NUMBER(10) PRIMARY KEY);INSERT INTO numero VALUES(1);INSERT INTO numero VALUES(3);

SELECT 'El factorial de ' || num || ' es ' || factorialr(num) AS factFROM numero;

Incluso se puede hacer algo como:

SELECT 'El factorial de ' ||factorialr(num) || ' es '|| factorialnr(factorialr(num)) AS factFROM numero;

Page 8: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

8

Paquetes

Un paquete es una agrupación de funciones, procedimientos y variables.

Clasifican los subprogramas de acuerdo a una categoría elegida por el programador o diseñador

Los paquetes se dividen en 2 partes: Especificación Definiciones de vbles “públicas” y

prototipos de los subprogramas Cuerpo (BODY) Implementación de los subprogramas

descritos en la especificación y vbles privadas

Page 9: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

9

CREATE PACKAGE nom_paquete IS -- Variables públicas -- Declaración de subprogramasEND;/

CREATE PACKAGE BODYBODY nom_paquete IS -- Variables privadas /* Implementación de subprogramas privados */ /* Implementación de subprogramas declarados en la especificación */END;/

Sintaxis

EESSPPEECC IIFF IICCAACC IIÓÓNN

CCUUEERRPPOO Los subprogramas Los subprogramas

privados privados deben deben implementarse implementarseantes que los otrosantes que los otros

Page 10: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

10

Ejemplo: Creación de la especificación:

CREATE OR REPLACE PACKAGE matematico IS FUNCTION factorial(n NATURAL) RETURN NUMBER; FUNCTION dist_puntos( x1 NUMBER, y1 NUMBER, x2 NUMBER, y2 NUMBER) RETURN NUMBER;END;/

Page 11: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

11

Ejemplo: Implementación

CREATE OR REPLACE PACKAGE BODY matematico IS FUNCTION fact (n NATURAL) RETURN NUMBER IS BEGIN IF n=0 THEN RETURN 1; ELSE RETURN n*fact(n-1); END IF; END;

PROCEDURE error(mensaje VARCHAR) IS BEGIN DBMS_OUTPUT.PUT_LINE(mensaje); END;

Continúa

Subprogramas privadosSubprogramas privados

Page 12: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

12

Cont. ImplementaciónFUNCTION factorial(n NATURAL) RETURN NUMBER IS BEGIN IF (n>20) THEN error('Valor demasiado grande'); RETURN -1; ELSE RETURN fact(n); END IF; END;

FUNCTION dist_puntos(x1 NUMBER, y1 NUMBER, x2 NUMBER, y2 NUMBER)

RETURN NUMBER IS BEGIN RETURN (SQRT(POWER(x2 - x1,2) + POWER(y2 - y1,2) ) ); END; END; --Fin del paquete/

Subprogramas PúblicosSubprogramas Públicos

Page 13: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

13

Para ejecutar:a) VAR a NUMBER;EXECUTE :a := matematico.factorial(3);PRINT a b) EXECUTE :a := matematico.dist_puntos(0,0,1,1);PRINT ac) EXECUTE :a := matematico.factorial(-5);Errord) EXECUTE matematico.error('Mensaje');Error, el subprograma es privado

Imprime 6

Imprime 1.4142…

Page 14: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

14

Ahora se invocará desde un SELECT a la función de distancia entre puntos:Sea la tabla:

CREATE TABLE punto( coordx NUMBER(10), coordy NUMBER(10), PRIMARY KEY(coordx, coordy) );INSERT INTO punto VALUES(0,0);INSERT INTO punto VALUES(1,1);INSERT INTO punto VALUES(0,4);

Page 15: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

15

SELECT 'La distancia del origen a (' || coordx || ',' || coordy || ')' || ' es ' || matematico.dist_puntos(0,0,coordx,coordy) AS distanciaFROM punto;

¿Qué hace la siguiente consulta?

SELECT p1.coordx p1x,p1.coordy p1y, p2.coordx p2x,p2.coordy p2y, matematico.dist_puntos(p1.coordx,p1.coordy, p2.coordx,p2.coordy) AS distanciaFROM punto p1, punto p2ORDER BY 1,2,3,4;

Nota: En versiones anteriores a 9i para poder invocar funciones empaquetadas se requiere especificar el grado de “pureza” de la función mediante PRAGMA RESTRICT_REFERENCES.

Page 16: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

16

Sobrecarga de Subprogramas

Es posible tener dentro de un paquetedentro de un paquete un subprograma declarado varias veces con el mismo nombre pero con diferentes tipos de parámetros

No puede haber sobrecarga si los parámetros sólo varían en el modo (IN, OUT)

No puede haber sobrecarga si ésta se basa exclusivamente en el tipo de retorno de la función

Debe haber diferencia entre la familia de los tipos, ejemplo CHAR vs. VARCHAR se consideran iguales

Page 17: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

17

No puede haber sobrecarga entre:

PROCEDURE xxx(a VARCHAR)

PROCEDURE yyy(a IN NUMBER)

FUNCTION zzz(a IN NUMBER)

RETURN NUMBER

PROCEDURE xxx(b CHAR)

PROCEDURE yyy(b OUT NUMBER)

FUNCTION zzz(b IN NUMBER) RETURN VARCHAR

Page 18: PL/SQL*

25/11/07

Ejemplo

CREATE OR REPLACE PACKAGE insercion IS PROCEDURE insertar(n NUMBER); PROCEDURE insertar(cad VARCHAR);END;/

Sean las tablas:

CREATE TABLE numero(num NUMBER(10));CREATE TABLE mensaje(texto VARCHAR2(10));

Page 19: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

19

CREATE OR REPLACE PACKAGE BODY insercion IS PROCEDURE insertar(n NUMBER) IS BEGIN INSERT INTO numero VALUES(n); END; PROCEDURE insertar(cad VARCHAR) IS BEGIN INSERT INTO mensaje VALUES(cad); END;END;/

Para Ejecutar:SQL> EXECUTE insercion.insertar('Hola');SQL> EXECUTE insercion.insertar(8);

InvocaciónInvocación

Page 20: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

20

Variables en los Paquetes

Las variables en los paquetes son persistentes (durante la sesión) Las variables declaradas en la especificación son

públicas, es decir, pueden ser accesadas y modificadas directamente desde otros subprogramas o bloques anónimos

Las variables declaradas en el cuerpo son privadas, sólo pueden ser accesadas dentro de éste. Si desean “verse” desde afuera del cuerpo se debe

crear un subprograma (público) a través del cual se accesen (cf. encapsulamiento)

Page 21: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

21

CREATE OR REPLACE PACKAGE vbles IS nro_veces NUMBER(3) := 0; -- Vble

pública PROCEDURE incrementa_veces; -- Ver Nota PROCEDURE muestra_veces; -- Ver Nota PROCEDURE muestra_impresiones; -- Requerido END; /

Nota: Estos procedimientos no son estrictamente necesarios aunque

recomendables ¿por qué?

Ejemplo

Subprogramas públicos

Page 22: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

22

CREATE OR REPLACE PACKAGE BODY vbles IS nro_impresiones NUMBER(3) :=0; --Variable privada PROCEDURE incrementa_veces IS BEGIN nro_veces := nro_veces + 1; END; PROCEDURE muestra_veces IS BEGIN DBMS_OUTPUT.PUT_LINE(nro_veces); nro_impresiones := nro_impresiones + 1; END; PROCEDURE muestra_impresiones IS BEGIN DBMS_OUTPUT.PUT_LINE(nro_impresiones); END;END;/

Page 23: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

23

Para ejecutar:

EXECUTE vbles.muestra_veces; EXECUTE vbles.muestra_impresiones; EXECUTE vbles.incrementa_veces; EXECUTE vbles.muestra_veces; EXECUTE vbles.muestra_veces; EXECUTE vbles.muestra_impresiones;

0

1

1

1

3

De nuevo:

Page 24: PL/SQL*

25/11/07 Laboratorio de Bases de Datos

24

Directamente se pueden accesar las variables públicas pero

NO las privadas por ejemplo:

BEGIN vbles.nro_veces := vbles.nro_veces +1;END;/

BEGIN DBMS_OUTPUT.PUT_LINE(vbles.nro_veces);END;/

BEGIN DBMS_OUTPUT.PUT_LINE(vbles.nro_impresiones);END;/ Genera error porque nro_impresiones NO es pública