Introducción a la programación PL/SQL en Oracle

Enviado por Chuletator online y clasificado en Informática y Telecomunicaciones

Escrito el en español con un tamaño de 102,2 KB

TEMA XII. PROGRAMACIÓN DE GUIONES

INTRODUCCIÓN AL PL/SQL

SQL es un lenguaje de cuarta Generación (4GL), es decir, el lenguaje describe lo que debe hacerse, pero no La forma de realizarlo. Los lenguajes de tercera generación, en cambio, son Procedimentales. En muchas ocasiones, las estructuras procedimentales que Implementan los lenguajes 3GL son muy útiles para la realización de programas. El PL/SQL combina la potencia del SQL como 4GL con las estructuras Procedimentales de un 3GL.

PL/SQL (Lenguaje Procedimental/SQL) Es un lenguaje de programación (basado en ADA), que es, en realidad, un apoyo y Una extensión al lenguaje SQL de la Base de Datos

Oracle


Al ser procedimental, nos permite Utilizar determinadas estructuras en los programas que no podríamos utilizar de Otra manera en SQL. De esta forma podemos implementar programas más estables y Funcionales.

Se trata de un lenguaje Orientado a bloque, es decir, su unidad mínima de trabajo es el bloque. Éste es Un conjunto de declaraciones, órdenes y controles. Podemos compararlos con las Funciones o subprogramas de otros lenguajes.

Su potencia se basa en distintos Aspectos:

·Su compatibilidad con SQL. Combina la potencia Del SQL para la manipulación de datos con la capacidad de procesamiento de los Lenguajes procedimentales.

·Permite mejorar la productividad y el Rendimiento, puesto que, a diferencia del SQL, un bloque de sentencias PL/SQL Se traduce en una sola llamada a la base de datos, lo que aumenta la Eficiencia.

·Es portable entre distintas máquinas y sistemas Operativos que trabajen con el sistema de bases de datos de Oracle.

Los programas creados con PL/SQL Se pueden almacenar en la base de datos como cualquier otro objeto de ésta. De Este modo se facilita a todos los usuarios autorizados el acceso a estos Programas.

Los programas se ejecutan en el Servidor, con el consiguiente ahorro de recursos en los clientes y disminución Del tráfico de red.

ESTRUCTURA DEL BLOQUE PL/SQL

Formato de un bloque PL/SQL:

            DECLARE

                        declaraciones

            BEGIN

                        órdenes

            EXCEPTION

                        gestión De errores y excepciones

            END

Consideraciones:

·Sólo la parte ejecutable (BEGIN, END) es Obligatoria.

·Los bloques pueden anidarse.

·Las órdenes, declaraciones, etc., deben terminar Con un “;”. Sólo los IF y los LOOP son excepciones a esta regla. En SQL, el “;” Supone el final de una orden y, en consecuencia, su ejecución. En los bloques PL/SQL, el “/” (run) es el finalizador de la orden, indicando el final del Bloque.

·Para escribir comentarios podemos utilizar dos Guiones “—“ cuando el comentario ocupa una sola línea o, los símbolos “/*” (para comenzar) y “*/” (para finalizar) cuando ocupa más de una línea.

·Podemos ponerle una etiqueta al bloque usando Los signos “<< etiqueta >>”. Esa etiqueta sirve para referenciar al Bloque con sentencias como el GOTO.

Las etiquetas también se pueden Usar dentro de los bloques para delimitar o marcar los distintos elementos que Hay en su interior.

DECLARACIÓN DE VARIABLES

Las declaraciones de variables Tienen la siguiente pinta:

            DECLARE

                        cumpleanos                 date;

                        contador                     number(2);

Al declarar las variables se les Puede asignar un valor:

            contador         number(2) := 5;

            v_contador     number DEFAULT 10;            (equivale a :=)

            nombre            char(11) := ‘Pedro Gómez’;

            ciudad             char(10) NOT NULL := ‘Toledo’;

sino                 boolean;      (admite tres posibles valores: sí, no, Null)

            porcen             CONSTANT number(3,2) := 0.15;

            max_val          number(8,2) := 1000 * porcen;

Para dar valores a las variables Se pueden usar cláusulas SELECT con la cláusula INTO:

            SELECT Nombre_columna INTO variable FROM tabla;

Disponemos de dos tipos de Atributos que permiten declarar las variables con los mismos tipos que otras Variables. Esos atributos son %TYPE y %ROWTYPE.

%TYPE le asigna a una variable el mismo tipo de Datos que otra variable o columna de la tabla:

            compras          number(8) := 20000;

            cantidad          compras%TYPE;

De esta forma indicamos que la Variable cantidad es del mismo tipo que compras.

También podemos asignar el mismo Tipo que el de una columna de la tabla:

            mi_variable     tabla.Columna%TYPE;

%ROWTYPE crea una variable de Tipo registro, que será una estructura que contenga las mismas columnas que la Tabla a la que se hace referencia. La variable tendrá los mismos nombres y Tipos de datos que los de la fila de la tabla:

            mi_fila            tcliente%ROWTYPE;

Podemos asignar valores de Distintas formas:

            mi_fila.Dni := ‘40404048’;

            mi_fila := fila2           (fila2 será una Variable del mismo tipo)

            SELECT * INTO mi_fila FROM tcliente;

Este tipo de variables no se Pueden usar en sentencias INSERT o UPDATE. Por lo tanto, no sería Correcto:

            INSERT INTO tcliente Valúes (mi_fila);

Cuando en un bloque se declara una variable, ésta es Local en ese bloque y global en todos los bloques incluidos en el primero. Esto Quiere decir que desde un bloque interior se puede hacer referencia a una Variable declarada en el bloque exterior.

Si en un bloque interior se Declara una variable con el mismo nombre que otra declarada en el bloque Exterior, se puede hacer referencia a la variable global anteponiendo el nombre Del bloque exterior (si tiene nombre):  etiqueta_bloque_exterior.Variable

ESTRUCTURAS DE CONTROL

CONTROL CONDICIONAL

            La Ejecución de ciertas órdenes depende del cumplimiento de una o más condiciones:

                        IF condición THEN

                                   sentencias;

END IF;

o bien

IF condición THEN

                                   sentencias;

                        ELSE

                                   sentencias;

                        END IF;

            Los IF se Pueden anidar de la siguiente forma:

                        IF condición THEN

                                   sentencias;

                        ELSE

IF condición2 THEN

sentencias;

                                    ELSE

                                               sentencias;

                        END IF;

ESTRUCTURAS REPETITIVAS

