You are on page 1of 19

TEMA 17: FUNDAMENTOS DEL LENGUAJE PL/SQL

1. Introduccin En la unidad anterior hemos estudiado las caractersticas generales de PL/SQL y su utilizacin desde una perspectiva global y un tanto intuitiva. En esta unidad nos preocuparemos a ver los principales elementos del lenguaje: 1. Cules son los tipos de datos 2. Variables 3. Operadores y Expresiones 4. Reglas sintcticas 5. Estructuras de control 6. Procedimientos y Funciones 2. Tipos de datos bsicos PL/SQL dispone de los mismos tipos de datos de SQL adems de los suyos propios. CHAR(L) Almacena cadenas de caracteres de longitud fila. Opcionalmente podemos configurar la longitud mxima entre parntesis. Las posiciones no usadas se rellenan con blancos. Ejemplos: Nombre CHAR(25); Letra_nif CHAR; Situacin CHAR(); esta mal Almacena caracteres de longitud variable cuyo limite mximo se debe especificar en numero de bytes (L). Ejemplos: Nombre VARCHAR2(25); Letra_nif VARCHAR2; esta mal Igual que el varchar2. Ejemplos: Observaciones LONG(5000); La precisin (P) y la escala (E) son opcionales, pero si se especifica la escala hay que especificar la precisin. Ejemplos: Importe NUMBER(5,2); Si al asignar un valor se excede la escala, se producir un truncamiento, si se excede la precisin se producir un error. PL/SQL usa de subtipos de tipo NUMBER, que son: DECIMAL, INTEGER, NUMERIC, REAL, SMALLINT.

VARCHAR2(L)

LONG(L) NUMBER(P,E) P: Precisin: N de dgitos E: N de decimales

BINARY_INTEGER

PLS_INTEGER

BOOLEAN DATE RAWID RAW(L) LONG RAW Se pueden hacer conversiones implcitas: TO_CHAR TO_NUMBER TO_DATE

Es un tipo numrico entero que se almacena en memoria en formato binario para facilitar los clculos, se usa en contadores. Sus subtipos son: NATURAL, POSITIVE. Es similar al BINARY_INTEGER pero con 2 ventajas: ms rpido y si hubiera un desbordamiento se producira un error y se levantara la excepcin correspondiente. Almacena tres valores: TRUE, FALSE Y NULL Almacena fechas, su formato por defecto es: dd/mm/aa

PL/SQL dispone tambin de tipos ms complejos: a) Registros b) Referencias c) Lob para objetos de gran tamao d) Permiten definir objetos. 3. Identificadores Se usan para nombrar los objetos que se intervienen en un programa, variables, constantes, cursores, excepciones, procedimientos, funciones, etiquetas. En PL/SQL pueden tener los identificadores hasta 30 que empiezan por una letra, que pueden ir seguidas por letras, nmeros y otros caracteres especiales. No identifica entre maysculas y minsculas. 4.Variables Toda variable en PL/SQL debe declararse en la seccin correspondiente antes de su uso. Sintaxis: <nombre_variable> <tipo> [NOT NULL][ := { DEFAULT | VALOR }] DECLARE Importe number(8,2); Contador number(2,0):=0; Nombre char(20) NOT NULL := Miguel;

Para cada variable se debe especificar el tipo, NO se puede declarar como en otros lenguajes una lista de variables del mismo tipo y a continuacin su tipo. La opcin NOT NULL fuerza a que la variable tenga siempre ese valor, si se usa deber inicializarse con la opcin DEFAULT o con := para una asignacin. Sino se inicializan las variables en PL/SQL se garantiza que su valor es NULL 4.1. Uso de atributos %TYPE y %ROWTYPE En lugar de indicar explcitamente el tipo y la longitud de una variable, existe la posibilidad de utilizar los atributos %TYPE y %ROWTYPE para declarar las variables que sean del mismo tipo que otros objetos ya definidos. %TYPE declara una variable del mismo tipo que otra, o que una columna de una tabla. Ejemplo: DECLARE Total importe%TYPE; Total recibe el mismo tipo que la variable importe. DECLARE Nombre clientes.clt_nom%TYPE; La variable nombre recibe el tipo de la columna de la tabla clientes. Al declarar una variable del mismo tipo que otro objeto usando los atributos %TYPE y %ROWTYPE, se hereda el tipo y la longitud, pero no son posibles los atributos NOT NULL, y los valores por defecto que tuviera definido el objeto original. 4.2. Constantes La sintaxis en las constantes seria: <nombre_cte> CONSTANT <tipo>:=<valor>; En el caso de las constantes deber asignarse siempre un valor en la declaracin. Ejemplo: DECLARE PCT_IVA CONSTANT REAL := 1.16;

