Estructura general PL/SQL es un lenguaje estructurado. Su unidad básica es el bloque. Un bloque PL/SQL tiene 3 partes: zona de declaraciones, zona ejecutable y zona de tratamiento de excepciones. La sintaxis de un bloque es la siguiente: [ DECLARE -- declaraciones ] -- sentencias [ EXCEPTION -- tratamiento de excepciones ] Mediante bloques pueden construirse procedimiento y funciones. Es posible el anidamiento de bloques. Fundamentos Comentarios Los comentarios de una sola línea comienzan con "--", los de varias líneas tienen la misma sintaxis que en C (empiezan con "/*" y terminan con "*/"). Tipos de datos Los tipos de datos de PL/SQL se muestran en la siguiente tabla: Tipos de datos de PL/SQL Tipos de datos escalares Tipos de datos compuestos BINARY_INTEGER CHAR RECORD TABLE DEC DECIMAL DOUBLE PRECISION FLOAT INT CHARACTER LONG RAW ROWID DATE NUMERIC BOOLEAN... Funciones de conversión Las funciones de conversión explícitas pueden verse en la siguiente tabla: CHAR DATE NUMBER RAW ROWID CHAR TO_DATE TO_NUMBER HEXTORAW CHARTOROWID DATE TO_CHAR NUMBER TO_CHAR TO_DATE RAW ROWID RAWTOHEX ROWIDTOCHAR 1
Conversiones implícitas La conversion entre los tipos indicados en la siguiente tabla es automática siempre que el tipo origen tenga el formato adecuado: BINARY_ INTEGER BINARY_ INTEGER CHAR DATE LONG NUMBER RAW ROWID VARCHAR 2 SI SI SI SI CHAR SI SI SI SI SI SI SI DATE SI SI SI LONG SI SI SI NUMBER SI SI SI SI RAW SI SI SI ROWID SI SI VARCHAR2 SI SI SI SI SI SI SI Declaraciones de variables La sintaxis de la declaración de variables es: nombre_variable [CONSTANT] TIPO [:= valor]; Se puede definir el tipo de una variable en base al de otra con: nombre_varible otro_nombre_variable%type; Otra opción es definir una variable de tipo registro en base a las columnas de una tabla: nombre_variable tabla%rowtype; Ambito de las variables El ámbito de las variables es el mismo que en Pascal. Asignaciones La sintaxis de la asignación es la siguiente: nombre_variables := operación; La operación puede ser simplemente un valor. Están definidos los dos valores booleanos: TRUE y FALSE. También pueden asignarse valores a través de los comandos SELECT y FETCH de forma similar a sql embebido. Precedencia de operadores Operador Operación **, NOT potencia, negación lógica +, - identidad, negación *, / multiplicación, división +, -, suma, resta, concatenación =,!=, <, >, <=, >=, IS NULL, LIKE, BETWEEN, IN AND OR comparaciones conjunción inclusión 2
Manipulación del valor nulo Para evitar errores al manipular valores nulos deben tenerse en cuenta las siguientes reglas: Cualquier comparación entre dos nulos devuelve el valor nulo. Aplicar el operador NOT a un valor nulo devuelve el valor nulo. En sentencias condicionales de control, si la condición se evalúa como NULL su secuencia de sentencias asociadas no se ejecutan. Uso de tablas y registros Las tablas PL/SQL tienen una funcionalidad similar a los arrays en C. Antes de poder utilizarlas, debe declararse un tipo tabla: TYPE nom_tipo_tabla IS TABLE OF tipo_dato INDEX BY BINARY_INTEGER; Después se declara una variable de este tipo: nombre_variable nom_tipo_tabla; Y a partir de este momento se puede hacer referencia al elemento n-ésimo de la tabla mediante la expresión: nombre_variable(n). Los registros PL/SQL (RECORD) tienen una funcionalidad similar a las estructuras en C. Antes de poder utilizarlos, debe declararse un tipo registro: TYPE nom_tipo_registro IS RECORD ( nom_campo_1 tipo_campo_1 [NOT NULL], nom_campo_2 tipo_campo_2 [NOT NULL],... ); Después se declara una variable de este tipo: nombre_variable nom_tipo_registro; Y a partir de este momento se puede hacer referencia a cualquier campo del registro mediante la expresión: nombre_variable.nom_campo. Mediante tablas y registros PL/SQL se facilitan las operaciones de inserción y selección en las tablas de la base de datos. Estructuras de control A continuación se muestra la sintaxis de las estructuras de control de PL/SQL. IF-THEN IF condicion THEN END IF; IF-THEN-ELSE IF condicion THEN secuencia_1_de_sentencias; ELSE secuencia_2_de_sentencias; END IF; 3
IF-THEN-ELSIF IF condicion_1 THEN secuencia_1_de_sentencias; ELSIF condicion_2 secuencia_2_de_sentencias; ELSE secuencia_3_de_sentencias; END IF; LOOP LOOP END LOOP; Dentro de los bucles se pueden usar las dos estructuras de control siguientes: EXIT; Sale incondicionalmente de un bucle. EXIT WHEN condición; Sale de un bucle cuando se cumpla la condición indicada. WHILE-LOOP WHILE condición LOOP END LOOP; FOR-LOOP FOR contador IN [REVERSE] valor_inicial..valor_final LOOP END LOOP; Interacción con ORACLE Uso de cursores La sintaxis de la declaración de un cursor es la siguiente: DECLARE CURSOR nom_cursor IS SELECT campos FROM tabla WHERE condición;... Al igual que en sql embebido, antes de usar un cursor hay que abirlo con OPEN y después de usarlo debe cerrarse con CLOSE. Para recoger los valores de la consulta se utiliza: FETCH nom_cursor INTO nom_variable; Los cursores poseen 4 atributos que permiten el acceso del usuario a información interesante en el caso de consultas que devuelvan más de una fila: nom_cursor%notfound TRUE cuando no quedan más filas como resultado de la consulta. nom_cursor%found TRUE cuando quedan más filas como resultado de la consulta. nom_cursor%rowcount número de filas recogidas (con FETCH) de la consulta. 4
nom_cursor%isopen TRUE si nom_cursor está abierto. Transacciones La confirmación y anulación de transacciones, así como el establecimiento de puntos seguros es similar a sql embebido: SAVEPOINT punto_seguro; COMMIT WORK; ROLLBACK [TO punto_seguro]; Disparadores Los disparadores se usan entre otras cosas para: Auditar las modificaciones de datos. Disponer de una traza de eventos de forma transparente. Reforzar reglas de integridad complejas. Calcular valores de columnas automáticamente. Implementar autorizaciones de seguridad complejas. Mantener réplicas de tablas. La sintaxis de un disparador es la siguiente: CREATE TRIGGER nombre_disparador antes_después lista_de_acciones OF campo ON tabla [FOR EACH ROW] WHEN ( condición ) donde: antes_después puede ser BEFORE o AFTER, y lista_de_acciones es cualquier combinación con OR de: SELECT, INSERT, UPDATE, etc. Gestión de errores Cuando se produce un error, se genera una excepción; es decir, la ejecución normal se detiene y se transfiere el control a la zona de tratamiento de excepciones. Las excepciones internas se generan automáticamente por el sistema. Sintaxis de las rutinas de tratamiento de excepciones: EXCEPTION WHEN nombre_de_excepción_1 THEN secuencia_1_de_sentencias; WHEN nombre_de_excepción_2 THEN secuencia_2_de_sentencias;... Las excepciones predefinidas son: CURSOR_ALREADY_OPEN DUP_VAL_ON_INDEX INVALID_CURSOR INVALID_NUMBER 5
LOGON_DENIED NO_DATA_FOUND NOT_LOGGED_ON PROGRAM_ERROR STORAGE_ERROR TIMEOUT_ON_RESOURCE TOO_MANY_ROWS TANSACTION_BACKED_OUT VALUE_ERROR ZERO_DIVIDE Las excepciones definidas por el usuario deben declararse en la zona de declaraciones de la siguente forma: nombre_de_excepción EXCEPTION; Para generar una excepción definida por el usuario se utilizar la orden: RAISE nombre_de_excepción; Tras generarse una excepción, el sistema busca la rutina de tratamiento de la excepción en la zona de excepciones del bloque PL/SQL que estaba ejecutando. Si no la encuentra, la buscará en el bloque que contiene al bloque en ejecución. Esta búsqueda seguirá hasta encontrar la rutina apropiada o volver al entorno de ejecución. Después de encontrar la rutina, se ejecuta ésta y se sale del bloque en el que se ha encontrado para seguir ejecutando normalmente el bloque que lo contiene. Subprogramas Sintaxis de la declaración de un procedimiento: PROCEDURE nom_procedimiento (parámetros) IS [declaraciones_locales] secuencia_de_sentencias [EXECPTION tratamiento_de_excepciones] END [nom_procedimiento]; Sintaxis de la declaración de una función: FUNCTION nom_función (argumentos) RETURN tipo_dato IS [declaraciones_locales] secuencia_de_sentencias [EXECPTION tratamiento_de_excepciones] END [nom_procedimiento]; donde los argumentos siguen la siguiente sintaxis: nombre_argumento [ IN OUT IN OUT ] tipo_dato Para almacenar un procedimiento de forma permanente en la base de datos: CREATE PROCEDURE nom_procedimiento (parámetros) AS Secuencia_de_sentencias; 6
De forma similar se puede almacenar permanentemente una función en la base de datos. Entornos de ejecución: sqlplus Después de entrar en el entorno sqlplus, se pueden usar bloques PL/SQL de varias formas: Introducir y almacenar un bloque PL/SQL. Introducir y ejecutar un bloque PL/SQL. Crear un escrito que contenga un bloque PL/SQL. Cargar y ejecutar un escrito que contenga un bloque PL/SQL. Llamar un subprograma previamente almacenado. Si se elige uno de los dos primeros métodos, para introducir el bloque basta con teclearlo tras la señal "SQL>", terminando con una línea que sólo contenga un punto. Una vez terminado, el bloque se encuentra almacenado en el buffer de sqlplus y puede ejecutarse con "RUN". Normalmente los bloques PL/SQL se almacenarán en ficheros. Para salvar el buffer de sqlplus a un fichero se utiliza la orden siguiente: SQL> SAVE nombre_de_fichero Por supuesto, tambien puede escribirse con cualquier editor. Hay que tener la precaución de terminar cada bloque PL/SQL del escrito con una barra "/". Para cargar un escrito en el buffer de sqlplus, se usa la orden: SQL> GET nombre_de_fichero Si además de cargarlo, queremos ejecutarlo, utilizaremos: SQL> START nombre_de_fichero Si lo que queremos es llamar un procedimiento almacenado en la base de datos, usaremos la orden: SQL> EXECUTE nombre_de_procedimiento(parametros); sql embebido La forma más sencilla de embeber un bloque PL/SQL en un programa en sql embebido es: EXEC SQL EXECUTE bloque_pl_sql END-EXEC; 7