Permiten repetir una serie de órdenes un determinado número de veces. Hay tres tipos:

            LOOP

            Con salida En la parte central del bucle:

                        LOOP

                                   sentencias;

                                    EXIT WHEN condición de salida;

                                   sentencias;

                        END LOOP;

            Lo anterior Equivale a:

                        LOOP

                                   sentencias;

                                    IF Condición de salida THEN EXIT;

                                    END IF;

                                   sentencias;

                        END LOOP;

WHILE

            Bucle en el Que las sentencias se ejecutan mientras se cumpla la condición:

            WHILE condición LOOP

                        sentencias;

            END LOOP;

            FOR

FOR variable IN [REVERSE] mínimo..Máximo LOOP

                                   sentencias;

                        END LOOP;

            Con la Opción reverse la variable comienza tomando el valor máximo y va disminuyendo Hasta el valor mínimo.

            La variable Utilizada en la instrucción FOR no es necesario declararla (el propio FOR lo Hace).

            Hay otras Dos sentencias que conviene comentar:

            GOTO:
Transfiere el control, de manera incondicional, a las sentencias de una Etiqueta:

                        GOTO insertar;



                        << insertar >>

                        INSERT INTO .......


NULL


Implica “no hacer nada”. Ejemplo:

                        IF Salario < 80000 THEN

                                   sentencias;

                        ELSE

                                   null;

                        END IF;

EJEMPLOS

            Antes de Comenzar con los ejemplos, vamos a hacer dos cosas para evitar que muestre en Pantalla todas las sentencias antes de ejecutarlas (set echo off)
Y para Evitar que muestre los valores anteriores y nuevos (set ver off  o  set Verify off)
.

            Para no Tener que escribirlas al comienzo de cada sesíón, podríamos escribirlas en el Archivo LOGIN.SQL.

            Comencemos Haciendo un programa que acepte un número por el teclado y nos diga si es par o Impar (ed sql001)
:

rem sql001

clear buff;

set serveroutput on;

DECLARE

            numro Number(4):=&numero;

BEGIN

            if (numro mod 2)=0 then

dbms_output.Put_line('El Número '||numro||' es par');

else

                        dbms_output.Put_line('El Número '||numro||' es impar');

            end if;

END;

/

La orden set serveroutput on Nos permite usar la sentencia dbms_output.Put_line que saca por pantalla Los resultados (PL/SQL no nos proporciona otra forma de mostrar datos en Pantalla.

Cuando ejecutemos el fichero (@ Sql001)
Aparecerá el mensaje Procedimiento PL/SQL terminado con éxito. Para que no aparezca, podemos hacer set feedback off.

El siguiente bloque PL/SQL Escribe los números del 10 al 1 (ed sql002)
:

--sql002

set serveroutput on;

BEGIN

            for i in reverse 1..10 loop

                        dbms_output.Put_line(i);

end loop;

END;

/

Programa que nos dice el número De veces que un número puede ser dividido por 2 (ed sql010)
:

--sql010

clear buff;

set serveroutput on;

DECLARE

            numro Number(4):=&numero;

            divdo number(4):=0;

            veces number(2):=0;

BEGIN

            divdo := numro;

            while divdo mod 2 = 0 loop

veces := veces + 1;

                        divdo := divdo / 2;

            end Loop;

            dbms_output.Put_line('El Número '||numro||' es '||veces||' veces divisible por dos');

END;

/

Cambiamos el programa anterior Usando la orden ACCEPT para pedir por teclado un número mediante un mensaje (ed Sql010)
:

--sql010

clear buff;

set serveroutput on;

accept numero Prompt 'dame un múmero ...: ';

DECLARE

divdo number(4):=0;

            veces number(2):=0;

BEGIN

            divdo :=&numero;

            while divdo mod 2 = 0 loop

veces := veces + 1;

                        divdo := divdo / 2;

            end Loop;

            dbms_output.Put_line(&numero||' Es '||veces||' veces divisible por dos');

END;

/

undefine Numero

Al usar la orden ACCEPT la Variable numero queda definida (de ahí el undefine numero que Escribimos al final).

Programa que calcula el total de Clientes, la suma de las compras y la media de éstas. Vamos a usar %TYPE y la Asignación de valor a una variable con una cláusula SELECT) (ed sql020)
:

-- sql020

set serveroutput on;

DECLARE

            total_clientes number(4);

total_compras Tcliente.Compras%type;

            media_compras Tcliente.Compras%type;

BEGIN

            select count(*), Sum(compras), avg(compras)

into Total_clientes, total_compras, media_compras

                                   from Tcliente;

            dbms_output.Put_line('nº De clientes  : '||total_clientes);

            dbms_output.Put_line('total De compras: '||total_compras);

            dbms_output.Put_line('media De compras: '||media_compras);

END;

/

Antes de hacer el ejemplo Siguiente hagamos select * from tvendedor y select avg(porcen) from Tvendedor para poder observar los cambios cuando lo ejecutemos. Este Ejemplo actualiza los porcentajes de los vendedores poniéndoles a aquellos que No llegan, el valor de la media (ed sql030)
:

--sql030

BEGIN

            update tvendedor set Porcen =  (select avg(porcen) from Tvendedor)

            where porcen <

(select avg(porcen) from tvendedor);

commit;

END;

/

Recordemos que commit confirma Las modificaciones, que ya no podrán deshacerse con rollback.

Programa que aumenta en dos Décimas la comisión de los vendedores con titulación elemental si la media de Sus porcentajes es inferior a la media de los porcentajes de los que tienen Titulación media (ed sql040):

-- sql040

DECLARE

            me number;

            mm number;

BEGIN

            select avg(porcen) into me From tvendedor  where titulación = 'ELEMENTAL';

            select avg(porcen) into mm From tvendedor  where titulación = 'MEDIA';

            if me < mm then

                        update tvendedor  set porcen=porcen+0.2

                                   where Titulación = 'ELEMENTAL';

            end if;

commit;

END;

/

Programa que escribe la serie 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, … hasta un número que escribiremos (ed sql045):

 rem sql045

 clear buff;

 set serveroutput on;

accept numero prompt 'dame un número ...: ';

DECLARE

            penúltimo number(4):=-1;

            ultimo number(4):=1;

            actual number(5);

            tope number;

BEGIN

tope := &numero;

            actual := penúltimo + ultimo;

while actual < tope loop

                        dbms_output.Put_line(actual);

penúltimo := ultimo;

                        ultimo := actual;

                        actual := penúltimo + ultimo;

end loop;

END;

/