4.3 mbito y visibilidad de las variables El mbito de una variable es el bloque en el que se declara y los bloques hijos de dicho bloque. La variable ser local para el bloque en que ha sido declarado y global para los bloques hijos de ste. No obstante las variables declaradas en los bloques hijos no son accesibles desde el bloque padre. DECLARE V1 NUMBER; BEGIN ...... V1 := 1; DECLARE V2 NUMBER; BEGIN V2 := 2; ....... V1 := V2; END; V2 := V1; Error porque la variable V2 es slo local a su procedimiento END; En este ejemplo podemos observar que V1 es accesible para los 2 bloques, es local al bloque padre y global al bloque hijo, mientras que V2 es accesible para el bloque hijo. Las variables se crean al comienzo del bloque y dejan de existir una finalizada la ejecucin del bloque en el que han sido declaradas. Se pueden usar etiquetas y cualificadores para deshacer ambigedades, en el caso de que un identificador local coincida con una global, sino se indica + se hace referencia al local. <<padre>> etiqueta DECLARE V CHAR; BEGIN ....... DECLARE V CHAR;

BEGIN V := padre.V; ........ END; END; 5.Operadores El operador de asignacin se usa con := Los operadores lgicos son AND, OR y NOT. El operador de concatenacin seria || ; Comparaciones = , !=, <=, >=, IS NULL, BETWEEN, LIKE, IN Suboperadores aritmeticos +, -, *, /, ** 5.1. Orden de precedencia de los operadores El orden de precedencia o prioridad de los operadores determina el orden de evaluacin de los operandos de una expresin. Prioridad 1 2 3 4 5 6 Evaluacin por cortocircuito PL/SQL da por concluida la evaluacin de una expresin lgica cuando el resultado ha quedado determinado por la evaluacin de una parte de ella. Esto ocurre en los AND y los OR. Operador ** y NOT * y / +, - y || =, !=, >=, <=, IS NULL, BETWEEN, LIKE y IN AND OR Operacin Exponenciacin y Negacin Multiplicacin y Divisin Mas, Menos y concatenacin

6. Funciones En PL/SQL se pueden usar las distintas funciones SQL que se han estudiado. Se deben tener en cuenta 2 aspectos: a) La funcin no modifica el valor de las variables o expresiones que se pasen como argumento sino que devuelve un valor a partir de dicho argumento.

b) Si a una funcin se le pasa un valor uno en la llamada normalmente devolver un valor nulo. Ejemplo: Hacer un procedimiento en PL/SQL que devuelva la fecha BEGIN DBMS_OUTPUT.PUT_LINE(La fecha es ||TO_CHAR(SYSDATE,'DAY DD MONTH YYYY')); END; / Que dara: La fecha es MIRCOLES 23 ENERO 2002 PL/SQL procedure successfully completed. 7. Estructuras de control Ejemplos: Existe una opcin dentro del FOR que es el REVERSE, utilizando el WHILE y utilizando el FOR. Este ejemplo toma la cadena hola y la visualiza al revs. FOR: DECLARE CADENA VARCHAR2(10); BEGIN FOR i IN REVERSE 1..LENGTH('HOLA') LOOP CADENA:=CADENA||SUBSTR('HOLA',i,1); END LOOP; DBMS_OUTPUT.PUT_LINE (CADENA); END; / WHILE: DECLARE CADENA VARCHAR2(10); i number; BEGIN i:=length('hola'); WHILE i > 0 LOOP CADENA:=CADENA||SUBSTR('HOLA',i,1);

