PL‐SQL - Irene-Frias/1DAM GitHub Wiki
PL/SQL (Procedural Language/SQL) es una extensión de SQL desarrollada por Oracle que permite incorporar estructuras propias de un lenguaje de programación, como variables, bucles, condicionales y subprogramas, directamente en el motor de base de datos.
Esto permite:
- Automatizar operaciones complejas.
- Encapsular lógica de negocio dentro de la base de datos.
- Reutilizar código mediante procedimientos, funciones y paquetes.
- Mejorar la seguridad y el mantenimiento del sistema.
PL/SQL se utiliza lo siguiente:
- Procedimientos almacenados
- Funciones definidas por el usuario
- Triggers (disparadores)
- Paquetes
- Bloques anónimos
Uso del usuario y permisos siguientes:
-
Oracle no crea múltiples bases de datos dentro de una misma instancia como lo hace MySQL. En su lugar, Oracle tiene una base de datos por instancia, y dentro de esa base de datos se crean usuarios (también llamados "schemas") que contienen objetos como tablas, vistas, procedimientos,...
-
Los permisos que le asignaremos al usuario serán todos, pero le quitaremos los siguientes permisos
ADMINISTER RESOURCE MANAGER
,KEEP DATE TIME
,KEEP SYSGUID
,SYSBACKUP
,SYSDBA
,SYSDG
,SYSKM
,SYSOPER
,SYSRAC
-
Por tanto, si quieres aislar conjuntos de objetos y datos, lo correcto es crear un usuario por "esquema" o conjunto funcional de objetos.
ALTER SESSION SET "_ORACLE_SCRIPT" = true;
- Bloques anónimos: fragmentos de código que se ejecutan directamente en herramientas como SQL*Plus o SQL Developer. No se almacenan en la base de datos.
BEGIN
DBMS_OUTPUT.PUT_LINE('Hola mundo');
END;
- Subprogramas almacenados: guardados en la base de datos como procedimientos, funciones o eventos. De esta forma se guardan en la base de datos y se pueden reutilizar.
- Sintaxis basada en bloques:
DECLARE
→BEGIN
→EXCEPTION
→END
. - Permite la declaración de variables locales y cursores.
- Soporta estructuras de control como
IF
,WHILE
,FOR
. - Permite el tratamiento de errores mediante bloques
EXCEPTION
. - Puede combinar SQL estándar con lógica procedural.
PL/SQL ofrece tipos de datos similares a SQL, y también permite heredar tipos directamente de las columnas de una tabla con %TYPE
Para definir las variables se declaran indicando el nombre seguido del tipo de dato, que puede ser:
-
Numéricos:
INT
,FLOAT
,DECIMAL
-
Texto:
CHAR
,VARCHAR
,TEXT
-
Fechas y tiempos:
DATE
,DATETIME
,TIME
,TIMESTAMP
-
Otros:
BOOLEAN
,BLOB
DECLARE
edad NUMBER(3);
nombre VARCHAR2(100);
fecha_nac DATE := SYSDATE;
activo BOOLEAN := TRUE;
BEGIN
-- Bloque de código
END;
- Nombres válidos para variables, funciones, etc.
- No deben comenzar por números ni contener caracteres especiales (excepto guion bajo).
- No se permiten caracteres especiales ni espacios.
- Ejemplos válidos:
v_total
,cliente_id
- Ejemplo inválido:
1nombre
,cliente-id
- Ejemplos válidos:
Las variables deben declararse al inicio de un bloque. Se declaran en la sección DECLARE antes del BEGIN.
DECLARE total INT DEFAULT 0;
DECLARE mensaje VARCHAR(255);
-
Números:
100
,3.14
-
Cadenas:
'Texto'
-
Fechas:
'2025-05-08'
-
Booleanos:
TRUE
,FALSE
-
Aritméticos:
+
,-
,*
,/
,%
-
Comparación:
=
,!=
,<
,>
,<=
,>=
-
Lógicos:
AND
,OR
,NOT
-
Otros:
IS NULL
,BETWEEN
,LIKE
,IN
-
Cadena:
LENGTH()
,CONCAT()
,SUBSTRING()
-
Numéricas:
ROUND()
,FLOOR()
,ABS()
-
Fecha/Hora:
NOW()
,DATE_ADD()
,CURDATE()
SELECT CONCAT('Hola ', 'mundo');
Al comenzar un fichero PL/SQL, es recomendable habilitar la visualización de mensajes enviados mediante DBMS_OUTPUT.PUT_LINE
. Para ello, activamos la opción con:
SET SERVEROUTPUT ON;
Esto permite que los mensajes generados por el programa se muestren en pantalla.
También es útil desactivar la verificación de sustitución de variables, especialmente cuando se utilizan variables con el símbolo &
. Al hacerlo, evitamos que se muestren mensajes como “old” y “new” durante la ejecución. Esto se logra con:
SET VERIFY OFF;
A continuación se muestran una serie de estructuras en las que estará comprendido en el bloque de BEGIN
y END
. Además de un DECLARE
o la creación de un procedimiento o función correspondiente, esto siendo opcional.
IF total > 100 THEN
SET descuento = 10;
ELSE
SET descuento = 0;
END IF;
CASE estado
WHEN 'A' THEN mensaje := 'Activo';
WHEN 'I' THEN mensaje := 'Inactivo';
ELSE mensaje := 'Desconocido';
END CASE;
WHILE contador < 10 DO
SET contador = contador + 1;
END WHILE;
REPEAT
SET intentos = intentos + 1;
UNTIL intentos = 3
END REPEAT;
LOOP
SET contador = contador + 1;
IF contador >= 5 THEN
LEAVE label;
END IF;
END LOOP label;
Reutilizan lógica sin devolver valores, es decir que realizan acciones.
CREATE OR REPLACE PROCEDURE saludar
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hola desde un procedimiento');
END;
EXECUTE IMMEDIATE
se combina con las funciones básicas de las sentencias, en las que puede utilizarse para preparar y ejecutar sentencias de SQL que no contengan variables del lenguaje. Pero no es una sentencia de consulta, devuelven datos después de ejecutar las sentencias. Los ejemplos de uso de los datos son los siguientes:
- Crear tablas dinámicamente con el nombre de una tabla basado en un valor y luego con la sintaxis
CREATE TABLE [nombre_tabla]
- Actualizar datos basados en criterios dinámicos en los que puede construir una sentencia
UPDATE
con unWHERE
que dependa de los datos de entrada. - Ejecutar los procedimientos almacenados dinámicamente para construir una llamada al procedimiento almacenado como parámetro.
EXECUTE IMMEDIATE 'CREATE TABLE clienteBackup AS (SELECT * FROM cliente)';
EXECUTE IMMEDIATE 'CREATE TABLE empleadoBackup AS (SELECT * FROM empleado)';
Devuelven un valor y se usan dentro de expresiones.
CREATE OR REPLACE FUNCTION doble(x IN NUMBER)
RETURN NUMBER -- No tiene porqué devolver algún valor
AS
BEGIN
RETURN x * 2;
END;
Permite controlar errores mediante handlers:
BEGIN
-- operación
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No se encontraron datos');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
Tipos de manejo:
- CONTINUE: continúa la ejecución tras el error.
- EXIT: termina el bloque actual al detectar el error.
Permiten recorrer resultados de consultas SELECT
:
Cuando la consulta devuelve múltiples filas, para obtener la información sobre la ejecución del mismo o sobre los datos estos atributos pueden ser usados en PL/SQL, pero no en SQL.
-
%FOUND
después de que el cursor esté abierto y antes de el primer FETCH en el que devuelve NULL. Después devolverá TRUE si en el último FETCH se ha devuelto una fila, y FALSE en caso contrario. Para cursores implícitos%FOUND
devuelve TRUE si es un INSERT, UPDATE o DELETE, que afectan a una o más filas como puede ser un SELECT ... INTO ... que devuelve una o más. -
%NOTFOUND
es lo contrario a%FOUND
-
%ISOPEN
evalúa la sentencia TRUE si el cursor está abierto y FALSE en caso contrario. Sin embargo para los cursores implícitos cierra automáticamente con%ISOPEN
en el que evalúa siempre a FALSE -
%ROWCOUNT
para un cursor abierto y antes del primer FETCH, es el que evalúa la condición a 0. Después de cada FETCH%ROWCOUNT
es incrementado y evalúa al número de filas afectadas por un INSERT, UPDATE o DELETE o el número de filas devueltas por un SELECT ... INTO ....
DECLARE
CURSOR c IS SELECT nombre FROM empleados;
v_nombre empleados.nombre%TYPE;
BEGIN
OPEN c;
LOOP
FETCH c INTO v_nombre;
EXIT WHEN c%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_nombre);
END LOOP;
CLOSE c;
END;
FOR emp IN (SELECT nombre FROM empleados) LOOP
DBMS_OUTPUT.PUT_LINE(emp.nombre);
END LOOP;
El código se ejecuta automáticamente ante los eventos INSERT
, UPDATE
, DELETE
.
CREATE OR REPLACE TRIGGER trg_auditoria
BEFORE INSERT ON empleados
FOR EACH ROW
BEGIN
:NEW.fecha_registro := SYSDATE;
END;