undefine numero;

TABLAS

En PL/SQL hay dos tipos de datos Compuestos: las tablas o arrays y los registros.

Las tablas tienen una columna y Una clave por la que se indexan. La columna puede contener cualquier tipo de Dato, pero el índice debe ser siempre BINARY_INTEGER.

Para declarar las tablas, Primero hay que definir un tipo tabla y, después, se declaran las tablas de ese Tipo:

            TYPE nombre IS TABLE OF

                        tipo De columna

            Índex BY BINARY_INTEGER;

Ejemplos:

    DECLARE

            TYPE Nombres IS TABLE OF

                        alumnos.Nombre%TYPE

            Índex BY BINARY_INTEGER;

            TYPE Tipotabla IS TABLE OF

                        VARCHAR2(10)

            Índex BY BINARY_INTEGER;

            TYPE Otro_tipo IS TABLE OF

                        tcliente%ROWTYPE

            Índex BY BINARY_INTEGER:

Podemos declarar variables de Los tipos definidos:

            nombre_alumnos        nombres;

            mi_tabla                      tipotabla;

Para hacer referencia a un elemento de una tabla Haremos cosas del tipo:

            nombre_alumnos(i) := ‘PEPE PÉREZ’;

Programa que almacena los 10 Primeros números pares en un vector “v” (ed sql048):

--sql048

set serveroutput on;

DECLARE

            type vector is table of Number índex by binary_integer;

            v vector;

BEGIN

            for i in 1..10 loop

                        v(i):= 2*i;

                        dbms_output.Put_line('i= '||i ||' v = '|| v(i));

end loop;

END;

/

Consideraciones con respecto a Las tablas:

·Una tabla consta de dos columnas, una para el índice Y la otra para almacenar los valores.

·Son válidas expresiones del tipo:        v(-7) :=9

·Los elementos de la tabla no se almacenan Necesariamente en memoria de forma contigua.

·Si tenemos dos tablas del mismo tipo se le puede Asignar a una de ellas el contenido de la otra.

Atributos de tabla:

ATRIBUTO

DESCRIPCIÓN

EXISTS(n)

Devuelve TRUE si existe el elemento n

IF Tabla.EXISTS(i) THEN ...

COUNT

Devuelve el número de elementos de una tabla

IF Tabla.COUNT = 100 THEN ...

FIRST

Devuelve El índice del primer elemento de la tabla.

i Binary_integer := tabla.FIRST

LAST

Devuelve el índice del último elemento de la tabla

PRIOR(n)

Devuelve el índice del elemento anterior de la tabla.  i:=tabla.PRIOR(i)

NEXT(n)

Devuelve el índice del elemento siguiente

DELETE(m,n)

Borra los elementos desde m hasta n. Si no se ponen Parámetros, borra toda la tabla. Si se pone sólo uno, borra el elemento Correspondiente.

Programa que lee la tabla de Clientes y coloca el contenido de las columnas nombre y compras en dos arrays. Luego mostrará el contenido de estos (ed sql050):

--sql050

set serveroutput on

DECLARE

            type nombres is table of Tcliente.Nombre%type

            índex by binary_integer;

            type importes is table of Tcliente.Compras%type

            índex by binary_integer;

            vnombres nombres;

            vimportes importes;

            i binary_integer:=0;

            fila tcliente%rowtype;

BEGIN

            for fila in (select nombre, Compras from tcliente) loop

                        i:=i+1;

                        vnombres(i):=fila.Nombre;

                        vimportes(i):=fila.Compras;

            end loop;

            for i in Vnombres.First..Vnombres.Last loop

                        dbms_output.Put_line('i= '||i ||' nombre = '||

                                                           vnombres(i)||' Compras = '||vimportes(i));

            end loop;

END;

/

REGISTROS

De la misma forma que con los Arrays, primero definimos los tipos y luego declaramos las variables de esos Tipos.

            TYPE Tipo_registro IS Récord (

                        campo1           tipo1 [not null][:= exprs],

                        campo2           tipo2 [not null][:= exprs],


                        campon           tipon [not null][:= exprs]);

Ahora podemos definir variables de ese tipo:

            mi_registro    tipo_registro;

Para hacer referencia a alguno De los campos se utiliza la notación punto (mi_registro.Campo3).

Si queremos asignar a la vez Valores a todos los campos de un registro, podemos asignar a un registro el Contenido de otro (si son del mismo tipo) o podemos utilizar las sentencias SELECT y FETCH.

No se puede asignar valores Utilizando listas ni se pueden utilizar en operaciones de inserción. No son Correctas:

            INSERT INTO tabla Valúes (mi_registro);

            mi_registro := (valor1, valor2,...);

Un registro se puede utilizar en La definición de otro.

Veamos un ejemplo sencillo de Utilización de registros (ed sql02):

--sql052

set serveroutput on

DECLARE

            type t_registro is Récord(

tabla      char(10),

                        fecha      date,

                        contador   number(4));

            mi_registro T_registro;

BEGIN

            mi_registro.Tabla := 'tcliente';

            mi_registro.Fecha := sysdate;

            select Count(dni) into mi_registro.Contador  from Tcliente;

            dbms_output.Put_line(mi_registro.Tabla||

                                               mi_registro.Fecha||' Nº = '||mi_registro.Contador);

END;

/

CURSORES

DEFINICIONES, SENTENCIAS DE MANEJO, ATRIBUTOS

Los cursores sirven para trabajar con consultas que Devuelven más de una fila. Esto permite realizar algunos tratamientos antes de Usar la información extraída y controlar qué fila se está procesando en cada Instante.

Un cursor se maneja como un Fichero secuencial en el que se almacenan las filas de una consulta. Para manipularlo Es necesario abrirlo, leerlo y cerrarlo.

Los cursores se definen en la Zona de declaraciones:

            CURSOR Nombre IS SELECT sentencia_select;

Por ejemplo, creamos un cursor Para los clientes de tipo ‘AA’:

            CURSOR Mi_cursor IS select * from tcliente where tipo = ‘AA’;

Consideraciones sobre cursores:

·No puede definirse con una consulta que contenga La cláusula INTO.

·Sus contenidos se obtienen en el momento de Abrirlos. No son “refrescados” hasta la siguiente apertura.

·Se identifica por su nombre. No es posible Asignar valores a un nombre de cursor o usarlo en expresiones.

Para abrir un cursor à OPEN nombre_cursor. Cuando se abre, se ejecuta la consulta asociada.