i:=i-1; END LOOP; DBMS_OUTPUT.PUT_LINE (CADENA); END; / Ahora lo haremos pasndole una palabra: CREATE OR REPLACE PROCEDURE VER_CONTRARIO(A VARCHAR2) IS CADENA VARCHAR2(10); i NUMBER; BEGIN FOR i IN REVERSE 1..LENGTH(A) LOOP CADENA:=CADENA||SUBSTR(A,i,1); END LOOP; DBMS_OUTPUT.PUT_LINE (CADENA); END; / Le pasamos una palabra: EXEC VER_CONTRARIO('HOLA'); Que dara: ALOH PL/SQL procedure successfully completed. 8. Consideraciones para el manejo de bucles Los bucles se pueden etiquetar para obtener una mayor legibilidad. Ejemplo: <<mibucle>> LOOP <sentencias>;

END LOOP mibucle; 9. Subprogramas: Procedimientos y Funciones Los subprogramas son bloques PL/SQL que tienen un nombre, pueden recibir parmetros y en el caso de las funciones pueden devolver un valor. Se guardan en la base de datos y se pueden ejecutar invocndolos desde otros subprogramas o herramientas. En todo subprograma podemos distinguir: a) La cabecera o especificacin del subprograma, que contendr: 1) el nombre del programa 2) la definicin del parmetro con sus tipos 3) el tipo de valor de retorno en el caso de las funciones b) El cuerpo del subprograma, es un bloque PL/SQL que incluye declaraciones (opcional), instrucciones y manejos de excepciones (opcional) 9.1 Procedimientos Sintaxis: CREATE OR REPLACE PRODECURE <nombre_procedimiento>[(<lista_parmetros>)] IS <declaraciones>; BEGIN <instrucciones>; [EXCEPTION <excepciones>;] END [<nombre_procedimiento>]; En la lista de parmetros se encuentra la declaracin de cada uno de los parmetros separados por comas ,. El formato genrico de cada declaracin ser: <nombre_variable> [IN | OUT | IN OUT] <tipo_dato> [{ := | DEFAULT }<valor>] Al indicar los parmetros debemos especificar el tipo pero no el tamao, en caso de que no tenga parmetros no usaremos parntesis ( ). Las declaraciones se pueden hacer

despus de IS que equivale al DECLARE en este caso se debe indicar la longitud de las variables locales. Para crear un procedimiento lo haremos usando CREATE [OR REPLACE], si el procedimiento no exista lo crea y sino lo sustituye. Ejemplo: hacer un procedimiento llamado cambiar_poblacin que cambiara la poblacin, y los parmetros sern el numero del cliente y la nueva poblacin. La salida ser el numero del cliente la antigua poblacin y la nueva poblacin. CREATE OR REPLACE PROCEDURE CAMBIAR_POB(NUM CLIENTES.CLT_NUM %TYPE,NUEVA_POB CLIENTES.CLT_POB%TYPE) IS POB CLIENTES.CLT_POB%TYPE; BEGIN SELECT CLT_POB INTO POB FROM CLIENTES WHERE CLT_NUM = NUM; UPDATE CLIENTES SET CLT_POB = NUEVA_POB WHERE CLT_NUM = NUM; DBMS_OUTPUT.PUT_LINE ('EL NUMERO DE CLIENTE ES '||NUM); DBMS_OUTPUT.PUT_LINE ('SU ANTIGUA POBLACION ES '||POB); DBMS_OUTPUT.PUT_LINE ('SU NUEVA POBLACION ES '||NUEVA_POB); END; / Lo compilamos ejecutamos y le pasamos un argumento: EXEC CAMBIAR_POB(1,'ROTA'); Que dara: EL NUMERO DE CLIENTE ES 1 SU ANTIGUA POBLACION ES MADRID SU NUEVA POBLACION ES ROTA PL/SQL procedure successfully completed. Para invocar al procedimiento lo que hay que hacer es compilarlo y despus ejecutarlo. 9.2. Funciones Las funciones tienen una estructura y funcionalidad similar a los procedimientos, pero a diferencia de ellos stos devuelven un valor. Sintaxis:

