30/11/2010 PL SQL -Oracle Miguel Ángel Manso ETSI en Topografía, Geodesia y Cartografía - UPM Índice • ¿Qué es PL/SQL? • ¿Qué permite? • Generalidades: – fundamentos, – delimitadores, – literales, – tipos de datos • PL/SQL en Oracle 1 30/11/2010 Introducción. ¿Qué es PL SQL? • SQL es un lenguaje de consulta para los sistemas de bases de datos relaciónales, si bien no posee la potencia de los lenguajes de programación • PL/SQL amplia SQL con los elementos característicos de los lenguajes de programación, variables, sentencias de control de flujo, bucles ... • Unifica la capacidad de consulta del SQL y la versatilidad de los lenguajes de programación tradicionales. PL/SQL es el lenguaje de programación que proporcionan las bases de datos como Oracle, PostGreSQL, etc. para extender el SQL estándar con otro tipo de instrucciones ¿Qué permite PL SQL? • Desarrollar unidades de programa para las bases de datos como: – Procedimientos almacenados – Funciones – Triggers – Scripts 2 30/11/2010 Fundamentos • No es sensible a las mayúsculas/minúsculas • Las UNIDADES LEXICAS son: – DELIMITADORES – IDENTIFICADORES – LITERALES – COMENTARIOS – EXPRESIONES Delimitadores e identificadores • DELIMITADOR: Es un símbolo simple o compuesto que tiene una función especial en PL/SQL. Estos pueden ser: – Operadores Aritméticos – Operadores Lógicos – Operadores Relacionales • IDENTIFICADOR: Son empleados para nombrar objetos de programas en PL/SQL así como a unidades dentro del mismo, estas unidades y objetos incluyen: – – – – – – Constantes Cursores Variables Subprogramas Excepciones Paquetes 3 30/11/2010 Literales y comentarios • LITERAL: Es un valor de tipo numérico, carácter, cadena o lógico no representado por un identificador (es un valor explícito) • COMENTARIO: Es una aclaración que el programador incluye en el código. Son soportados 2 estilos de comentarios, el de línea simple y de multi-línea, para lo cual son empleados ciertos caracteres especiales como son: -- Línea simple /* Conjunto de Líneas */ Tipos de datos • Cada constante y variable esta asociado a un tipo de dato que define el formato de almacenamiento, las restricciones y el rango de valores permitidos • PL/SQL proporciona una variedad predefinida de tipos de datos . Casi todos los tipos de datos manejados por PL/SQL son similares a los soportados por SQL del SGBD 4 30/11/2010 PL/SQL ORACLE Contenido • • • • • • • • • • • • • • Operadores Estructuras de control Bloques Cursores Excepciones Operaciones con cursores Procedimientos Funciones Triggers Creación de paquetes Uso de Registros y Tablas con PL/SQL Varrays SQL dinámico Funciones disponibles 5 30/11/2010 Operadores • Asignación (=) • Operadores aritméticos := (dos puntos + igual) + (suma) - (resta) * (multiplicación) / (división) ** (exponente) • Operadores de relación o de comparación = (igual a) <> (distinto de) < (menor que) > (mayor que) >= (mayor o igual a) <= (menor o igual a) • Operadores lógicos AND (y lógico) NOT (negación) OR (o lógico) • Operador de concatenación || Estructuras de control • • Control de flujo IF (expresión) THEN -- Instrucciones ELSIF (expresión) THEN -- Instrucciones ELSE -- Instrucciones END IF; Sentencia GOTO DECLARE flag NUMBER; BEGIN flag :=1 ; IF (flag = 1) THEN GOTO paso2; END IF; <<paso1>> dbms_output.put_line('Ejecución de paso 1'); <<paso2>> dbms_output.put_line('Ejecución de paso 2'); END; 6 30/11/2010 Estructuras de control • LOOP LOOP -- Instrucciones IF (expresión) THEN -- Instrucciones EXIT; END IF; END LOOP; • WHILE WHILE (expresión) LOOP -- Instrucciones END LOOP; • FOR FOR contador IN [REVERSE] inicio..final LOOP -- Instrucciones END LOOP; Bloques anónimo DECLARE /* declaraciones */ variable NUMBER; BEGIN /* ejecución */ SELECT… EXCEPTION /* excepciones */ WHEN OTHERS THEN dbms_output.put_line('Se ha producido un error'); END; 7 30/11/2010 Bloque no anónimo (procedimiento) CREATE PROCEDURE procedimiento_simple IS DECLARE BEGIN EXCEPTION END; Ejemplo de procedimiento CREATE OR REPLACE PROCEDURE SYSTEM.CREA_ALUM (DNI IN VARCHAR2) AS sql_str VARCHAR2(1000); BEGIN sql_str := ('CREATE USER A'||DNI||' IDENTIFIED BY A'||DNI); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('GRANT Alum_BDE TO A'||DNI); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('GRANT CREATE TABLE TO A'||DNI); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('GRANT CREATE ANY INDEX TO A'||DNI); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('GRANT CREATE SEQUENCE TO A'||DNI); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('ALTER USER A'||DNI||' QUOTA 100M ON USERS'); EXECUTE IMMEDIATE sql_str; COMMIT; sql_str := ('CREATE SYNONYM A'||DNI||'.CRUCE FOR SYSTEM.CRUCE'); EXECUTE IMMEDIATE sql_str; COMMIT; END CREA_ALUM; 8 30/11/2010 Cursores • Es: el conjunto de registros resultado de una instrucción SQL. También son fragmentos de memoria reservados para procesar los resultados de una consulta • Tipos: – Implícitos: consulta genera un único registro (SELECT INTO) – Explícitos: consulta genera varios (pensado programación) Excepciones de los cursores implícitos • NO_DATA_FOUND: Se produce cuando una sentencia SELECT intenta recuperar datos pero ninguna fila satisface sus condiciones. Es decir, cuando "no hay datos“ • TOO_MANY_ROWS: Dado que cada cursor implícito sólo es capaz de recuperar una fila , esta excepción detecta la existencia de más de una fila 9 30/11/2010 Cursores • Simples: declare cursor nombre is SELECT ……[FOR UPDATE]; • Con parámetros: declare cursor nombre (par1 IN tipo1) is SELECT ….; La idea es que el cursor es como una función devolverá resultados dependiendo de los parámetros distintos registros Ejemplo de cursores CURSOR datos_tramo IS SELECT id_vial, id_tramo FROM tramo; CURSOR datos_vial IS SELECT id_vial, ine_mun_pr, dgc_via FROM vial WHERE (dgc_via <> 0 AND dgc_via IS NOT NULL) OR ((UPPER (tip_via)) NOT LIKE '%CTRA%'); CURSOR datos_ccpp (geo municipio.geom%TYPE) IS SELECT id_ccpp, geom FROM ccpp WHERE ( (sdo_geom.relate (geo, geom, ‘mask=CONTAINS', 0.5) = ‘TRUE') OR (sdo_geom.relate (geo, geom, ‘mask=COVERS’, 0.5) = ‘TRUE‘) ); 10 30/11/2010 Operaciones con cursores • Declarar el cursor (revisado) • Abrir el cursor con la instrucción OPEN • Leer los datos del cursor con la instrucción FETCH, FOR • Cerrar el cursor y liberar los recursos con la instrucción CLOSE Abrir, leer datos y cerrar un cursor • Abrir: – OPEN nombre_cursor; – OPEN nombre_cursor(valor1, valor2, ..., valorN); • Leer datos: – FETCH nombre_cursor INTO lista_variables – FETCH nombre_cursor INTO registro_PL/SQL; • Cerrar cursor: – CLOSE nombre_cursor; 11 30/11/2010 Ejemplos apertura y lectura DECLARE CURSOR cpaises IS SELECT CO_PAIS, DESCRIPCION, CONTINENTE FROM PAISES; co_pais VARCHAR2(3); descripcion VARCHAR2(50); continente VARCHAR2(25); BEGIN OPEN cpaises; FETCH cpaises INTO co_pais,descripcion,continente; …. CLOSE cpaises; END; DECLARE CURSOR cpaises (p_continente VARCHAR2) IS SELECT CO_PAIS, DESCRIPCION, CONTINENTE FROM PAISES WHERE CONTINENTE = p_continente; registro cpaises%ROWTYPE; BEGIN OPEN cpaises('EUROPA'); FETCH cpaises INTO registro; ……. CLOSE cpaises; END; Más ejemplos (bucles-cursores) DECLARE CURSOR cpaises IS SELECT COD_PAIS, DESC, CONTINENTE FROM PAISES; cod_pais VARCHAR2(3); desc VARCHAR2(50); continente VARCHAR2(25); BEGIN OPEN cpaises; LOOP FETCH cpaises INTO cod_pais, desc, continente; EXIT WHEN cpaises%NOTFOUND; END LOOP; CLOSE cpaises; END; 12 30/11/2010 Otro ejemplo con control While OPEN nombre_cursor; FETCH nombre_cursor INTO lista_variables; WHILE nombre_cursor%FOUND LOOP FETCH nombre_cursor INTO lista_variables; END LOOP; CLOSE nombre_cursor; Otro ejemplo con FOR Geometría de un municipio area_cp := 0; FOR var_datos2 IN datos_ccpp(var_datos1.geom) LOOP area_cp := area_cp + sdo_geom.sdo_area (var_datos2.geom, 0.5, 'unit=HECTARE'); END LOOP; 13 30/11/2010 Excepciones Predefinidas Definidas por usuario DECLARE DECLARE VALOR_NEGATIVO EXCEPTION; valor NUMBER; BEGIN valor := -1; IF valor < 0 THEN RAISE VALOR_NEGATIVO; END IF; EXCEPTION WHEN VALOR_NEGATIVO THEN END; BEGIN EXCEPTION WHEN NO_DATA_FOUND THEN WHEN ZERO_DIVIDE THEN WHEN OTHERS THEN END; Procedimientos almacenados CREATE [OR REPLACE] PROCEDURE <procedure_name> [(<param1> [IN|OUT|IN OUT] <type>, <param2> [IN|OUT|IN OUT] <type>, ...)] IS -- Declaración de variables locales BEGIN -- Sentencias [EXCEPTION] -- Sentencias control de excepción END [<procedure_name>]; 14 30/11/2010 Ejemplo procedimiento CREATE OR REPLACE PROCEDURE Actualiza_Saldo(cuenta NUMBER, nuevo_saldo NUMBER DEFAULT 10 ) IS BEGIN UPDATE SALDOS_CUENTAS SET SALDO = nuevo_saldo, FX_ACTUALIZACION = SYSDATE WHERE CO_CUENTA = cuenta; END Actualiza_Saldo; Uso: BEGIN Actualiza_Saldo(200501,2500); COMMIT; END; Otro ejemplo de procedimiento CREATE OR REPLACE PROCEDURE quinta_comple (nombre IN VARCHAR2) AS CURSOR datos IS SELECT * FROM toponimia WHERE id_topo IS NULL OR ine_mun IS NULL OR texto IS NULL OR tipo IS NULL OR fuente IS NULL OR geom IS NULL; nombre_exp VARCHAR2 (50); BEGIN nombre_exp := nombre; FOR var_datos IN datos LOOP INSERT INTO errores.errores VALUES (error.NEXTVAL, 24, '2', var_datos.id_topo, 'toponimia', nombre_exp, NULL); COMMIT; END LOOP; END quinta_comple; 15 30/11/2010 Funciones CREATE [OR REPLACE] FUNCTION <fn_name>[(<param1> IN <type>, <param2> IN <type>, ...)] RETURN <return_type> IS result <return_type>; BEGIN return(result); [EXCEPTION] -- Sentencias control de excepción END [<fn_name>]; Ejemplo de función CREATE OR REPLACE FUNCTION fn_Obtener_Precio(precio_producto VARCHAR2) RETURN NUMBER IS result NUMBER; BEGIN SELECT PRECIO INTO result FROM PRECIOS_PRODUCTOS WHERE CO_PRODUCTO = precio_producto; return(result); EXCEPTION WHEN NO_DATA_FOUND THEN return 0; END ; Ejemplo de Utilización: DECLARE Valor NUMBER; BEGIN Valor := fn_Obtener_Precio('000100'); END; 16 30/11/2010 Otro ejemplo de función CREATE FUNCTION celsius_to_fahrenheit (degre e NUMBER) RETURN NUMBER IS buffer NUMBER; BEGIN buffer := (degree * 9/5) + 32; RETURN buffer; END celsius_to_fahrenheit; Función no almacenada, ejemplo: DECLARE CURSOR myAllLecturer IS SELECT first_name, last_name FROM lecturer; v_FormattedName VARCHAR2(50); FUNCTION FormatName(p_FirstName IN VARCHAR2, p_LastName IN VARCHAR2) RETURN VA RCHAR2 IS BEGIN RETURN p_FirstName || ' ' || p_LastName; END FormatName; BEGIN FOR v_StudentRecord IN myAllLecturer LOOP v_FormattedName := FormatName(v_StudentRecord.first_name, v_StudentRecord.last_name); DBMS_OUTPUT.PUT_LINE(v_FormattedName); END LOOP; END; / 17 30/11/2010 Declaración de Trigger • Un trigger es un bloque PL/SQL asociado a una tabla, que se ejecuta como consecuencia de una determinada instrucción SQL sobre dicha tabla • Crear Trigger: CREATE [OR REPLACE] TRIGGER <nombre_trigger> {BEFORE|AFTER} {DELETE|INSERT|UPDATE [OF col1, col2, ..., colN] [OR {DELETE|INSERT|UPDATE [OF col1, col2, ..., colN]...]} ON <nombre_tabla> [FOR EACH ROW [WHEN (<condición>)]] DECLARE -- variables locales BEGIN -- Sentencias [EXCEPTION] -- Sentencias control de excepción END <nombre_trigger>; Ejemplo de Trigger CREATE OR REPLACE TRIGGER TR_PRODUCTOS_01 AFTER INSERT ON PRODUCTOS FOR EACH ROW DECLARE BEGIN INSERT INTO PRECIOS_PRODUCTOS (CO_PRODUCTO,PRECIO,FX_ACTUALIZACION) VALUES (:NEW.CO_PRODUCTO,100,SYSDATE); END ; 18 30/11/2010 Creación de paquetes PLSQL • Un paquete es una estructura que agrupa objetos de PL/SQL compilados(procedimientos, funciones, variables, tipos ...) en la base de datos • Creación de paquetes: CREATE [OR REPLACE] PACKAGE <pkgName> IS -- Declaraciones de tipos y registros públicas {[TYPE <TypeName> IS <Datatype>;]} -- Declaraciones de variables y constantes públicas -- También podemos declarar cursores {[<ConstantName> CONSTANT <Datatype> := <valor>;]} {[<VariableName> <Datatype>;]} -- Declaraciones de procedimientos y funciones públicas {[FUNCTION <FunctionName>(<Parameter> <Datatype>,...) RETURN <Datatype>;]} {[PROCEDURE <ProcedureName>(<Parameter> <Datatype>, ...);]} END <pkgName>; Registros • Un registro es una estructura de datos en PL/SQL, almacenados en campos, cada uno de los cuales tiene su propio nombre y tipo y que se tratan como una sola unidad lógica • Declaración: TYPE <nombre> IS RECORD ( campo <tipo_datos> [NULL | NOT NULL] [,<tipo_datos>...] ); • Ejemplo: TYPE PAIS IS RECORD ( CO_PAIS NUMBER , DESCRIPCION VARCHAR2(50), CONTINENTE VARCHAR2(20) ); 19 30/11/2010 Tablas (equivalente a matrices) • Permiten almacenar varios datos del mismo tipo • Se declaran como un tipo: TYPE <nombre_tipo_tabla> IS TABLE OF <tipo_datos> [NOT NULL] INDEX BY BINARY_INTEGER ; • Ejemplo: TYPE PAISES IS TABLE OF NUMBER INDEX BY BINARY_INTEGER ; Tabla_PAISES PAISES; Más sobre tablas de registros • Se pueden declarar tablas de tipo registro • Se dispone en todo caso de métodos y propiedades para tratar las tablas: – LAST, FIRST – EXIST(i), COUNT, PRIOR(n),NEXT(n), TRIM, TRIM(n),DELETE, DELETE(n),DELETE(n,m) • Ejemplo: IF courses.EXISTS(i) THEN courses(i) := new_course; END IF; 20 30/11/2010 VARRAYS • Equivalentes a las tablas pero los índices comienzan en 1 • Declaración: TYPE <nombre_tipo> IS VARRAY (<tamaño_maximo>) OF <tipo_elementos>; • Ejemplo: TYPE t_cadena IS VARRAY(5) OF VARCHAR2(50); v_lista t_cadena := t_cadena('Aitor', 'Alicia', 'Pedro','',''); SQL dinámico • PL/SQL ofrece la posibilidad de ejecutar sentencias SQL a partir de cadenas de caracteres mediante EXECUTE IMMEDIATE Ejemplo: DECLARE ret NUMBER; FUNCTION fn_execute (nn VARCHAR2, cod NUMBER) RETURN NUMBER IS sql_str VARCHAR2(1000); BEGIN sql_str := 'UPDATE DATOS SET NOMBRE = :nn WHERE CODIGO = :cod; EXECUTE IMMEDIATE sql_str USING nn, cod; RETURN SQL%ROWCOUNT; END fn_execute ; BEGIN ret := fn_execute('Devjoker',1); END; 21 30/11/2010 Funciones integradas en PL/SQL SYSDATE DECODE if-elseif-else DECODE (co_pais, 'ESP', 'ESPAÑA', 'MEX', 'MEXICO', 'PAIS '|| co_pais) TO_DATE TO_DATE('01/12/2006‘,'DD/MM/YYYY') TO_CHAR TO_CHAR(SYSDATE, 'DD/MM/YYYYY') TO_NUMBER TRUNC LENGTH LENGTH('HOLA MUNDO') INSTR INSTR('AQUI ES DONDE SE BUSCA', 'BUSCA', 1, 1 ) REPLACE REPLACE ('HOLA MUNDO','HOLA', 'VAYA') SUBSTR SUBSTR('HOLA MUNDO', 6, 5) UPPER LOWER ROWIDETOCHAR ROWIDTOCHAR(ROWID) RPAD LPAD LPAD('Hola Mundo', 50, '.') RTRIM RTRIM (' Hola Mundo ') LTRIM LTRIM (' Hola Mundo') TRIM TRIM (' Hola Mundo ') MOD MOD(20,15) 22