Para recorrer el cursor se Utiliza FETCH, que devuelve una fila cada vez que se ejecuta. Los valores que Lee o devuelve tienen que ser depositados en variables predefinidas

            FETCH Nombre_cursor INTO variables;

También se puede volcar la Información sobre una sola variable definida con %ROWTYPE:

            DECLARE

                        fila       tcliente%ROWTYPE;


            BEGIN

                        fetch Mi_cursor into fila;


Para cerrar el cursor à CLOSE nombre_cursor;

Se pueden declarar variables del Mismo tipo que un cursor ya definido. Por ejemplo definimos la variable mi_copia Con la estructura del cursor mi_cursor.

                        mi_copia    mi_cursor%ROWTYPE;

Los cursores tienen cuatro Atributos predefinidos que nos sirven para conocer el estado del cursor en un Determinado momento:

·%NOTFOUND. Se activa si el último FETCH  no ha recuperado ninguna fila del cursor (se Han agotado las filas de la consulta). Ejemplo: EXIT WHEN mi_cursor%NOTFOUND;

·%FOUND. Es el caso contrario, se activa si el último FETCH ha devuelto una fila. Antes de realizar ningún FETCHA su valor es Null.

·%ROWCOUNT. Devuelve el número de filas Recuperadas hasta ese momento con un FETCH. Ejemplo: if mi_cursor%ROWCOUNT = 5 then .........

·%ISOPEN. Verdadero si el cursor está abierto.

Si intentamos usar %FOUND, % NOTFOUND, %ROWCOUNT antes de la apertura o después del cierre se producirá un Error.

Programa que utiliza un cursor Para obtener el número de vendedores que tienen cada una de las titulaciones, y Cuántos tienen una comisión superior a 10. Además, nos dará el número de Registros leídos (ed sql058):

-- sql058

set serveroutput on

DECLARE

            cursor cvendedor is

select titulación, porcen from Tvendedor;

cs number:=0;

            cm number:=0;

            ce number:=0;

            po number:=0;

            x cvendedor%rowtype;

BEGIN

            open cvendedor;

            loop

                        fetch cvendedor Into x;

                        exit when Cvendedor%notfound;

                        if X.Porcen > 10 then

                                   po:=po+1;

                        end if;

                        if x.Titulación = 'SUPERIOR' then

                                   cs:=cs+1;

                        else

                                   if x.Titulación = 'MEDIA' then

cm:=cm+1;

                                               else

                                               ce:=ce+1;

end if;

                        end if;

            end loop;

            dbms_output.Put_line  ('total de registros leídos    '||cvendedor%rowcount);

            close cvendedor;

            dbms_output.Put_line('total Con titulación superior    : '||cs);

dbms_output.Put_line('total Con titulación media       : '||cm);

            dbms_output.Put_line('total Con titulación elemental   : '||ce);

            dbms_output.Put_line('total Con comisión superior a 10 : '||po);

END;

/

Si definimos un cursor Utilizando expresiones, tenemos que poner un alias a las columnas Correspondientes para poder referenciar los campos de posibles valores de tipo Cursor.

Si definimos un cursor haciendo:

            cursor Cvendedor is

                                    select titulación, Porcen + 0.5 nuevopor from tvendedor;

Si definimos una variable x Cvendedor%rowtype, podemos poner en el programa expresiones del tipo if X.Nuevopor > 10 then...

Se puede trabajar con cursores Usando los bucles for para cursores, que provocan la apertura, los fetch Y el close de una manera implícita.

El siguiente programa hace lo mismo que el anterior Y usa un bucle for:

-- sql060

set serveroutput on

DECLARE

            cursor cvendedor is

select Titulación, porcen from tvendedor;

cs number:=0;

            cm number:=0;

            ce number:=0;

            po number:=0;

            rl number:=0;

BEGIN

            for x in cvendedor loop

                        if x.Porcen > 10 then

                                   po:=po+1;

                        end if;

                        if x.Titulación = 'SUPERIOR' then

                                   cs:=cs+1;

                        else

                                   if X.Titulación = 'MEDIA' then

cm:=cm+1;

                                   else

                                               ce:=ce+1;

end if;

                        end if;

                        rl:=cvendedor%rowcount;

            end loop;

            dbms_output.Put_line('registros Leídos                            : '||rl);

dbms_output.Put_line('total Con titulación superior        : '||cs);

            dbms_output.Put_line('total Con titulación media           : '||cm);

            dbms_output.Put_line('total Con titulación elemental     : '||ce);

            dbms_output.Put_line('total Con comisión superior a 10 : '||po);

END;

/

No se podría colocar la Sentencia rl:=cvendedor%rowcount;
fuera del bucle. La razón es que fuera Del bucle for ya no existen ni el cursor ni sus atributos.

CURSORES IMPLÍCITOS

Cuando se procesa una sentencia SQL no asociada a un cursor declarado explícitamente, el sistema abre un cursor Implícito.

PL/SQL permite que referenciemos El más reciente cursor implícito como el cursor SQL. Con estos cursores no Podemos usar OPEN, FETCH ni CLOSE, pero sí podemos usar (con condiciones) los Atributos del cursor para obtener información del último comando ejecutado.

Para referenciar un atributo del Cursor implícito à SQL%NOTFOUND. Esta sentencia tiene que ser inmediata a la sentencia SELECT, INSERT, etc. Y devuelve TRUE al insertar una fila, al actualizar filas, o al Borrar filas. Devolverá  FALSE si falla La inserción, modificación o borrado de una fila. Ejemplo:

--sql065

set serveroutput on

BEGIN

            update tcliente set tipo = 'BB'

where dni = '12345';

            if sql%found then -- USAMOS Aquí EL CURSOR Implícito

dbms_output.Put_line('cambiado ');

            else

                        dbms_output.Put_line('este Cliente no existe');

            end if;

END;

/

El programa sql060 podría Haberse hecho sin definir un cursor de forma explícita usando la sentencia:

            for X in (select titulación, porcen, nom_ven from tvendedor) loop

Hay que tener en cuenta que no Se puede manejar el atributo sql%rowcount.

CURSORES CON PARÁMETROS

Definir cursores con parámetros Nos permite cualificar la consulta.

            CURSOR Nombre (parámetro1 tipo, parámetro2 tipo ...)

            IS SELECT columnas... WHERE columna = parámetro1 ..........;

Vamos a hacer un programa que Pida por teclado un código de jefe y un porcentaje. Se creará un cursor con los Vendedores que tengan ese jefe y un porcentaje de comisión superior y Obtendremos cuántos vendedores tienen cada una de las titulaciones:

-- sql091