CREATE OR REPLACE FUNCTION <nombre_funcin> [(lista_parmetros>)] RETURN <tipo_valor_devuelto> IS <declaraciones>; BEGIN <instrucciones>; RETURN <expresin>; EXCEPTION <expresiones>; END [<nombre_funcin>]; Los parmetros tienen la misma sintaxis en las funciones que los procedimientos, y es valido todo lo indicado para ello. La clusula RETURN de la cabecera retorna el tipo de valor que devuelve la funcin, en el cuerpo del programa se har efectivo este retorno, utilizando dicha clusula RETURN junto con la expresin cuyo valor se devolver. Esta clusula devuelve el control al programa que llamo a la funcin, asignando el valor devuelto por la funcin al identificador de la misma en el punto de la llamada. De manera anloga a los procedimientos para crear o modificar una funcin, CREATE OR REPLACE FUNCTION. Ejemplo: funcin que le pasamos el numero y nos devuelve el apellido del cliente. Debemos hacer 2 partes, una es la funcin y despus un bloque en el que llamamos a la funcin mediante DBMS_OUTPUT.PUT_LINE (nombre_funcin (lista_parmetros)); CREATE OR REPLACE FUNCTION BUSCAR_APELLIDO(NUM CLIENTES.CLT_NUM%TYPE) RETURN VARCHAR2 IS APELL CLIENTES.CLT_APELL%TYPE; BEGIN SELECT CLT_APELL INTO APELL FROM CLIENTES WHERE CLT_NUM = NUM;

RETURN APELL; END; / El bloque seria: BEGIN DBMS_OUTPUT.PUT_LINE (BUSCAR_APELLIDO(1)); END; / Que dara: Input truncated to 1 characters BORRAS PL/SQL procedure successfully completed. 9.3 Parmetros Los subprogramas usan parmetros para pasar y recibir informacin. Hay dos tipos: a) Parmetros actuales o reales: son las variables o expresiones indicadas en la llamada a un subprograma. Las que pasamos como parmetro. b) Parmetros formales: son las variables declaradas en la especificacin del subprograma. Las que se encuentran dentro del subprocedimiento o funcin. Si es necesario PL/SQL har la conversin automtica de tipos, sin embargo los tipos de los parmetros actuales y los correspondientes parmetros formales deben ser compatibles. Podemos hacer el paso de parmetros usando las notaciones posicional, nominal y mixta. Notacin posicional: el compilador asocia los parmetros actuales a los formales basndose en la posicin. Notacin nominal: el smbolo => despus de parmetro actual y antes del parmetro formal indica al compilador la correspondencia. Notacin mixta: consiste un usar ambas notaciones con la restriccin de que la notacin posicional debe preceder a la nominal. Ejemplo: cambiar_poblacin(numero, poblacin) posicional cambiar_poblacin(numero => num_cliente, poblacin => nueva_poblacin); nominal

cambiar_poblacin(poblacin => nueva_poblacin, numero => num_cliente); nominal cambiar_poblacin(numero, poblacin=> nueva_poblacin); mixta

Valores por defecto en el paso de parmetros Los parmetros en modo IN(entrada) estos parmetros se pueden inicializar con valores por omisin, es decir, indicando al subprograma que en el caso que no se pase el parmetro correspondiente asuma un valor por defecto. Tipos de parmetros Tipo IN Caractersticas y usos Permite pasar valores a un subprograma, el parmetro acta como una constante, es decir, no se le puede asignar ningn valor. El parmetro actual puede ser una variable, una constante, un literal o una expresin. Permite devolver valores al bloque que llamo al subprograma. Dentro del subprograma, el parmetro acta como una variable no inicializada, no puede intervenir en ninguna expresin salvo para tomar un valor. El parmetro actual debe ser una variable. Permite pasar un valor inicial y devolver un valor actualizado. Dentro del subprograma acta como una variable inicializada, puede intervenir en otras expresiones y puede tomar nuevos valores. El parmetro actual debe ser una variable.

OUT

IN/OUT

Ejemplo: recibe una cantidad en pesetas y devuelve la cantidad equivalente en la moneda cuyo cambio se especifica como segundo parmetro. 1. Realizar primero un procedimiento que se llame cambiar_divisas pasndole como parmetro pesetas y factor y devuelve un valor. 2. Desde otro bloque llamado convertir que llama a cambiar_divisas. 1. CREATE OR REPLACE PROCEDURE CAMBIAR_DIVISAS(pesetas IN number,factor IN number,valor OUT number) IS BEGIN