set serveroutput on

accept p prompt 'Dame un Porcentaje...........: '

accept j prompt 'Dame un código de Superior...: '

DECLARE

            cursor cvendedor(p_por number:=&p, P_sup char:='&j') is

                                    select titulación, porcen from tvendedor

                                               where Porcen > p_por and superior = p_sup;

cs number:=0;

            cm number:=0;

            ce number:=0;

            x cvendedor%rowtype;

BEGIN

            open cvendedor;

            loop

                        fetch cvendedor Into x;

                        exit when Cvendedor%notfound;

                        if x.Titulación = 'SUPERIOR' then

                                   cs:=cs+1;

                        else

                                   if X.Titulación = 'MEDIA' then

cm:=cm+1;

                                   else

                                               ce:=ce+1;

end if;

                        end if;

            end loop;

            dbms_output.Put_line('total De registros  '||cvendedor%rowcount);

close cvendedor;

            dbms_output.Put_line('total Con titulación superior   '||cs);

            dbms_output.Put_line('total Con titulación media      '||cm);

            dbms_output.Put_line('total Con titulación elemental  '||ce);

END;

/

undefine p

undefine j

Dos cosas a tener en cuenta:

A) se ha Utilizado el atributo %rowcount para obtener el total de registros del cursor y

B) en la Declaración de los parámetros no se incluye su tamaño

El paso de parámetros se puede Hacer en la sentencia OPEN nombre_cursor(par1, par2,....)

            DECLARE

                        cursor Cvendedor(p_por number, p_sup char) is

                                   select Titulación, porcen from tvendedor

                                               where Porcen > p_por and superior = p_sup;



            BEGIN

                        open Cvendedor(&p, ‘&j’);



MODIFICACIÓN DE DATOS CON CURSORES

Si un cursor está posicionado Sobre una fila, podemos modificarla o borrarla si en la definición del cursor Lo hemos indicado.

Si el cursor se define sobre una Tabla podemos poner:

            CURSOR Nombre IS SELECT sentencia_select

            FOR UPDATE [NOWAIT];