VALOR := PESETAS / FACTOR; END; / 2. CREATE OR REPLACE PROCEDURE CONVIERTE(PESETAS NUMBER,FACTOR NUMBER) IS V_VALOR NUMBER(8,3); BEGIN CAMBIAR_DIVISAS(PESETAS,FACTOR,v_VALOR); DBMS_OUTPUT.PUT_LINE ('El valor es '||V_VALOR); END; / La llamamos pasndole un argumento: exec convierte(100,166.386); Que dara: El valor es ,601 PL/SQL procedure successfully completed. Para borrar un subprograma al igual que otros objetos se usa la clusula DROP, seguido del tipo de subprograma. 9.4 Subprogramas almacenados Los subprogramas procedimientos o funciones se pueden compilar independientemente y almacenar en la base de datos de Oracle. Cuando creamos procedimientos o funciones desde SQLPLUS usando los comandos CREATE PROCEDURE o CREATE FUNCTION, Oracle automticamente compila el cdigo fuente, genera el cdigo objeto llamado P-cdigo y los guarda en el diccionario de datos. De esta forma quedan disponibles para su utilizacin. Los programas almacenados tienen 2 estados: VALID o INVALID. Si alguna de los objetos referenciados por el programa ha sido borrado o alterado desde la ultima compilacin del programa, quedara en situacin de no disponible y se compilara de nuevo automticamente en la prxima llamada. Al compilar, Oracle determina si hay que compilar algn otro programa referido por el actual, y se puede producir una cascada de compilaciones.

Estos estados se pueden comprobar en la vista USER_OBJECTS que tiene diversos campos, pero solo nos interesan object_name, object_type, status. Tambin se puede encontrar el cdigo en la vista USER_SOURCE Para volver a compilar un subprograma almacenado en la base de datos se usa el subcomando ALTER indicando PROCEDURE o FUNCTION segn el tipo de subprograma. Sintaxis: ALTER {PROCEDURE | FUNCTION } nombre_subprograma COMPILE; 9.5 Subprogramas locales 9.6 Recursividad PL/SQL implementa al igual que muchos lenguajes de programacin, la posibilidad de escribir subprogramas recursivos. Ejemplo: hacer el factorial de un numero. CREATE OR REPLACE FUNCTION FACTORIAL(N INTEGER) RETURN INTEGER IS BEGIN IF N = 0 THEN RETURN 1; ELSE RETURN N * FACTORIAL(N-1); END IF; END; / El bloque seria: BEGIN DBMS_OUTPUT.PUT_LINE(FACTORIAL(3)); END; /

Que dara: 6 PL/SQL procedure successfully completed. 10. Ejercicios 1. Indicar los errores que aparecen en las siguientes instrucciones y la forma de corregirlo. DECLARE Num1 number(8,2):=0; Num2 number(8,2) NOT NULL DEFAULT 0; Num3 number(8,2) NOT NULL; Cantidad integer(3); INTEGER no lleva tamao Precio, descuento number(6); precio no tendra tipo Num4, num1%rowtype; habria que quitar la coma para que Num4 sea del tipo de la fila de num1 Descuento CONSTANT integer; falta el valor BEGIN ..... END; / 2. Escribir un procedimiento que reciba 2 nmeros y visualice sus sumas. CREATE OR REPLACE PROCEDURE SUMAR(A INTEGER,B INTEGER) IS BEGIN DBMS_OUTPUT.PUT_LINE('LA SUMA DE ' ||A|| ' Y ' ||B|| ' ES IGUAL A '|| (A+B)); END; /

3. Codificar un procedimiento que reciba una cadena y la visualice al revs. CREATE OR REPLACE PROCEDURE VER_ALREVES(A VARCHAR2) IS CONTRARIO VARCHAR2(100); i INTEGER; BEGIN FOR i IN REVERSE 1..LENGTH(A) LOOP CONTRARIO := CONTRARIO||SUBSTR(A,i,1); END LOOP; DBMS_OUTPUT.PUT_LINE('LA CADENA ' ||A|| ' AL REVES ES ' || CONTRARIO); END; / 4. Escribir una funcin que reciba una fecha y devuelva el ao, el nmero correspondiente a esa fecha. CREATE OR REPLACE FUNCTION FECHA(A DATE) RETURN NUMBER IS VALOR INTEGER; BEGIN VALOR:= TO_NUMBER(TO_CHAR(A,'YYYYY')); RETURN VALOR; END; / 5. Escribir un bloque PL/SQL que haga uso del bloque anterior. SQL> SET SERVEROUTPUT ON SQL> BEGIN 2 DBMS_OUTPUT.PUT_LINE(FECHA('23/02/1990')); 3 END; 4 / 19900 PL/SQL procedure successfully completed.

6. Dado el siguiente procedimiento: PROCEDURE crear_depart( V_num_dept depart.dept_num%type, V_dnombre depart.dnombre%type DEFAULT PROVISIONAL, V_loc depart.loc%type DEFAULT PROVISIONAL) IS BEGIN INSERT INTO depart VALUES v_num,v_dnombre,v_loc) END crear_depart; / Indicar cuales de las siguientes llamadas son correctas y los incorrectos, en este ultimo caso escribir la llamada correcta usando la notacin posicional ( en los casos que se pueda). Crear_depart; hay que pasarle por lo menos un parametro Crear_depart(50); Crear_depart(COMPRAS);necesita el numero Crear_depart(50,COMPRAS); Crear_depart(COMPRAS,50);esta mal el orden Crear_depart(COMPRAS,VALENCIA); falta el numero Crear_depart(50,COMPRAS,VALENCIA); Crear_depart(VALENCIA,50,COMPRAS); mal el orden Crear_depart(VALENCIA,COMPRAS); falta el numero Crear_depart(VALENCIA,50); esta mal el orden 7. Desarrollar una funcin que devuelva el nmero de aos completos que hay entre dos fechas que se pasen como argumento. CREATE OR REPLACE FUNCTION anos_dir(fecha1 date, fecha2 date) RETURN NUMBER IS V_anos_dir NUMBER(6); BEGIN V_anos_dif:= ABS(TRUNC(MONTHS_BETWEEN(fecha2,fecha1)/12)); RETURN v_anos_dif; END anos_dif; 8. Escribir una funcin que haciendo uso de la funcin anterior devuelva los trienios(3 aos completos) que hay entre 2 fechas. CREATE OR REPLACE FUNCTION trienios(fecha1 date,fecha2 date) RETURN NUMBER AS V_trienos NUMBER(6);

BEGIN V_trienos:=TRUN(anos_dif(fecha1/fecha2)/3); RETURN v_trienios; END; 9. Codificar un procedimiento que reciba una lista de hasta 5 nmeros y visualice su suma. CREATE OR REPLACE PROCEDURE sumar_5numeros( Num1 NUMBER DEFAULT 0, Num2 NUMBER DEFAULT 0, Num3 NUMBER DEFAULT 0, Num4 NUMBER DEFAULT 0, Num5 NUMBER DEFAULT 0, AS BEGIN DBMS_OUTPUT.PUT_LINE(num1+num2+num3+num4+num5); END sumar_5numeros; 10. Escribir una funcin que devuelva slo caracteres alfabticos sustituyendo cualquier otro carcter por blancos a partir de una cadena que se pasara en la llamada. CREATE OR REPLACE FUNCTION sust_por_blancos(cad VARCHAR2) RETURN VARCHAR2 AS Nueva_cad VARCHAR2(30); Car CHARACTER; BEGIN FOR i IN 1..LENGTH(cad) LOOP Car:=SUBSTR(cad,i,1); IF(ASCII(car) NOT BETWEEN 65 AND 90) AND (ASCII(car) NOT BETWEEN 97 AND 122) THEN Car :=; END IF; Nueva_cad:=nueva_cad || car; END LOOP; RETURN nueva_cad; END sust_por_blancos; 11. Implementar un procedimiento que reciba un importe y visualice el desglose del cambio en unidades monetarias. 1,5,25,100,200,500,1000,2000,5000 al orden inverso en el que aparecen aqu enumeradas. 12. Codificar un procedimiento que permita borrar un empleado cuyo numero se pasara en la llamada.

13. Escribir un procedimiento que modifique la localidad de un procedimiento que recibir el nmero del departamento y la localidad nueva. 14. Visualizar todas los procedimientos y funciones en la base de datos y su situacin.

You might also like