Si se define sobre más tablas, Las tablas que pueden ser actualizadas se pueden especificar nombrando alguna De sus columnas (no es necesario que estas columnas intervengan en la cláusula SELECT.

            CURSOR Nombre IS SELECT sentencia_select

            FOR UPDATE OF col1, col2, ... [NOWAIT];

Al definir un cursor con FOR UPDATE, se produce un bloqueo sobre la tabla o tablas susceptibles de Modificación. Si la tabla ya está bloqueada por otro usuario cuando se crea el Cursor, el sistema queda a la espera de que quede liberada. Si, además de la Sentencia FOR UPDATE, añadimos NOWAIT, el sistema no crea el cursor y devuelve Un error.

Update

Nos permite modificar la tabla o Vista sobre la que se ha formado el cursor:

            UPDATE Nombre_tabla SET col1 = exp1, col2 = exp2 ...

            WHERE CURRENT OF nombre_cursor;

Con esta sentencia se actualiza La fila a la que apunta el cursor “nombre_cursor”.

Delete

Se utiliza para borrar la fila Sobre la que apunta el cursor:

            DELETE FROM nombre_tabla

WHERE CURRENT OF nombre_cursor;

En el ejemplo se utiliza un Cursor para actualizar los porcentajes de comisión de los vendedores, haciendo Que aquellos que tengan una comisión inferior a 10 se les ponga este valor (antes de ejecutar este programa conviene comprobar cuál es el contenido de TVENDEDOR: select * from tvendedor):

-- sql110

set serveroutput on

DECLARE

            cursor cvendedor is

                        select nom_ven, Porcen from tvendedor

                                   where Porcen < 10

                                               for Update;

            x cvendedor%rowtype;

BEGIN

            open cvendedor;

            loop

                        fetch Cvendedor into x;

                        exit When cvendedor%notfound;

                                    update tvendedor set porcen = 10

                                               where Current of cvendedor;

                        dbms_output.Put_line('actualizando '||cvendedor%rowcount

                                                           ||' '||x.Nom_ven||x.Porcen);

                        end loop;

            close cvendedor;

            commit;

END;

/

MANEJO DE EXCEPCIONES

Utilizando las excepciones se Pueden gestionar los errores y los mensajes (tanto las propias de SQL*PLUS como Los de los usuarios).

Al detectar una excepción, PL/SQL pasa el control a la parte EXCEPTION. En ella se ejecutan las sentencias Que se hayan previsto para cada caso.

Cuando se produce una excepción, El bloque en el que se ha producido acaba.

            EXCEPTION

                        WHEN Excepción1 THEN

                                               órdenes;

                        WHEN Excepción2 THEN

                                               órdenes;


                        WHEN OTHERS THEN

órdenes;

Si tenemos bloques anidados y se Produce una excepción en el bloque interno, el control del programa pasa a su Sección de excepciones. Si no tiene esta sección o no trata este error, éste Pasa al bloque externo para ser tratado allí.

Tipos de excepciones:

·
Excepciones que tienen relación con la Herramienta.

qInternas Ya definidas.

qNo Definidas.

·Excepciones definidas por el usuario.

Excepciones internas ya Definidas

Estas excepciones activan unos Indicadores cuya descripción es la siguiente:

Excepción

Descripción

CURSOR_ALREADY_OPEN

Se activa al abrir un cursor que Ya está abierto.

DUP_VAL_ON_INDEX

Intento de almacenar un valor que ya existe en índice único.

INVALID_CURSOR

Operación incorrecta sobre un cursor.

INVALID_NUMBER

Fallo de conversión de un carácter a un número.

LOGON_DENIED

Nombre de usuario/contraseña no válido.

NO_DATA_FOUND

Una orden SELECT devuelve cero filas.

PROGRAM_ERROR

Se activa si PL/SQL tiene un problema de ejecución.

NOT_LOGGED_ON

Se activa si se intenta algún tipo de llamada a la base de Datos sin haber iniciado la sesíón.

STORAGE_ERROR

Fallo de memoria.

TIMEOUT_ON_RESOURCE

Se acaba el tiempo intentando coger un recurso.

TOO_MANY_ROWS

Cuando se espera que una sentencia SELECT devuelva una Fila y devuelve más.

TRANSACTION_BACKED_OUT

Cuando se anula la parte remota de una transacción.

VALUE_ERROR

Cuando hay un error de aritmética, conversión, Truncamiento o restricción.

ZERO_DIVIDE

Error al intentar dividir por cero.

En el siguiente ejemplo vamos a Intentar encontrar al cliente con dni 101010104, previendo una excepción para El caso de que no lo encuentre:

--sql120

DECLARE

            fila tcliente%rowtype;

BEGIN

            select * into fila from Tcliente

                        where Dni = '101010104';

            dbms_output.Put_line(fila.Nombre);

EXCEPTION

            when no_data_found then

                        dbms_output.Put_line('no Lo he encontrado');

END;

/

Excepciones internas no Definidas

Las excepciones estándar del Sistema tienen asociado un código (NO_DATA_FOUND tiene asociado el error ORA-01403, TOO_MANY_ROWS el ORA-01427, etc.). Sólo se les ha dado nombre a Algunos errores del sistema (a los más comunes). El resto pueden ser tratados Definiendo una variable en la que se deposite el error enviado por el sistema.

Por ejemplo, si el error Devuelto por el sistema es el –1547 cuando no tiene sitio para crear una nueva Extensión, para asociar este error a una variable (ésta será de tipo EXCEPTION)
Usamos la orden PRAGMA EXCEPTION_INIT.

DECLARE

            error_sin_sitio EXCEPTION;

            pragma Exception_init (error_sin_sitio, -1547);

BEGIN

            sentencias

EXCEPTION

            when Error_sin_sito then

                        sentencia ...

END;

Excepciones definidas por El usuario

Puede interesarnos generar Nuestras propias situaciones de excepción y darles un tratamiento específico. Para hacer esto, definimos una variable de tipo EXCEPTION, generamos el Código en el bloque de excepciones y, dentro del bloque BEGIN, arrancamos la Excepción con la sentencia RAISE nombre_excepción.

DECLARE

            mi_error EXCEPTION;

BEGIN

            sentencias

            if condición then

                        RAISE Mi_error;

            end If;

EXCEPTION

            when Mi_error then

                        sentencias ...

END;

En el siguiente ejemplo vamos a Considerar una excepción el hecho de que algún vendedor tenga en la columna SUPERIOR un valor null. Trataremos esa excepción dando un mensaje:

-- sql130

set serveroutput on

DECLARE

            cursor Cvendedor is

                        select Nom_ven, superior from tvendedor;

            x Cvendedor%rowtype;

            error_sup Exception;

BEGIN

            open Cvendedor;

            loop

                        fetch cvendedor into x;

                        exit when cvendedor%notfound;

                        if x.Superior is null then

                                    raise error_sup;

                        else

                                    dbms_output.Put_line(x.Nom_ven);

                        end if;

            end loop;

            close cvendedor;

EXCEPTION

            when error_sup then

                        dbms_output.Put_line('no Tiene superior '||x.Nom_ven);

END;

/

En la primera fila se encuentra Que el vendedor tiene valor null en SUPERIOR, se arranca la excepción y el Programa se acaba después de ejecutar las sentencia previstas.

Otras consideraciones sobre las excepciones

·Cuando se dispara una excepción dentro de un Bloque FOR LOOP, el cursor se cierra implícitamente antes de que el manejador De la excepción sea invocado. Por lo tanto, los valores de sus atributos no Están disponibles en el manejador de la excepción.

·Al ejecutar las rutinas de manejo de Excepciones, la ejecución del bloque acaba y, no es posible volver a un punto Determinado dentro de él. Para solucionar esto, podríamos crear un bloque Interno que contuviera el manejo de excepciones. Vamos a ver este tipo de Solución modificando el último programa de la manera siguiente:

-- sql133

set serveroutput on

DECLARE

            cursor Cvendedor is

select nom_ven, superior from Tvendedor;

            x cvendedor%rowtype;

            error_sup exception;

BEGIN

            open cvendedor;

            loop

                                    fetch Cvendedor into x;

                                    exit when cvendedor%notfound;

                                    begin

                                               if X.Superior is null then

                                                           raise error_sup;

                                   else

                                               dbms_output.Put_line(x.Nom_ven);

                                               end If;

                        exception

                                   when Error_sup then

                                           dbms_output.Put_line (x.Nom_ven||' ..*no tiene Superior*.. ');

                        end;

            end loop;

            close cvendedor;

END;

/

Cuando se produce una excepción, El bloque (interno) que la contiene finaliza, pero no el bloque exterior. Por Lo tanto, el programa continúa.

·Si deseamos redisparar una excepción hacia el Bloque contenedor para que éste la trate de nuevo, basta con incluir la Sentencia RAISE en el manejador local de la excepción.

Podemos usar dos funciones para Gestionar errores:

Función

Descripción

SQLCODE

Devuelve el código asociado con la excepción activada en último lugar. Devuelve siempre un número negativo excepto con NO_DATA_FOUND, Que devuelve 100. Para excepciones de usuario devuelve 1, a no ser que estén Redefinidas por PRAGMA EXCEPTION_INIT.

SQLERRM

Devuelve el mensaje asociado con el actual SQLCODE. Dado Que se trata de una cadena de 512 caracteres, el programador normalmente Corta el texto a mostrar. Si se proporciona un número entero, devuelve el Mensaje asociado a ese valor entero (a:=sqlerrm(1403))

Estas funciones tienen que ser Asignadas a variables. Ejemplo:

--sql140

set serveroutput on

DECLARE

e_num number;

            e_men Varchar2(100);

            fila tcliente%rowtype;

BEGIN

            select * into fila from Tcliente

                        where dni = '101010104';

            dbms_output.Put_line(fila.Nombre);

EXCEPTION

            when others then

                        e_num := sqlcode;

                        e_men := substr(sqlerrm,1,100);

                        dbms_output.Put_line ('error nº '||e_num||' mensaje: '||e_men);

END;

/

El procedimiento RAISE_APPLICATION_ERROR permite introducir mensajes de error definidos por el Usuario desde procedimiento almacenados. Para llamar a este procedimiento:

            raise_application_error (nº de error, mensaje [,{TRUE | FALSE]);

El número de error tiene que Estar entre –20000 y –20999, ambos incluidos. Mensaje es el texto que acompaña Al error. TRUE o FALSE determina si el error se sitúa sobre la pila de errores O si sustituye a todos los demás errores existentes (la opción por defecto es FALSE). Ejemplo:

-- sql145

set serveroutput on

DECLARE

            cursor cvendedor is

                        select nom_ven, Superior from tvendedor;

            x cvendedor%rowtype;

BEGIN

            open cvendedor;

            loop

                        fetch cvendedor Into x;

                        exit when Cvendedor%notfound;

                        if x.Superior Is null then

                                   raise_application_error(-20000,'falta Superior');

                        else

                                   dbms_output.Put_line(x.Nom_ven);

                        end if;

            end loop;

            close cvendedor;

END;

/

En el siguiente programa Forzamos un mensaje para cualquier situación:

-- sql150

set serveroutput on

DECLARE

            cursor cvendedor is

                        select nom_ven, Superior from tvendedor;

            x cvendedor%rowtype;

            err_num number;

            err_msg Varchar2(80);

BEGIN

            open cvendedor;

            loop

                        fetch cvendedor into x;

                        exit when cvendedor%notfound;

                        begin

                                    if x.Superior is null then

raise_application_error(-20000,'no tiene Superior');

else

                                               raise_application_error(-20001,'SÍ Tiene superior');

                                    end if;

                        exception

                                    when OTHERS then

                                                           err_num := SQLCODE;

                                                           err_msg := SUBSTR(SQLERRM,1,80);

                                               dbms_output.Put_line(x.Nom_ven||err_num||' '||err_msg);

                                    end;

            end loop;

            close cvendedor;

END;

/

EJERCICIOS:


1. Mostrar los nombres de los empleados con los Trienios de antigüedad en la empresa

2. Mostrar qué empleados tienen un sueldo superior al De su jefe


3. Pedir por teclado la denominación de un puesto (por ejemplo, ANALISTA) e Incrementar las comisiones de los empleados que estén a su cargo (todos los Empleados que dependan de cada ANALISTA) en una cantidad igual a la comisión Que recibe el superior, dividida por el número de sus empleados.

SUBPROGRAMAS

            Pueden Llevar parámetros y ser llamados desde otros programas.

            Hay dos Tipos: procedimientos y funciones. Ambos tienen secciones declarativa, Ejecutable y de excepciones. Se diferencian en que una llamada a un Procedimiento es una orden PL/SQL en si misma, en tanto que una llamada a una Función se realiza como parte de una expresión.

PROCEDIMIENTOS

            Tienen una Estructura similar a un bloque PL/SQL. Se pueden utilizar con cualquier Herramienta que use PL/SQL y en cualquier bloque, procedimiento o función. Deben ser declarados en la sección DECLARE después del resto de variables.

            PROCEDURE Nombre(parámetros) IS

                        declaraciones;

               BEGIN

                        sentencias;

               EXCEPTION

                        excepciones;

               END nombre;

            No se puede Especificar el tamaño de los parámetros, en caso de hacerlo se generará un Error. Si el procedimiento no tiene parámetros, no tenemos que usar los Paréntesis.

            El Siguiente bloque pide un número y llama a un procedimiento que escribe la Palabra “hola” tantas veces como indique el número:

-- sql200

set Serveroutput on

DECLARE

            procedure Veces (i number) is

            begin

                        for X in 1..I loop

                                   dbms_output.Put_line('hola');

                        end Loop;

            end Veces;

BEGIN

            veces(&b);

END;

/

Procedimiento que calcula el Factorial de un número:

--sql210

set Serveroutput on

DECLARE

            procedure Factorial (i number) is

                        fact Int:=1;

            begin

                        for X in 1..I loop

                                   fact:=fact*x;

                        end Loop;

                        dbms_output.Put_line(fact);

            end Factorial;

BEGIN

            factorial(&b);

END;

/

El siguiente procedimiento Modificará el tipo del cliente que especifiquemos haciendo que sea AA. En el Caso de que ya lo sea, nos dará un aviso:

--sql220

set Serveroutput on

DECLARE

            procedure Cambiar(cod_cli char) is

tipo_cli Tcliente.Tipo%type;

begin

                        select Tipo into tipo_cli

                                   from tcliente where dni=cod_cli;

if tipo_cli='AA' then

                               Dbms_output.Put_line('ya es de tipo AA');

else

                               update tcliente Set tipo='AA' where dni=cod_cli;

                        end If;

            end Cambiar;

BEGIN

            cambiar('&a');

END;

/

Cuando no se encuentra el Cliente, se produce un error y se abandona el programa. Vamos a mejorar el Programa tratando la excepción cuando el cliente no está en la tabla. Además, Vamos a hacer que nos pida por teclado el tipo que le queremos poner al Cliente:

--sql225

set Serveroutput on

DECLARE

            procedure Cambiar(cod_cli char, nue_tip char) is

tipo_cli tcliente.Tipo%type;

begin

                        select Tipo into tipo_cli

                                   from tcliente where dni=cod_cli;

                        if Tipo_cli=nue_tip then

dbms_output.Put_line('ya es de tipo '||nue_tip);

else

                                   update tcliente set tipo=nue_tip

                                               where dni=cod_cli;

                        end If;

            exception

                        when no_data_found then

dbms_output.Put_line('este Cliente no existe ');

            end cambiar;

BEGIN

            cambiar('&cliente','&nuevo_tipo');

END;

/

El siguiente programa hace lo Mismo que el anterior usando el cursor implícito que se genera al ejecutar la Sentencia UPDATE:

--sql230

set Serveroutput on

DECLARE

            procedure Cambiar(cod_cli char, nue_tip char) is

            begin

                        update Tcliente set tipo=nue_tip

                                   where dni=cod_cli and tipo!=nue_tip;

                        if Sql%found then  -- USAMOS EL CURSOR IMPLÍCITO

                                   dbms_output.Put_line('cambiado');

else

                                   dbms_output.Put_line('este Cliente no existe o ya es de ese tipo');

                        end If;

            end Cambiar;

BEGIN

            cambiar('&cliente','&nuevo_tipo');

END;

/

PROCEDIMIENTOS Y PARÁMETROS

Ya hemos visto la utilización De parámetros en procedimiento. Por defecto, los parámetros son de entrada (pasan de la llamada al procedimiento). Es posible tener parámetros de salida y También parámetros de entrada y salida.

            PROCEDURE

                        nombre(par1 IN tipo, Par2 OUT tipo2, par3 IN OUT tipo3, ...) IS

                               declaraciones;

            BEGIN

                        sentencias;

            EXCEPTION

                        excepciones;

            END nombre;

·Un parámetro de tipo IN permite pasar valores a Un subprograma cuando se produce la llamada. Hay que tener en cuenta que, Dentro del subprograma, no podemos modificarlo.

·Un parámetro de tipo OUT permite devolver Valores al bloque o al subprograma que le ha llamado. La única operación que se Puede hacer sobre él es asignarle una variable (no se le puede asignar una Constante ni tampoco una expresión).

·Un parámetro de tipo IN OUT puede ser Inicializado. También puede ser asignado a cualquier otra variable y ser Empleado en cualquier expresión.

Vamos a ver unos ejemplos Sencillos sobre la utilización de los parámetros:

--sql235

set Serveroutput on

DECLARE

            x Number:=33;

            procedure P1(i in number, x out number) is

                        a Int:=10;

           begin

                        dbms_output.Put_line('entro en procedimiento '||'i= '||i||' a= '||a);

                        x:=a;

            end P1;

BEGIN

            dbms_output.Put_line('antes De llamar x= '||x);

p1(2,x);

            dbms_output.Put_line('salgo del Procedimiento x= '||x);

END;

/

--sql240

set Serveroutput on

DECLARE

            x Number:=33;

            procedure P2(x in out number) is

                        a Int:=10;

            begin

                        dbms_output.Put_line('entro En procedimiento '||'x= '||x||' a= '||a);

                        x:=a+x;

            end P2;

BEGIN

            dbms_output.Put_line('antes De llamar x= '||x);

p2(x);

            dbms_output.Put_line('salgo del Procedimiento x= '||x);

END;

/

El siguiente programa calcula El valor de las combinaciones de m elementos tomados de n en n. Este valor se Obtiene haciendo = m!/(n!*(m-n)!)

--sql242

set serveroutput on

DECLARE

            m Number:=&m;

            n Number:=&n;

            m_fac Number;

            n_fac Number;

            m_n_fac Number;

            procedure Factorial(entrada in number, salida out number) is

                        f Int:=1;

            begin

                        for X in 1..Entrada loop

                                   f:=f*x;

                        end Loop;

                        salida:=f;

            end Factorial;

BEGIN

            factorial(m,m_fac);

            factorial(n,n_fac);

            factorial(m-n,m_n_fac);

            dbms_output.Put_line('resultado= '||m_fac/(n_fac*m_n_fac));

END;

/

FUNCIONES

Son subprogramas que Devuelven un valor. Para ello deben utilizar la orden RETURN, que finaliza la Función y retorna al programa principal un valor.

            FUNCTION Nombre(parámetros) RETURN tipo IS

                        declaraciones;

            BEGIN

                        sentencias;

                        return Variable;

            EXCEPTION

                        excepciones;

            END nombre;

            El tipo de Dato que tiene que devolver es “tipo”. No se debe especificar su tamaño. Veamos un ejemplo sencillo:

--sql250

set Serveroutput on

DECLARE

            x Number:=33;

            resultado Number;

            function Suma_30(x number) return number is

                        a Number:=30;

            begin

                        dbms_output.Put_line('entro En la función '||'x='||x||' a= '||a);

                        a:=a+x;

                        return A;

            end Suma_30;

BEGIN

            dbms_output.Put_line('antes De llamar x= '||x);

resultado:=suma_30(x);

            dbms_output.Put_line('salgo de la Función resultado= '||resultado);

END;

/

Cuando declaramos los Subprogramas, podemos asignar valores por defecto a algunos de sus parámetros. Conviene que éstos se sitúen al final de la lista.

            Vamos a Hacer un programa que pida dos números y nos indique si el resto de dividirlos Es cero. Si no se introduce ningún valor para el segundo se asumirá que vale 10:

--sql253

set Serveroutput on

DECLARE

            dividendo Number(3):=&numero1;

            divisor Number(2):=to_number('&numero2');

            function Esdiv(dndo dividendo%type, dsor divisor%type default 10) return boolean is

            begin

                        if (dndo mod dsor)=0 then

                                   return True;

                        else

                                   return False;

                        end If;

            end esdiv;

BEGIN

            if Divisor is null then

                        if Esdiv(dividendo) then

                                   dbms_output.Put_line(dividendo||' Es divisible por 10');

                        else

                                   dbms_output.Put_line(dividendo||' NO es divisible por 10');

                        end If;

            else

                        if Esdiv(dividendo,divisor) then

                                   dbms_output.Put_line(dividendo||' Y '||divisor||' son divisibles');

                        else

                                   dbms_output.Put_line(dividendo||' Y '||divisor||' NO son divisibles');

                        end If;

            end If;

END;

/

FUNCIONES RECURSIVAS

            La Recursión consiste en un subprograma que se invoca a sí mismo. En una función Recursiva deberá haber dos “return”, uno para acabar la recursión finalizando La ejecución del subprograma y otro que corresponderá a la llamada recursiva al Mismo.

            Puede haber Una solución iterativa para un problema resuelto de forma recursiva. Hay que Decir que un proceso recursivo es más fácil de optimizar y resulta más elegante Y corto. Sin embargo, consume más recursos que un proceso iterativo.

            Vamos a Hacer un programa que calcule el factorial de un número de forma recursiva:

--sql255

set Serveroutput on

DECLARE

            f Number:=&f;

            resultado Number;

            function Factorial(x positive) return number is

            begin

                        if X=0 then

                                   return 1;

                        else

                                    return X*factorial(x-1);

                        end If;

            end Factorial;

BEGIN

            resultado:=factorial(f);

            dbms_output.Put_line('Factorial De '||f||' = '||resultado);

END;

/

            Programa Que escribe el elemento enésimo de la sucesión de Fibonacci:

--sql260

set Serveroutput on

DECLARE

            n Number:=&n;

            resultado Number;

            function Fibo(x positive) return number is

            begin

                        if x=1 or x=2 then

return 1;

            else

                                    return fibo(x-1) + fibo(x-2);

                        end If;

            end fibo;

BEGIN

            if N>0 then

resultado:=fibo(n);

end if;

            dbms_output.Put_line('Fibonacci De '||n||' = '||resultado);

END;

/

PROCEDIMIENTOS Y FUNCIONES ALMACENADOS

            Se trata de Procedimientos que se almacenan dentro del servidor. Se pueden invocar desde Muchos entornos y aplicaciones. Cuando están almacenados en la base de datos, Podemos invocarlos desde el prompt de sql usando “execute”:

SQL>


EXECUTE procedimiento(parámetros);

            Para Llamarlos desde otro bloque o procedimiento basta con nombrarlos.

            Cuando se Trata de funciones, lo único que hay que tener en cuenta es que el valor que Devuelven hay que asignárselo a una variable:

                        resultado:=función(var);

            Para Ejecutar una función desde el prompt haremos algo similar a lo siguiente:

                        SQL> accept valor;

SQL> var k number;

SQL> Execute :k:=función(&valor);

                        SQL> print k;

Para crear un procedimiento o función almacenados usamos la orde

Entradas relacionadas: