PLSQL
Documentación
-
[PL/SQL para desarrolladores Oracle España](https://www.oracle.com/es/database/technologies/appdev/plsql.html) - PLSQL para desarrolladores Oracle España-plsql.html
- Diferencia entre SQL y PLSQL Cuándo utilizar cada uno-difference-between-sql-and-plsql
Qué es PL/SQL
PL/SQL es el lenguaje procedimental nativo de Oracle, diseñado para extender SQL con estructuras de programación para crear lógica compleja, procesos transaccionales y manipulación de datos eficiente dentro de la base de datos.
Características principales
- Extensión de SQL: añade variables, bucles, condiciones y tipos de datos avanzados.
- Bloques Anidados: estructura basada en DECLARE → BEGIN → EXCEPTION → END.
- Alto rendimiento: ejecución cercana al motor, minimiza viajes entre aplicación y base.
- Manejadores de excepciones: control robusto de errores.
- Paquetes: encapsulación de lógica en módulos reutilizables.
- Triggers: ejecución automática ligada a eventos de tablas o vistas.
- Cursores: control explícito o implícito sobre conjuntos de resultados.
Arquitectura de un bloque PL/SQL
Ejemplo de estructura
DECLARE
v_total NUMBER;
BEGIN
SELECT SUM(salary) INTO v_total FROM employees;
DBMS_OUTPUT.PUT_LINE('Total: ' || v_total);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;
/
`
Tipos de programas PL/SQL
- Procedures: lógica que ejecuta acciones.
- Functions: devuelven un valor y pueden usarse desde SQL (con restricciones).
- Packages: colecciones de funciones/procedimientos organizadas en especificación y cuerpo.
- Triggers: lógica que responde a INSERT/UPDATE/DELETE o eventos del sistema.
- Tipos definidos por usuario: records, colecciones, objetos.
Cursores
Los cursores permiten procesar filas una a una cuando la lógica lo requiere.
Cursor explícito
DECLARE
CURSOR c_emp IS SELECT first_name, salary FROM employees;
v_name employees.first_name%TYPE;
v_salary employees.salary%TYPE;
BEGIN
FOR rec IN c_emp LOOP
DBMS_OUTPUT.PUT_LINE(rec.first_name || ' - ' || rec.salary);
END LOOP;
END;
/
Manejo de excepciones
Ejemplo
BEGIN
INSERT INTO employees(id, name) VALUES (1, 'John');
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE('ID duplicado.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error no esperado: ' || SQLERRM);
END;
/
Ventajas de PL/SQL
- Encapsulación de lógica compleja.
- Seguridad: control de acceso granular y privilegios mínimos.
- Reutilización mediante paquetes.
- Reducción del tráfico entre cliente y servidor.
- Integración con SQL y tipos del motor de Oracle.
Cuándo usar SQL y cuándo PL/SQL
- Usar SQL:
- Consultas simples.
- Agregaciones sin lógica adicional.
- Manipulación directa de datos sin procesos procedurales.
- Usar PL/SQL:
- Lógica condicional compleja.
- Procesos que requieren control de flujo, bucles o cursores.
- Automatización mediante triggers.
- APIs internas dentro de la base.
Buenas prácticas
- Usar
%TYPEy%ROWTYPEpara mantener coherencia con la estructura de la base. - Colocar EXCEPTION solo cuando sea necesario.
- Documentar cada paquete y rutina.
- Evitar cursores explícitos cuando un bucle implícito es suficiente.
- Minimizar commits dentro del código para evitar inconsistencias.
- Agrupar lógica relacionada en paquetes para claridad y mantenimiento.
Herramientas recomendadas
- SQL Developer
- Oracle APEX
- PL/SQL Unit Testing (UTPLSQL)
- Oracle LiveSQL (online)
PLSQL — Conceptos Avanzados y Temas Faltantes
Optimización y Rendimiento
- Bulk Operations (FORALL / BULK COLLECT): permiten mejorar el rendimiento al procesar grandes volúmenes reduciendo context switches entre SQL y PL/SQL.
- Parallel Execution: algunas operaciones PL/SQL pueden coordinar trabajo paralelo cuando se ejecutan vía SQL, especialmente en ETL.
- Pipelined Table Functions: funciones que devuelven datos fila a fila sin esperar al set completo, ideales para integraciones y flujos de datos en streaming.
- PL/SQL Native Compilation: compilar paquetes a código nativo para aumentar rendimiento en cálculos intensivos.
Bulk Collect
DECLARE
TYPE t_names IS TABLE OF employees.first_name%TYPE;
l_names t_names;
BEGIN
SELECT first_name BULK COLLECT INTO l_names FROM employees;
FOR i IN 1 .. l_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(l_names(i));
END LOOP;
END;
/
`
Diseño Profesional de Paquetes
Los paquetes pueden estructurarse como mini-módulos de software:
- Especificación mínima: solo lo que debe ser público.
- Cuerpo encapsulado: implementar lógica privada, sub-funciones, constantes internas.
- Variables de estado: cuidado con estado persistente entre sesiones, usar solo cuando sea estrictamente necesario.
- Instrumentación integrada:
DBMS_APPLICATION_INFOpara trazabilidad.
Plantilla recomendada
CREATE OR REPLACE PACKAGE customer_api IS
PROCEDURE create_customer(p_name VARCHAR2, p_email VARCHAR2);
FUNCTION get_customer(p_id NUMBER) RETURN customer_obj;
END customer_api;
/
CREATE OR REPLACE PACKAGE BODY customer_api IS
PROCEDURE create_customer(p_name VARCHAR2, p_email VARCHAR2) IS
BEGIN
INSERT INTO customers(name, email) VALUES (p_name, p_email);
END;
FUNCTION get_customer(p_id NUMBER) RETURN customer_obj IS
l_result customer_obj;
BEGIN
SELECT customer_obj(id, name, email)
INTO l_result
FROM customers
WHERE id = p_id;
RETURN l_result;
END;
END customer_api;
/
Seguridad en PL/SQL
- Definer Rights vs Invoker Rights:
- Definer Rights: el código usa los permisos del autor.
- Invoker Rights: ejecuta con permisos del usuario que lo llama.
- Wrappers y ofuscación: proteger lógica sensible.
- Privilege Minimization: evitar otorgar más permisos que los necesarios.
- Roles en PL/SQL: recordatorio crucial: los roles no están activos dentro del código, siempre usar privilegios directos.
Ejemplo de Invoker Rights
CREATE OR REPLACE PROCEDURE report_data AUTHID CURRENT_USER IS
BEGIN
-- ejecuta con permisos del usuario que llama
NULL;
END;
/
Tipos Avanzados
- Colecciones anidadas
- VARRAY
- Objetos y métodos
- Table Functions con objetos
- Tipos para integración: JSON_OBJECT_T, JSON_ARRAY_T
JSON nativo en PL/SQL
DECLARE
j JSON_OBJECT_T := JSON_OBJECT_T('{"name":"John","age":30}');
BEGIN
DBMS_OUTPUT.PUT_LINE(j.get_String('name'));
END;
/
Patrones de Diseño Recomendados
- API por paquetes: separar lectura/escritura, validaciones y utilidades en módulos claros.
- Dominio + Validación: crear funciones de validación reutilizables antes de cada INSERT/UPDATE.
- Control de Transacciones: centralizar commits/rollbacks en niveles superiores.
- Excepciones personalizadas: crear un paquete
errors_pkgpara estandarizar errores.
Excepción personalizadas
DECLARE
e_invalid_status EXCEPTION;
PRAGMA EXCEPTION_INIT(e_invalid_status, -20010);
BEGIN
RAISE e_invalid_status;
END;
/
Testing Profesional en PL/SQL
- UTPLSQL (framework estándar)
- Test de procedimientos
- Mock de tablas mediante entornos temporales
- Pruebas determinísticas con fixtures
Ejemplo UTPLSQL
BEGIN
ut.expect(customer_api.get_customer(1).name).to_equal('John');
END;
/
Integraciones Modernas
- PL/SQL + REST (Oracle REST Data Services — ORDS):
- Exponer procedimientos como endpoints REST.
- Controlar JSON IN/OUT con
APEX_JSONo tipos nativos.
- Eventos y colas (AQ / Advanced Queuing):
- Integración asíncrona entre sistemas.
- Programación con DBMS_SCHEDULER:
- Crear jobs automáticos avanzados, dependencias y flujos.
Job programado
BEGIN
DBMS_SCHEDULER.create_job(
job_name => 'daily_customer_sync',
job_type => 'PLSQL_BLOCK',
job_action => 'BEGIN sync_customers; END;',
repeat_interval => 'FREQ=DAILY;BYHOUR=3;',
enabled => TRUE
);
END;
/
Depuración e Instrumentación
- DBMS_OUTPUT: básico, evitar en producción.
- DBMS_DEBUG: depuración paso a paso.
- DBMS_PROFILER / PL/SQL Hierarchical Profiler: medir rendimiento real.
- Logs estructurados: registrar parámetros, errores y tiempos.
Errores Comunes a Evitar
- Declarar cursores cuando un bucle implícito sería suficiente.
- Realizar commit dentro de procedimientos internos.
- Exponer lógica interna en especificaciones de paquetes.
- Excepciones genéricas sin diagnóstico.
- No usar
%TYPE/%ROWTYPE.
Conceptos Avanzados a Vigilar
- Gestión de memoria interna de colecciones.
- Diferencias entre SQL Engine y PL/SQL Engine.
- Context Switching (CPU killer si no se controla).
- PL/SQL en entornos multitenant (CDB/PDB).
PLSQL — Nota actualizada a 2025 con recursos recientes
Qué es PL/SQL y por qué sigue vigente
PL/SQL es la extensión procedimental de SQL para Oracle Database, diseñada para permitir lógica compleja, modular y eficiente directamente en la base de datos. Combina la potencia de manipulación de datos de SQL con las capacidades de un lenguaje de programación: variables, estructuras de control, excepciones, subprogramas, etc.
Gracias a su integración nativa con el motor de Oracle, PL/SQL mantiene ventajas clave hoy en día: alto rendimiento, portabilidad, escalabilidad, reutilización de código, facilidad para mantenimientos centrales y seguridad.
Novedades, prácticas actuales y optimización (2025)
Buenas prácticas y optimización recomendadas
- Evita operaciones una-fila-a-una: usa operaciones bulk (
BULK COLLECT / FORALL) para procesar lotes de datos, reduciendo los context switches entre SQL y PL/SQL y aumentando el rendimiento. - Utiliza correctamente los tipos de datos: evita conversiones implícitas de tipo, dimensiona
VARCHAR2adecuadamente para evitar desperdicio de memoria. - Prefiere utilidades internas de Oracle antes de reinventar lógica del sistema.
- Usa herramientas de perfilado como
DBMS_PROFILERpara detectar cuellos de botella. - Diseña paquetes con interfaz pública mínima y lógica privada clara.
Temas y capacidades modernas dentro del ecosistema Oracle (2025)
- Soporte completo para tipos SQL (VARCHAR2, DATE, LOB…), variables con
%TYPE/%ROWTYPE. - Uso de SQL estático y dinámico para mayor flexibilidad.
- Estructuras modulares: procedimientos, funciones, paquetes, triggers.
- Manejo de excepciones avanzado y homogéneo en toda la aplicación.
Recursos recomendados (2024-2025)
-
**PL/SQL para desarrolladores Oracle España** — guía base del lenguaje, contexto, ventajas y recursos de inicio. - Database PL/SQL Language Reference (2025) — documentación oficial completa y actualizada del lenguaje.
- PL/SQL Best Practices — prácticas modernas de optimización, rendimiento y estilo.
- Curso fundamentos PL/SQL (OpenWebinars) — formación introductoria en español.
- Libro Oracle PL/SQL (César Pérez López, Ra-Ma) — base teórica recomendable para dominar fundamentos.
Estado actual del uso de PL/SQL en 2025
Aunque la publicación de nuevos libros se ha ralentizado, la documentación oficial de Oracle continúa actualizándose regularmente, manteniendo PL/SQL como una pieza central en entornos empresariales con Oracle Database.
En comunidades técnicas se observa que la demanda laboral especializada exclusivamente en PL/SQL ha disminuido, pero crece su valor combinado con otras tecnologías (frontend, backend generalista, cloud, ORDS, APEX).
Sigue siendo altamente útil en proyectos con lógica compleja, integraciones internas y sistemas críticos, especialmente en el sector bancario, seguros, fintech y organismos públicos.
Conclusión
PL/SQL continúa siendo en 2025 un lenguaje potente, seguro, escalable y profundamente integrado con Oracle Database. Para aprovechar su máximo potencial es necesario aplicar buenas prácticas modernas: operaciones bulk, diseño modular, uso de paquetes, profiling y control cuidadoso de transacciones.
Este stack sigue siendo relevante en entornos corporativos y críticos, aunque combinado cada vez más con tecnologías externas.
Enlaces utilizados
- https://docs.oracle.com/en/database/oracle/oracle-database/21/lnpls/overview.html
- https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/database-pl-sql-language-reference.pdf
- https://docs.oracle.com/en/industries/retail/retail-analytics-planning/24.1.201.0/rapig/pl-sql-best-practice.htm
- https://www.oracle.com/es/database/technologies/appdev/plsql.html
- https://openwebinars.net/cursos/fundamentos-pl-sql
- https://www.ra-ma.es/libro/oracle-pl-sql_141216
- https://www.reddit.com/r/oracle/comments/1idmlbg
Glosario PL/SQL (Listado)
Fundamentos del Lenguaje
- PL/SQL: Extensión procedural de SQL integrada en Oracle.
- Bloque PL/SQL: Estructura con
DECLARE,BEGIN,EXCEPTION,END. - Bloque anónimo: No almacenado, ejecución directa.
- Bloque nombrado: Procedimientos, funciones o paquetes almacenados.
- Declaración de variables.
- Tipos escalares:
NUMBER,VARCHAR2,DATE,BOOLEAN. - Tipos anclados:
%TYPE,%ROWTYPE. - Constantes: Uso de
CONSTANT. - Estructuras de control:
IF,CASE,FOR,WHILE,LOOP.
Estructuras de Programación
- Procedimientos:
- Parámetros
IN,OUT,IN OUT. - Sobrecarga (overload).
- Parámetros
- Funciones:
- Devuelven valor.
- Usables en SQL si son deterministas o seguras.
- Packages:
- Specification (interfaz pública).
- Body (implementación privada).
- Variables de paquete persistentes.
SQL en PL/SQL
SELECT INTO: Asignación de resultados.- DML directo:
INSERT,UPDATE,DELETE. RETURNING INTO: Obtener valores tras un DML.- Cursores:
- Implícitos.
- Explícitos:
OPEN / FETCH / CLOSE. FOR cursor IN ... LOOP.- Cursores con parámetros.
- Bulk processing:
BULK COLLECT.FORALL.SAVE EXCEPTIONS.
Manejo de Excepciones
- Excepciones predefinidas:
NO_DATA_FOUND,TOO_MANY_ROWS,DUP_VAL_ON_INDEX. - Excepciones definidas por el usuario.
RAISEyRAISE_APPLICATION_ERROR.SQLCODEySQLERRM.
Tipos Avanzados
- Registros:
%ROWTYPE.TYPE ... IS RECORD.
- Colecciones:
- Associative Arrays (
INDEX BY). - Nested Tables.
- VARRAYs.
- Associative Arrays (
Rendimiento
- Bulk operations para evitar row-by-row.
- Reducción de context switching SQL ↔ PL/SQL.
- Caching con variables de paquete.
- Minimizar queries dentro de loops.
- Bind variables en SQL dinámico.
- Uso de
DBMS_PROFILERyDBMS_HPROF.
Seguridad y Acceso
- Definer’s Rights (por defecto).
- Invoker’s Rights (
AUTHID CURRENT_USER). - SQL Injection en SQL dinámico.
- Mitigación mediante parámetros bind.
SQL Dinámico
EXECUTE IMMEDIATE:USINGpara bind variables.INTOpara resultados.RETURNING INTOpara DML.
- Paquete
DBMS_SQL:- Ejecución de SQL dinámico complejo.
- Compatibilidad con columnas variables.
Paquetes del Sistema
DBMS_OUTPUT: Mostrar texto.DBMS_RANDOM: Valores aleatorios.DBMS_SCHEDULER: Jobs programados.DBMS_UTILITY: Utilidades varias.DBMS_LOCK: Locks a nivel PL/SQL.UTL_FILE: Acceso a ficheros.UTL_HTTP: Llamadas HTTP.
Transacciones
COMMITyROLLBACK.SAVEPOINT.- Transacciones autónomas:
PRAGMA AUTONOMOUS_TRANSACTION.
Herramientas Habituales
- SQL*Plus.
- SQL Developer.
- SQLcl.
- Oracle APEX.
- Oracle REST Data Services (ORDS).
PL/SQL — Ejemplos de Código Explicados (2025)
Bloques PL/SQL
Bloque Anónimo
DECLARE
v_msg VARCHAR2(50) := 'Hola desde PL/SQL';
BEGIN
DBMS_OUTPUT.PUT_LINE(v_msg);
END;
/
`
Explicación:
Un bloque anónimo no se almacena en la base de datos; se ejecuta directamente. Es ideal para pruebas rápidas, scripts o lógica temporal.
Variables y Tipos
Uso de %TYPE
DECLARE
v_emp_name employees.last_name%TYPE;
BEGIN
SELECT last_name INTO v_emp_name
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE(v_emp_name);
END;
/
Explicación:
%TYPE hereda el tipo de columna, garantizando consistencia incluso si la estructura de la tabla cambia.
Uso de %ROWTYPE
DECLARE
v_emp_record employees%ROWTYPE;
BEGIN
SELECT * INTO v_emp_record
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE(v_emp_record.last_name);
END;
/
Explicación:
%ROWTYPE crea un registro con todas las columnas de la tabla o vista, útil para consultas completas.
Estructuras de Control
IF / ELSIF / ELSE
DECLARE
v_num NUMBER := 7;
BEGIN
IF v_num > 10 THEN
DBMS_OUTPUT.PUT_LINE('Mayor que 10');
ELSIF v_num = 10 THEN
DBMS_OUTPUT.PUT_LINE('Igual a 10');
ELSE
DBMS_OUTPUT.PUT_LINE('Menor que 10');
END IF;
END;
/
Explicación:
Permite evaluar condiciones múltiples y tomar decisiones lógico-procedimentales.
FOR Loop
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE('Iteración: ' || i);
END LOOP;
END;
/
Explicación:
El FOR define automáticamente el contador y sus límites.
Procedimientos
Procedimiento con Parámetros IN y OUT
CREATE OR REPLACE PROCEDURE get_salary (
p_emp_id IN employees.employee_id%TYPE,
p_salary OUT employees.salary%TYPE
) AS
BEGIN
SELECT salary INTO p_salary
FROM employees
WHERE employee_id = p_emp_id;
END;
/
Explicación:
El parámetro OUT devuelve datos al llamador, permitiendo que el procedimiento actúe como una operación que modifica el estado externo.
Funciones
Función Determinista
CREATE OR REPLACE FUNCTION yearly_salary (
p_monthly NUMBER
) RETURN NUMBER DETERMINISTIC AS
BEGIN
RETURN p_monthly * 12;
END;
/
Explicación:
DETERMINISTIC indica que la función devolverá siempre el mismo resultado con la misma entrada, permitiendo optimizaciones internas.
Packages
Package Specification y Body
CREATE OR REPLACE PACKAGE math_pkg AS
FUNCTION square(p_num NUMBER) RETURN NUMBER;
END math_pkg;
/
CREATE OR REPLACE PACKAGE BODY math_pkg AS
FUNCTION square(p_num NUMBER) RETURN NUMBER IS
BEGIN
RETURN p_num * p_num;
END;
END math_pkg;
/
Explicación:
Los paquetes separan la interfaz (spec) de la implementación (body), facilitando el mantenimiento y ocultando detalles.
Cursores
Cursor Explícito
DECLARE
CURSOR c_emps IS
SELECT employee_id, last_name FROM employees;
v_id employees.employee_id%TYPE;
v_name employees.last_name%TYPE;
BEGIN
OPEN c_emps;
LOOP
FETCH c_emps INTO v_id, v_name;
EXIT WHEN c_emps%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_id || ' - ' || v_name);
END LOOP;
CLOSE c_emps;
END;
/
Explicación:
Permite recorrer fila a fila el resultado de una consulta, ideal cuando se necesita procesar datos individualmente.
Cursor FOR Loop
BEGIN
FOR rec IN (SELECT employee_id, last_name FROM employees) LOOP
DBMS_OUTPUT.PUT_LINE(rec.employee_id || ': ' || rec.last_name);
END LOOP;
END;
/
Explicación:
Simplifica la sintaxis: Oracle maneja OPEN, FETCH y CLOSE automáticamente.
Bulk Processing
BULK COLLECT
DECLARE
TYPE t_names IS TABLE OF employees.last_name%TYPE;
v_names t_names;
BEGIN
SELECT last_name BULK COLLECT INTO v_names
FROM employees;
DBMS_OUTPUT.PUT_LINE('Total: ' || v_names.COUNT);
END;
/
Explicación:
Permite obtener muchas filas a la vez, eliminando múltiples cambios de contexto SQL↔PLSQL y acelerando procesos masivos.
FORALL
DECLARE
TYPE t_ids IS TABLE OF NUMBER;
v_ids t_ids := t_ids(1, 2, 3, 4, 5);
BEGIN
FORALL i IN v_ids.FIRST .. v_ids.LAST
UPDATE employees
SET salary = salary * 1.05
WHERE employee_id = v_ids(i);
END;
/
Explicación:
Ejecuta DML masivo en lotes, mucho más rápido que ejecutar UPDATE dentro de un loop.
Excepciones
Manejo de Excepciones
DECLARE
v_sal NUMBER;
BEGIN
SELECT salary INTO v_sal
FROM employees
WHERE employee_id = 9999; -- No existe
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Empleado no encontrado.');
END;
/
Explicación:
EXCEPTION intercepta errores y permite un manejo controlado.
SQL Dinámico
EXECUTE IMMEDIATE Básico
DECLARE
v_sql VARCHAR2(200) := 'UPDATE employees SET salary = salary * 1.10 WHERE employee_id = :id';
BEGIN
EXECUTE IMMEDIATE v_sql USING 100;
END;
/
Explicación:
SQL dinámico permite construir y ejecutar sentencias en tiempo de ejecución, con soporte para bind variables.
EXECUTE IMMEDIATE con INTO
DECLARE
v_count NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM employees' INTO v_count;
DBMS_OUTPUT.PUT_LINE('Total: ' || v_count);
END;
/
Transacciones
Uso de SAVEPOINT y ROLLBACK
BEGIN
UPDATE employees SET salary = salary + 100 WHERE employee_id = 101;
SAVEPOINT sp1;
UPDATE employees SET salary = salary + 100 WHERE employee_id = 9999; -- error
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO sp1;
DBMS_OUTPUT.PUT_LINE('Se revierte al savepoint.');
END;
/
Explicación:
Los savepoints permiten revertir parcialmente una transacción sin perder operaciones anteriores.
Transacciones Autónomas
PRAGMA AUTONOMOUS_TRANSACTION
CREATE OR REPLACE PROCEDURE log_event(p_msg VARCHAR2) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO event_log(message, created_at)
VALUES (p_msg, SYSDATE);
COMMIT; -- independiente de la transacción principal
END;
/
Explicación:
Este procedimiento hace commit por sí mismo sin afectar la lógica externa.
Paquetes del Sistema
DBMS_OUTPUT
BEGIN
DBMS_OUTPUT.PUT_LINE('Mostrando un mensaje');
END;
/
DBMS_RANDOM
DECLARE
v_num NUMBER;
BEGIN
v_num := DBMS_RANDOM.VALUE(1, 100);
DBMS_OUTPUT.PUT_LINE('Número aleatorio: ' || v_num);
END;
/
UTL_HTTP — Petición HTTP
DECLARE
v_resp CLOB;
BEGIN
v_resp := UTL_HTTP.REQUEST('https://example.com');
DBMS_OUTPUT.PUT_LINE(v_resp);
END;
/
Explicación:
Permite acceder a servicios web desde PL/SQL (requiere ACL configurado).
PL/SQL — Casos Reales de Empresa (Ejemplos Extensos y Explicados)
Caso 1: Cálculo de Comisiones Mensuales (Sector Ventas / Retail)
Descripción
Una empresa de retail necesita calcular comisiones mensuales basadas en el total vendido por cada empleado. El sistema debe: - Detectar ventas del mes. - Aplicar reglas diferentes según categoría del vendedor. - Registrar el cálculo en una tabla histórica. - Ser ejecutado automáticamente cada inicio de mes.
Ejemplo de Código
CREATE OR REPLACE PROCEDURE calc_comisiones IS
CURSOR c_vendedores IS
SELECT v.vendedor_id,
v.categoria,
SUM(s.monto) total_mes
FROM ventas s
JOIN vendedores v ON v.vendedor_id = s.vendedor_id
WHERE s.fecha BETWEEN ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -1)
AND TRUNC(SYSDATE, 'MM') - 1
GROUP BY v.vendedor_id, v.categoria;
v_comision NUMBER;
BEGIN
FOR rec IN c_vendedores LOOP
-- Reglas por categoría
IF rec.categoria = 'A' THEN
v_comision := rec.total_mes * 0.12;
ELSIF rec.categoria = 'B' THEN
v_comision := rec.total_mes * 0.08;
ELSE
v_comision := rec.total_mes * 0.05;
END IF;
INSERT INTO historial_comisiones(vendedor_id, total_mes, comision, fecha_calculo)
VALUES (rec.vendedor_id, rec.total_mes, v_comision, SYSDATE);
END LOOP;
COMMIT;
END;
/
`
Explicación
Este procedimiento reemplaza informes manuales. Puede ejecutarse mediante DBMS_SCHEDULER mensualmente, evitando cálculos externos (Excel, scripts Python) y garantizando consistencia.
Caso 2: Auditoría Automática de Cambios (Sector Bancario)
Descripción
Regulaciones financieras obligan a auditar cada modificación de ciertas tablas (clientes, cuentas, transacciones). La auditoría debe incluir:
- Usuario que realizó el cambio.
- Timestamp.
- Valores antes y después.
Ejemplo de Trigger de Auditoría
CREATE OR REPLACE TRIGGER audit_cuentas_trg
AFTER UPDATE ON cuentas
FOR EACH ROW
BEGIN
INSERT INTO auditoria_cuentas(
cuenta_id,
usuario,
fecha_cambio,
saldo_anterior,
saldo_nuevo
)
VALUES(
:OLD.cuenta_id,
SYS_CONTEXT('USERENV','SESSION_USER'),
SYSTIMESTAMP,
:OLD.saldo,
:NEW.saldo
);
END;
/
Explicación
Este patrón es muy común en banca, donde trazabilidad = cumplimiento normativo. PL/SQL es ideal, pues la auditoría reside dentro del motor y no depende de aplicaciones externas.
Caso 3: Envío de Notificaciones a Clientes (Sector Seguros / Telecom)
Descripción
Una compañía quiere avisar a clientes cuyo contrato expira en los próximos 30 días. Las notificaciones deben enviarse mediante ORDS o un API REST.
Ejemplo con UTL_HTTP
DECLARE
CURSOR c_clientes IS
SELECT cliente_id, email
FROM contratos
WHERE fecha_fin BETWEEN SYSDATE AND SYSDATE + 30;
v_payload VARCHAR2(4000);
v_response CLOB;
BEGIN
FOR rec IN c_clientes LOOP
v_payload := '{"email": "' || rec.email || '", "mensaje": "Su contrato está próximo a expirar."}';
v_response := UTL_HTTP.REQUEST(
url => 'https://api.miempresa.com/notificaciones',
method => 'POST',
body => v_payload
);
INSERT INTO log_notificaciones(cliente_id, fecha_envio, respuesta)
VALUES (rec.cliente_id, SYSDATE, v_response);
END LOOP;
COMMIT;
END;
/
Explicación
Ideal para integraciones sin intermediarios. Requiere ACL, pero evita tener que sacar datos fuera de la BD para enviarlos desde un servicio externo.
Caso 4: Procesamiento Masivo de Datos (Sector Logística)
Descripción
Una empresa logística recibe a diario millones de registros de escaneos de paquetes (IoT). Necesita:
- Procesar en lotes (bulk collect).
- Consolidar datos y actualizar estados.
- Mantener rendimiento alto.
Ejemplo con BULK COLLECT + FORALL
DECLARE
TYPE t_escaneos IS TABLE OF escaneos%ROWTYPE;
v_lote t_escaneos;
BEGIN
SELECT *
BULK COLLECT INTO v_lote
FROM escaneos
WHERE procesado = 'N'
FETCH FIRST 50000 ROWS ONLY;
FORALL i IN v_lote.FIRST .. v_lote.LAST
UPDATE paquetes
SET ultima_localizacion = v_lote(i).ubicacion,
fecha_ultima = v_lote(i).fecha
WHERE paquete_id = v_lote(i).paquete_id;
FORALL i IN v_lote.FIRST .. v_lote.LAST
UPDATE escaneos SET procesado = 'S'
WHERE id = v_lote(i).id;
COMMIT;
END;
/
Explicación
Procesar fila por fila sería inviable. Bulk operations permiten procesar cientos de miles de registros en segundos.
Caso 5: Generación de Informes Diarios (Sector Financiero)
Descripción
Se generan PDFs o CSV con movimientos, saldos y operaciones. La generación se hace dentro de la BD para evitar transferencias.
Ejemplo: Generación de CSV con UTL_FILE
DECLARE
fh UTL_FILE.FILE_TYPE;
BEGIN
fh := UTL_FILE.FOPEN('DIR_REPORTES', 'movimientos.csv', 'W');
FOR rec IN (SELECT cuenta_id, monto, fecha FROM movimientos WHERE fecha >= TRUNC(SYSDATE)) LOOP
UTL_FILE.PUT_LINE(fh, rec.cuenta_id || ';' || rec.monto || ';' || rec.fecha);
END LOOP;
UTL_FILE.FCLOSE(fh);
END;
/
Explicación
Usado en ambientes core, donde los informes diarios deben generarse rápido y con datos consistentes.
Caso 6: Limpieza y Archivado Automático (Sector Administración Pública)
Descripción
El sistema debe archivar registros antiguos en una tabla histórica, eliminar registros muy antiguos y mantener índices limpios.
Ejemplo
BEGIN
INSERT INTO historico_tramites
SELECT * FROM tramites
WHERE fecha < ADD_MONTHS(SYSDATE, -24);
DELETE FROM tramites
WHERE fecha < ADD_MONTHS(SYSDATE, -24);
COMMIT;
END;
/
Explicación
Permite mantener el rendimiento de tablas críticas y cumplir políticas de conservación de datos.
Caso 7: Validación Compleja de Datos (Sector Salud)
Descripción
Antes de registrar un acto clínico, deben validarse múltiples reglas:
- Formatos.
- Rango de valores.
- Existencia de datos obligatorios.
- Reglas de negocio específicas del centro.
Ejemplo
CREATE OR REPLACE FUNCTION validar_datos (
p_paciente_id NUMBER,
p_codigo_acto VARCHAR2,
p_monto NUMBER
) RETURN VARCHAR2 AS
BEGIN
IF p_monto < 0 THEN
RETURN 'Monto inválido';
END IF;
IF NOT EXISTS (SELECT 1 FROM pacientes WHERE paciente_id = p_paciente_id) THEN
RETURN 'Paciente inexistente';
END IF;
IF p_codigo_acto NOT IN ('C01','C02','C03') THEN
RETURN 'Acto no permitido';
END IF;
RETURN 'OK';
END;
/
Explicación
Permite centralizar reglas complejas en la base de datos, evitando inconsistencias entre múltiples aplicaciones.
Caso 8: Sincronización de Sistemas (Sector Multinacional / ERP)
Descripción
Un ERP debe sincronizar datos con un sistema externo cada noche:
- Extraer datos modificados.
- Convertirlos a JSON.
- Enviar a un API.
Ejemplo
DECLARE
v_json CLOB;
BEGIN
FOR rec IN (SELECT * FROM productos WHERE fecha_mod > SYSDATE - 1) LOOP
v_json := '{"id": ' || rec.id || ', "name": "' || rec.nombre || '"}';
-- Llamada HTTP simulada
UTL_HTTP.REQUEST('https://externo/api/sync', 'POST', v_json);
END LOOP;
INSERT INTO log_sync(fecha, registros)
VALUES (SYSDATE, SQL%ROWCOUNT);
COMMIT;
END;
/
Explicación
Evita tener procesos ETL externos para sincronizaciones pequeñas y frecuentes.
Caso 9: Control de Inventario en Tiempo Real (Sector Industrial)
Descripción
Sensores notifican cambios de stock. La BD debe actualizar inventario y detectar alertas.
Ejemplo
CREATE OR REPLACE PROCEDURE actualizar_stock (
p_item_id NUMBER,
p_cantidad NUMBER
) AS
BEGIN
UPDATE inventario
SET stock = stock + p_cantidad
WHERE item_id = p_item_id;
IF (SELECT stock FROM inventario WHERE item_id = p_item_id) < 10 THEN
INSERT INTO alertas(item_id, fecha, mensaje)
VALUES(p_item_id, SYSDATE, 'Stock bajo');
END IF;
COMMIT;
END;
/
Explicación
Procesos de stock críticos requieren que la lógica esté en el motor para ser inmediata.
Caso 10: Logs de Aplicación Centralizados (Cualquier Sector)
Descripción
Se quiere que todas las aplicaciones escriban logs en una tabla única con transacciones autónomas.
Ejemplo
CREATE OR REPLACE PROCEDURE app_log(p_msg VARCHAR2) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO app_logs(mensaje, fecha)
VALUES(p_msg, SYSTIMESTAMP);
COMMIT;
END;
/
Explicación
Permite que los logs no dependan del flujo normal ni de commits externos.
Si quieres, puedo generar otra versión con casos extremadamente avanzados, como:
- modelado de particiones + PL/SQL,
- flujos distribuidos,
- PL/SQL como motor de reglas,
- automatización con ORDS + PL/SQL,
- pipelines de datos internos.
Casos Extremadamente Avanzados en PL/SQL (2025)
1. Procesamiento Masivo con Pipelines, Paralelismo y Bulk Ops
Caso: ETL interno de millones de registros con mínima carga en buffer cache
Explicación:
En entornos de data warehousing, PL/SQL permite crear table functions pipelined combinadas con paralelismo para transformar conjuntos enormes sin materializar tablas intermedias.
Ejemplo — Pipeline + Bulk + Transformación Compleja
CREATE OR REPLACE TYPE t_etl_row AS OBJECT (
id NUMBER,
valor NUMBER,
etiqueta VARCHAR2(50)
);
/
CREATE OR REPLACE TYPE t_etl_tab IS TABLE OF t_etl_row;
/
CREATE OR REPLACE FUNCTION etl_pipeline_f(p_limit NUMBER)
RETURN t_etl_tab PIPELINED
IS
TYPE t_src_tab IS TABLE OF src_table%ROWTYPE;
v_src t_src_tab;
BEGIN
LOOP
-- Extracción por lotes
SELECT * BULK COLLECT INTO v_src
FROM (
SELECT * FROM src_table
WHERE procesado = 0
AND ROWNUM <= p_limit
);
EXIT WHEN v_src.COUNT = 0;
FOR i IN 1 .. v_src.COUNT LOOP
-- Lógica avanzada de enriquecimiento + segmentación
PIPE ROW (t_etl_row(
v_src(i).id,
v_src(i).valor * DBMS_CRYPTO.HASH(TO_CHAR(v_src(i).id), 2),
CASE
WHEN v_src(i).valor < 100 THEN 'LOW'
WHEN v_src(i).valor < 500 THEN 'MID'
ELSE 'HIGH'
END
));
END LOOP;
END LOOP;
RETURN;
END;
/
-- Consulta paralela del pipeline
SELECT /*+ PARALLEL(4) */ *
FROM TABLE(etl_pipeline_f(5000));
`
Qué resuelve:
- ETL de alto volumen sin staging tables.
- Transformación en streaming.
- Uso eficiente de memoria.
- Puede ser paralelizado, incluso distribuido.
2. Motor de Reglas Empresariales Dinámicas (Dynamic SQL + JSON + PLSQL)
Caso: Un banco debe cambiar reglas de scoring sin desplegar código
Explicación:
Las reglas se almacenan como JSON en una tabla. PL/SQL las interpreta dinámicamente.
Ejemplo — Regla dinámica
DECLARE
v_regla JSON_OBJECT_T;
v_sql VARCHAR2(4000);
v_score NUMBER;
BEGIN
-- Obtener regla JSON
SELECT JSON_OBJECT_T(regla_json)
INTO v_regla
FROM reglas_scoring
WHERE regla_id = 10;
-- Construcción dinámica de expresión
v_sql := '
SELECT (' || v_regla.get_String('formula') || ')
FROM dual';
EXECUTE IMMEDIATE v_sql INTO v_score;
DBMS_OUTPUT.PUT_LINE('Score resultante = ' || v_score);
END;
Qué resuelve:
- Cambios de reglas por negocio sin tocar PL/SQL.
- Permite evaluaciones matemáticas o lógicas complejas configurables.
3. Particionamiento Lógico por Código con Result Cache Inteligente
Caso: Sistema que debe servir cálculos pesados a miles de consultas por segundo
Explicación:
RESULT_CACHE + invalidación manual permite reducir tiempos a microsegundos.
Ejemplo — Cache con partición lógica
CREATE OR REPLACE FUNCTION fx_get_riesgo(p_cliente NUMBER)
RETURN NUMBER
RESULT_CACHE RELIES_ON(clientes)
IS
v_riesgo NUMBER;
BEGIN
SELECT riesgo INTO v_riesgo
FROM clientes
WHERE id = p_cliente;
RETURN v_riesgo;
END;
/
-- Invalida el valor del cache al actualizar
CREATE OR REPLACE TRIGGER trg_upd_cliente
AFTER UPDATE ON clientes
BEGIN
DBMS_RESULT_CACHE.FLUSH;
END;
Qué resuelve:
- Consultas repetitivas ultra rápidas.
- Control total sobre invalidación.
- Ideal para dashboards en tiempo real.
4. Optimización de Pricing Avanzado usando Colecciones Indexadas + Hashes
Caso: Motor de precios que debe recalcular tarifas según cientos de reglas jerarquizadas
Explicación:
Las associative arrays permiten crear estructuras hash ultra rápidas para búsquedas complejas en memoria PL/SQL.
Ejemplo — Motor de pricing en memoria
DECLARE
TYPE t_price_map IS TABLE OF NUMBER INDEX BY VARCHAR2(200);
v_prices t_price_map;
v_key VARCHAR2(200);
BEGIN
-- Cargar reglas en memoria
FOR r IN (SELECT categoria, subcat, coef
FROM pricing_reglas) LOOP
v_key := r.categoria || ':' || r.subcat;
v_prices(v_key) := r.coef;
END LOOP;
-- Aplicar reglas a transacción
DBMS_OUTPUT.PUT_LINE(
'Precio final = ' ||
(100 * v_prices('ELEC:HIGH'))
);
END;
Qué resuelve:
- Reglas jerárquicas rápidas (tiempo O(1)).
- Sistemas de pricing, scoring, tarifas y segmentación.
- Evita JOINs costosos.
5. Procesos de Conciliación Inter-Sistemas a Alta Velocidad
Caso: Comparación masiva de datos entre dos sistemas externos
Explicación:
Uso de BULK COLLECT, hashing y procesamiento batch para medir diferencias entre millones de registros.
Ejemplo — Conciliación con hashing
DECLARE
TYPE t_rows IS TABLE OF VARCHAR2(4000);
v_src1 t_rows;
v_src2 t_rows;
v_diff t_rows := t_rows();
BEGIN
-- Cargar datos (simplificado)
SELECT DBMS_CRYPTO.HASH(col1 || col2, 2)
BULK COLLECT INTO v_src1
FROM tabla_a;
SELECT DBMS_CRYPTO.HASH(col1 || col2, 2)
BULK COLLECT INTO v_src2
FROM tabla_b;
-- Comparación avanzada
FOR i IN 1 .. v_src1.COUNT LOOP
IF v_src2.EXISTS(i) THEN
IF v_src1(i) != v_src2(i) THEN
v_diff.EXTEND;
v_diff(v_diff.COUNT) := 'DIF: ' || i;
END IF;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Total diferencias: ' || v_diff.COUNT);
END;
Qué resuelve:
- Conciliación masiva entre sistemas heterogéneos.
- Uso eficiente de CPU y memoria.
- Detección rápida de divergencias.
6. Orquestación de Microservicios desde PL/SQL (HTTP + JSON + Lógica Transaccional)
Caso: Core bancario llama a microservicios externos pero controla la transacción en Oracle
Explicación:
PL/SQL actúa como coordinador de operaciones externas asegurando consistencia.
Ejemplo — Llamada avanzada a microservicios
DECLARE
v_req UTL_HTTP.req;
v_resp UTL_HTTP.resp;
v_body VARCHAR2(32767);
v_json JSON_OBJECT_T;
BEGIN
v_req := UTL_HTTP.begin_request('https://api.interno/cliente/score', 'POST');
UTL_HTTP.set_header(v_req, 'Content-Type', 'application/json');
UTL_HTTP.write_text(v_req, '{"id":1234}');
v_resp := UTL_HTTP.get_response(v_req);
LOOP
UTL_HTTP.read_text(v_resp, v_body, 32000);
EXIT WHEN v_body IS NULL;
END LOOP;
UTL_HTTP.end_response(v_resp);
v_json := JSON_OBJECT_T.parse(v_body);
DBMS_OUTPUT.PUT_LINE('Score recibido: ' || v_json.get_Number('score'));
END;
Qué resuelve:
- Orquestación transaccional híbrida.
- Integración con APIs REST.
- Lógica compleja sin exponer Oracle directamente.
7. Implementación de un Sistema de Auditoría Criptográfica Interna
Caso: Empresa de seguros requiere auditoría no repudiable dentro de Oracle
Explicación:
PL/SQL + DBMS_CRYPTO generan huellas digitales encadenadas (tipo blockchain ligera).
Ejemplo — Cadena de auditoría
DECLARE
v_last_hash RAW(256);
v_new_hash RAW(256);
BEGIN
SELECT hash INTO v_last_hash
FROM auditoria
ORDER BY id DESC
FETCH FIRST 1 ROW ONLY;
v_new_hash := DBMS_CRYPTO.HASH(
UTL_I18N.STRING_TO_RAW('evento=' || SYSTIMESTAMP || '|' || v_last_hash),
DBMS_CRYPTO.HASH_SH256
);
INSERT INTO auditoria(id, timestamp, hash)
VALUES (auditoria_seq.NEXTVAL, SYSTIMESTAMP, v_new_hash);
END;
Qué resuelve:
- Auditoría encadenada estilo blockchain.
- No repudiable.
- Inmutable sin herramientas externas.
¿Quieres la versión siguiente?
Puedo generar:
- Versión con casos de ciberseguridad extrema
- Versión con patrones arquitectónicos PL/SQL + microservicios
- Versión con optimizaciones de rendimiento extremo para 2025
- Versión con anti-patterns avanzados (qué NO hacer)
Patrones Arquitectónicos PL/SQL + Microservicios (2025)
1. Pattern: Orquestador Centralizado
Descripción
PL/SQL actúa como nodo central que coordina múltiples microservicios y bases de datos externas, asegurando consistencia transaccional.
Ejemplo
DECLARE
v_response1 CLOB;
v_response2 CLOB;
BEGIN
-- Llamada a microservicio A
v_response1 := UTL_HTTP.REQUEST('https://api.servicioA.com/operacion', 'POST', '{"id":1001}');
-- Llamada a microservicio B solo si A fue exitoso
IF v_response1 IS NOT NULL THEN
v_response2 := UTL_HTTP.REQUEST('https://api.servicioB.com/validar', 'POST', '{"ref":1001}');
END IF;
-- Registro interno de transacción
INSERT INTO log_orquestacion(fecha, servicioA_resp, servicioB_resp)
VALUES(SYSDATE, v_response1, v_response2);
COMMIT;
END;
`
Ventaja: Control total de la lógica empresarial desde Oracle, manteniendo integridad sin depender de middleware externo.
2. Pattern: Event-Driven Architecture
Descripción
PL/SQL actúa como productor y consumidor de eventos usando tablas de cola o triggers; los microservicios reaccionan a cambios en la base de datos.
Ejemplo — Trigger Event Queue
CREATE OR REPLACE TRIGGER trg_evento_cliente
AFTER INSERT OR UPDATE ON clientes
FOR EACH ROW
BEGIN
INSERT INTO event_queue(event_type, payload, fecha)
VALUES(
'CLIENTE_MODIFICADO',
'{"id":' || :NEW.cliente_id || ',"nombre":"' || :NEW.nombre || '"}',
SYSTIMESTAMP
);
END;
/
Explicación:
Microservicios externos leen event_queue y procesan eventos de forma asíncrona, permitiendo desacoplar sistemas.
3. Pattern: API Gateway Interno
Descripción
Oracle PL/SQL expone endpoints internos mediante ORDS o REST Data Services, actuando como gateway para microservicios y clientes internos.
Ejemplo — ORDS PL/SQL Endpoint
BEGIN
-- Endpoint: /clientes/get
ORDS.ENABLE_SCHEMA(
p_enabled => TRUE,
p_schema => 'APP_SCHEMA'
);
-- Procedimiento que se mapea como REST GET
CREATE OR REPLACE PROCEDURE get_cliente(p_id IN NUMBER) AS
v_name VARCHAR2(100);
BEGIN
SELECT nombre INTO v_name FROM clientes WHERE cliente_id = p_id;
HTP.P('{"cliente_id":' || p_id || ',"nombre":"' || v_name || '"}');
END;
END;
Ventaja:
- Exposición segura de datos internos.
- Simplifica acceso de microservicios a datos críticos.
- Permite control de autenticación y throttling en Oracle.
4. Pattern: Transacciones Distribuidas / Saga Pattern
Descripción
PL/SQL gestiona pasos locales con commits parciales o autonómicos, coordinando microservicios externos en transacciones distribuidas tipo saga.
Ejemplo — Saga Simplificada
BEGIN
-- Paso 1: Actualizar inventario
UPDATE inventario SET stock = stock - 1 WHERE item_id = 101;
-- Paso 2: Llamada a microservicio de facturación
BEGIN
UTL_HTTP.REQUEST('https://api.facturacion.com/generar', 'POST', '{"item":101}');
EXCEPTION
WHEN OTHERS THEN
-- Revertir inventario si falla facturación
UPDATE inventario SET stock = stock + 1 WHERE item_id = 101;
RAISE;
END;
COMMIT;
END;
Ventaja:
- Garantiza consistencia eventual sin depender de XA o middleware complicado.
- Cada paso maneja su propio rollback en caso de fallo.
5. Pattern: Bulk + Queue para Alta Concurrencia
Descripción
PL/SQL actúa como motor de procesamiento de lotes para microservicios, usando BULK COLLECT y FORALL para disminuir latencia y bloqueo.
Ejemplo
DECLARE
TYPE t_jobs IS TABLE OF job_queue%ROWTYPE;
v_jobs t_jobs;
BEGIN
SELECT * BULK COLLECT INTO v_jobs
FROM job_queue
WHERE status = 'PENDING';
FORALL i IN v_jobs.FIRST .. v_jobs.LAST
UPDATE job_queue
SET status = 'PROCESSING'
WHERE job_id = v_jobs(i).job_id;
-- Enviar a microservicio de procesamiento
FOR i IN v_jobs.FIRST .. v_jobs.LAST LOOP
UTL_HTTP.REQUEST('https://api.procesador.com/job', 'POST', '{"job_id":' || v_jobs(i).job_id || '}');
END LOOP;
COMMIT;
END;
Ventaja:
- Escalabilidad para cientos de miles de jobs diarios.
- Reducción de context switches.
- Control total desde Oracle, sin saturar microservicios externos.
6. Pattern: Orquestación de Lógica de Negocio Compleja
Descripción
Centralizar reglas críticas de negocio en PL/SQL y exponerlas a microservicios mediante funciones REST o colas, evitando duplicación en varios lenguajes.
Ejemplo — Motor de Reglas
CREATE OR REPLACE FUNCTION calcular_descuento(
p_cliente_id NUMBER,
p_monto NUMBER
) RETURN NUMBER AS
v_desc NUMBER := 0;
BEGIN
SELECT CASE
WHEN tipo_cliente = 'VIP' THEN p_monto * 0.15
WHEN tipo_cliente = 'REGULAR' THEN p_monto * 0.05
ELSE 0
END INTO v_desc
FROM clientes
WHERE cliente_id = p_cliente_id;
RETURN p_monto - v_desc;
END;
Ventaja:
- Microservicios externos llaman a la función vía REST.
- Evita inconsistencias entre sistemas.
- Toda la lógica de negocio permanece centralizada y auditada.
7. Pattern: Integración Híbrida con Legacy Systems
Descripción
PL/SQL orquesta interacciones entre microservicios modernos y sistemas legacy (bases antiguas, mainframes), actuando como puente.
Ejemplo — Adaptador de Legacy
DECLARE
v_data CLOB;
BEGIN
-- Extraer datos legacy vía DB Link
SELECT datos_xml INTO v_data FROM legacy_db.remote_table@DBLINK_LEGACY;
-- Transformar y enviar a microservicio
UTL_HTTP.REQUEST('https://api.nuevo.com/import', 'POST', v_data);
COMMIT;
END;
Ventaja:
- Evita reescribir sistemas antiguos.
- Centraliza integración y control de errores.
- Permite migración incremental a microservicios.
8. Pattern: Observabilidad / Logging Centralizado
Descripción
Todos los microservicios reportan eventos a Oracle, que centraliza logs, métricas y alertas usando procedimientos autónomos.
Ejemplo — Logging Autónomo
CREATE OR REPLACE PROCEDURE log_microservicio(
p_servicio VARCHAR2,
p_evento VARCHAR2
) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO log_microservicios(servicio, evento, fecha)
VALUES(p_servicio, p_evento, SYSTIMESTAMP);
COMMIT;
END;
Ventaja:
- Logs consistentes, independientes de transacciones externas.
- Facilita observabilidad y alertas en tiempo real.
- Ideal para microservicios distribuidos.
Conclusión
Estos patrones muestran cómo PL/SQL puede:
- Ser nodo central de orquestación.
- Gestionar eventos y colas para microservicios.
- Exponer REST / ORDS de forma segura.
- Mantener consistencia transaccional incluso en entornos distribuidos.
- Servir como motor de reglas de negocio y de procesamiento masivo.
Integrar microservicios con PL/SQL permite modernizar arquitectura sin sacrificar el poder y la consistencia de Oracle Database.
PL/SQL — Anti-Patterns Avanzados (Qué NO hacer en 2025)
1. Bloques Monolíticos Gigantes
Descripción
Escribir un único bloque con cientos de líneas, múltiples loops, DML y lógica de negocio mezclada.
Ejemplo
BEGIN
FOR i IN 1..10000 LOOP
UPDATE empleados SET salario = salario * 1.05 WHERE dept_id = i;
INSERT INTO log_emp VALUES(i, SYSDATE, 'update');
-- más lógica compleja, condiciones, llamadas a APIs
END LOOP;
COMMIT;
END;
`
Problemas:
- Difícil de mantener y depurar.
- Alta probabilidad de errores.
- Consume demasiados recursos y puede bloquear la base de datos.
Qué hacer en su lugar:
- Modularizar en procedimientos, funciones y paquetes.
- Usar BULK COLLECT / FORALL.
2. Cursor Row-by-Row (Slow-by-Slow / “Slow by Row”)
Descripción
Procesar fila por fila cuando hay miles o millones de registros, sin usar BULK COLLECT.
Ejemplo
DECLARE
v_name empleados.last_name%TYPE;
BEGIN
FOR rec IN (SELECT last_name FROM empleados) LOOP
-- Procesamiento fila a fila
v_name := rec.last_name;
DBMS_OUTPUT.PUT_LINE(v_name);
END LOOP;
END;
Problemas:
- Cambios de contexto SQL ↔ PL/SQL frecuentes.
- Rendimiento extremadamente bajo.
Qué hacer en su lugar:
- BULK COLLECT + FORALL o procesamiento en SQL directo.
3. Dynamic SQL sin Bind Variables
Descripción
Concatenar cadenas para construir consultas SQL dinámicas, incluyendo valores de entrada.
Ejemplo
DECLARE
v_sql VARCHAR2(4000);
v_count NUMBER;
BEGIN
v_sql := 'SELECT COUNT(*) FROM empleados WHERE dept_id = ' || :dept_id;
EXECUTE IMMEDIATE v_sql INTO v_count;
END;
Problemas:
- Vulnerable a SQL Injection.
- Pierde performance por falta de reutilización de plan de ejecución.
Qué hacer en su lugar:
- Usar bind variables con
EXECUTE IMMEDIATE … USING.
4. Excepciones Silenciosas
Descripción
Capturar todas las excepciones sin registrar ni manejar.
Ejemplo
BEGIN
UPDATE empleados SET salario = salario * 1.05;
EXCEPTION
WHEN OTHERS THEN
NULL; -- Ignora todos los errores
END;
Problemas:
- Dificulta debugging.
- Puede corromper datos o pasar errores inadvertidos a producción.
Qué hacer en su lugar:
- Manejar excepciones específicas.
- Registrar errores y tomar acciones correctivas.
5. Commit Frecuente o Dentro de Loops
Descripción
Ejecutar COMMIT dentro de un bucle fila por fila.
Ejemplo
BEGIN
FOR i IN 1..1000 LOOP
UPDATE empleados SET salario = salario * 1.05 WHERE emp_id = i;
COMMIT;
END LOOP;
END;
Problemas:
- Reduce performance.
- Fragmenta undo y redo.
- Difícil de revertir transacciones.
Qué hacer en su lugar:
- Hacer COMMIT fuera de loops, usar BULK.
6. Hardcoding de Parámetros / Valores Mágicos
Descripción
Incluir strings, números o rutas directamente en código PL/SQL.
Ejemplo
BEGIN
INSERT INTO log VALUES ('/home/oracle/logs/app.log', SYSDATE);
END;
Problemas:
- Difícil mantener entre entornos (dev, test, prod).
- Difícil de parametrizar.
Qué hacer en su lugar:
- Usar tablas de configuración, constantes o variables de entorno.
7. Dependencia Directa de Tablas Externas
Descripción
Hacer SELECT o DML directo en tablas de otros sistemas o legacy desde procesos críticos sin intermediarios.
Ejemplo
BEGIN
SELECT nombre INTO v_name FROM legacy_db.clientes@dblink;
END;
Problemas:
- Fallas externas detienen procesos críticos.
- Bloqueos y latencias inesperadas.
Qué hacer en su lugar:
- Replicar datos en tablas locales o usar colas/eventos.
8. Triggers Complejos y Multi-Nivel
Descripción
Triggers que disparan otros triggers, con lógica de negocio pesada.
Ejemplo
CREATE OR REPLACE TRIGGER trg_emp AFTER INSERT ON empleados
FOR EACH ROW
BEGIN
-- Hace múltiples llamadas, cálculos, updates
END;
Problemas:
- Difícil depuración.
- Riesgo de recursión infinita.
- Impacto severo en performance.
Qué hacer en su lugar:
- Usar procedimientos almacenados llamados explícitamente.
- Evitar lógica pesada en triggers.
9. Uso Excesivo de Autonomous Transactions
Descripción
Hacer commit autónomo en muchos lugares sin control.
Ejemplo
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO log VALUES('evento', SYSDATE);
COMMIT;
END;
Problemas:
- Dificulta rollback global.
- Puede corromper integridad de datos en transacciones distribuidas.
Qué hacer en su lugar:
- Usar autonómicos solo para logging crítico o auditoría.
- Mantener control central de transacciones.
10. Generación de Informes Dentro de PL/SQL con Lógica Compleja
Descripción
Crear PDFs, CSV o HTML en PL/SQL con loops y formateo masivo.
Problemas:**
- Consumo excesivo de CPU y memoria.
- Dificultad de mantenimiento.
- Mejor delegar a ETL o microservicios especializados.
Qué hacer en su lugar:
- Extraer datos desde PL/SQL y procesarlos en un microservicio o aplicación dedicada.
Conclusión
Evitar estos anti-patterns avanzados permite que tu PL/SQL sea:
- Mantenible y legible.
- Eficiente y escalable.
- Seguro y confiable.
Siempre modulariza, usa BULK, maneja errores correctamente y separa lógica de negocio de integraciones externas.
Guía Completa de Entrevistas PL/SQL (2025)
1. Conceptos Clave que Debes Dominar
- Diferencia SQL vs PL/SQL:
- SQL: Lenguaje declarativo para manipulación y consulta de datos.
- PL/SQL: Lenguaje procedimental que extiende SQL con variables, loops, condiciones, excepciones y subprogramas.
- Bloques PL/SQL:
- Anónimos, procedimientos, funciones, paquetes, triggers.
- Tipos de Datos:
- Escalares: NUMBER, VARCHAR2, DATE, BOOLEAN.
- %TYPE / %ROWTYPE para mantener compatibilidad con columnas y tablas.
- Control de flujo: IF, CASE, LOOP, WHILE, FOR, EXIT, GOTO (poco usado).
- Manejo de errores: Excepciones predefinidas (NO_DATA_FOUND, TOO_MANY_ROWS) y excepciones personalizadas.
- Colecciones y tipos avanzados:
- VARRAY, Nested Tables, Associative Arrays.
- Operaciones Bulk: BULK COLLECT / FORALL para optimizar procesamiento masivo.
- SQL dinámico: EXECUTE IMMEDIATE, DBMS_SQL para consultas flexibles.
- Paquetes: Encapsulan funciones, procedimientos, tipos y variables globales.
- Triggers: BEFORE, AFTER, INSTEAD OF; fila a fila o statement level.
- Integraciones: UTL_HTTP, UTL_FILE, DBMS_SCHEDULER, DBMS_ALERT, JSON/REST con ORDS.
2. Preguntas Técnicas Comunes
SQL vs PL/SQL
- ¿Cuándo usar SQL y cuándo PL/SQL?
- Ejemplo: INSERT masivo, cálculo de comisiones, transformaciones de datos.
Bloques y Procedimientos
- Diferencia entre procedimiento y función.
- Ventajas de usar paquetes.
Manejo de Errores
- ¿Cómo se captura una excepción en PL/SQL?
- Diferencia entre excepciones predefinidas y definidas por el usuario.
- Ejemplo: manejo de NO_DATA_FOUND en SELECT INTO.
Optimización
- ¿Qué es un BULK COLLECT y cuándo usarlo?
- ¿Cómo evitar context switches SQL ↔ PL/SQL?
Cursores
- Diferencia entre cursores implícitos y explícitos.
- Cómo recorrer resultados y liberar recursos.
SQL Dinámico
- Ventajas de EXECUTE IMMEDIATE vs DBMS_SQL.
- Uso seguro con bind variables para evitar SQL Injection.
Triggers
- Tipos de triggers y ejemplos de uso.
- Riesgos de triggers complejos y recursivos.
Integraciones
- ¿Cómo se envía un HTTP POST desde PL/SQL?
- Uso de UTL_FILE para generación de CSV o logs.
- Integración con JSON y REST usando ORDS.
3. Preguntas Avanzadas / Escenarios Reales
- Diseñar un procedimiento que calcule bonificaciones y guarde resultados en tabla histórica.
- Detectar cambios en tablas críticas y almacenar auditoría (trigger + tabla).
- Procesar millones de registros sin saturar memoria (bulk collect + forall).
- Exponer una función PL/SQL a microservicios mediante REST.
- Integrar PL/SQL con sistemas legacy o APIs externas sin perder consistencia.
- Crear un motor de reglas dinámico configurable desde JSON.
4. Preguntas de Optimización y Buenas Prácticas
- Diferencia entre row-by-row y BULK processing.
- Cuándo usar paquetes vs procedimientos sueltos.
- Cómo evitar locks y deadlocks en transacciones masivas.
- Uso adecuado de commit, autononomous transaction y manejo de rollback.
- Evitar triggers complejos que disparen otros triggers.
5. Preguntas de Diseño y Arquitectura
- Cómo diseñar un paquete para lógica de negocio reutilizable.
- Cómo exponer PL/SQL a microservicios sin duplicar lógica.
- Diseño de auditoría o logs centralizados.
- Patrones de ETL internos con pipelines, bulk y cache de resultados.
- Integración con ORDS y RESTful services.
6. Ejercicios Prácticos Comunes
- Escribir un procedimiento que:
- Seleccione clientes con contratos próximos a vencer.
- Genere CSV con sus datos.
- Inserte log de envío de notificaciones.
- Crear un trigger que:
- Detecte cambios de saldo en cuentas bancarias.
- Inserte registro de auditoría.
-
Optimizar un loop que actualiza 1 millón de registros en tabla
ventas. - Generar un motor de scoring que:
- Reciba parámetros dinámicos.
- Devuelva calificación calculada según reglas configurables en JSON.
7. Recursos para Preparación
-
[PL/SQL para desarrolladores Oracle España](https://www.oracle.com/es/database/technologies/appdev/plsql.html) - Oracle Database PL/SQL Language Reference 2025.
- Oracle Live SQL — Practicar ejercicios online.
- Cursos online: OpenWebinars, Udemy, Coursera.
- Libros recomendados: Oracle PL/SQL Programming de Steven Feuerstein, última edición.
8. Tips Finales para la Entrevista
- Sé capaz de explicar tus decisiones de diseño y optimización.
- Familiarízate con casos reales: comisiones, auditoría, ETL, integración microservicios.
- Practica escribir procedimientos, funciones, triggers y paquetes en Oracle Live SQL.
- Prepárate para preguntas sobre errores comunes y anti-patterns.
- Explica cómo mantienes consistencia y performance en sistemas críticos.
PL/SQL — Respuestas y Hoja de Trucos para Entrevistas (2025)
1. Conceptos Clave — Respuestas Rápidas
- SQL vs PL/SQL:
- SQL: declarativo, solo consulta/manipula datos.
- PL/SQL: procedimental, combina SQL con variables, loops, excepciones y subprogramas.
- Bloques PL/SQL:
- Anónimo: Ejecutable inmediato, no reutilizable.
- Procedimiento: Realiza acciones, puede recibir parámetros, no devuelve valor.
- Función: Devuelve un valor, se puede usar en SQL.
- Paquete: Agrupa procedimientos, funciones, tipos y variables globales.
- Trigger: Ejecuta lógica automáticamente ante eventos DML o DDL.
- Tipos de Datos:
- Escalares: NUMBER, VARCHAR2, DATE, BOOLEAN.
%TYPE / %ROWTYPE: para mantener compatibilidad automática con columnas y tablas.
- Control de flujo: IF, CASE, LOOP, WHILE, FOR, EXIT.
- Manejo de errores: Excepciones predefinidas (NO_DATA_FOUND, TOO_MANY_ROWS), excepciones definidas por usuario.
- Colecciones: VARRAY, Nested Tables, Associative Arrays.
- Operaciones Bulk: BULK COLLECT y FORALL para optimización de procesamiento masivo.
- SQL dinámico: EXECUTE IMMEDIATE + bind variables para seguridad y performance.
- Integraciones: UTL_HTTP, UTL_FILE, DBMS_SCHEDULER, DBMS_ALERT, JSON, REST/ORDS.
2. Preguntas Técnicas — Respuestas Cortas
- Diferencia SQL vs PL/SQL: SQL = consulta; PL/SQL = lógica + SQL.
- Procedimiento vs Función: Procedimiento = no retorna valor; Función = retorna valor.
- Paquetes: Encapsulan y organizan código, permiten variables globales, modularidad y mantenimiento.
- Excepciones: NO_DATA_FOUND captura SELECT INTO vacío; TOO_MANY_ROWS captura más de una fila.
- BULK COLLECT / FORALL: Para evitar procesamiento fila a fila y context switches SQL↔PL/SQL.
- Cursor implícito vs explícito: Implícito = automático en SELECT INTO; explícito = OPEN/FETCH/LOOP/ CLOSE.
- SQL Dinámico: Usa bind variables para seguridad y plan reutilizable.
- Trigger: Evitar lógica pesada y recursión.
3. Escenarios Reales — Respuestas / Tips
- Procedimiento de bonificaciones: Usar BULK COLLECT para leer empleados, FORALL para updates masivos.
- Auditoría en tabla histórica: Trigger AFTER INSERT/UPDATE + autononomous transaction para logging seguro.
- Procesamiento millones de registros: Bulk + FORALL, evitar row-by-row.
- Exposición a microservicios: ORDS REST endpoints para funciones PL/SQL.
- Motor de reglas dinámico: Almacenar reglas en JSON + EXECUTE IMMEDIATE seguro con bind.
4. Optimización — Trucos
- Evitar loops fila a fila → BULK COLLECT / FORALL.
- Commit fuera de loops; autonómicos solo para logging/auditoría.
- Usar paquetes para centralizar lógica.
- Evitar triggers multi-nivel complejos.
- SQL dinámico = bind variables.
- Profiling: DBMS_PROFILER, DBMS_TRACE.
- Result Cache para cálculos repetitivos.
5. Diseño / Arquitectura — Hoja de Trucos
- Orquestación Centralizada: PL/SQL coordina microservicios y transacciones.
- Event-Driven: Tabla de colas + triggers → microservicios reaccionan a eventos.
- API Gateway / ORDS: Exponer procedimientos y funciones como REST.
- Saga / Transacciones Distribuidas: Cada paso controlado; rollback parcial si falla.
- Bulk + Queue: Procesamiento masivo eficiente.
- Motor de reglas: JSON configurable; función PL/SQL centralizada.
- Integración con legacy: DB Link o ETL incremental.
- Logging centralizado: Pragma autonomous_transaction para logs independientes.
6. Anti-Patterns — Recordatorio
- Bloques monolíticos gigantes → modularizar.
- Row-by-row loops → BULK COLLECT / FORALL.
- Dynamic SQL sin bind → riesgo SQL Injection.
- Excepciones silenciosas → siempre manejar y loggear.
- Commit dentro de loops → mover fuera.
- Hardcoding → usar tablas de configuración.
- Dependencia directa en sistemas externos → replicar/localizar datos.
- Triggers complejos multi-nivel → usar procedimientos explícitos.
- Autonómicos excesivos → solo logs críticos.
- Informes complejos dentro de PL/SQL → delegar a microservicios o ETL.
7. Ejercicios Comunes — Respuestas Rápidas
- Clientes próximos a vencer: SELECT INTO BULK COLLECT, generar CSV con UTL_FILE, log con autonómicos.
- Trigger auditoría: AFTER UPDATE → insert en tabla log.
- Optimización loop 1 millón registros: BULK COLLECT + FORALL + COMMIT en batches.
- Motor de scoring dinámico: JSON reglas + EXECUTE IMMEDIATE + bind.
8. Atajos y Comandos Útiles
DECLARE ... BEGIN ... END;→ bloque anónimo.CREATE OR REPLACE PROCEDURE nombre IS ... END;→ procedimiento.CREATE OR REPLACE FUNCTION nombre RETURN tipo IS ... END;→ función.%TYPE / %ROWTYPE→ mantiene consistencia de tipos.BULK COLLECT INTO→ cargar varias filas en colecciones.FORALL→ ejecutar DML masivo.EXECUTE IMMEDIATE→ SQL dinámico.DBMS_OUTPUT.PUT_LINE()→ debug.PRAGMA AUTONOMOUS_TRANSACTION→ commit independiente.DBMS_PROFILER/DBMS_TRACE→ perfilado de performance.ORDS→ exponer funciones como REST.JSON_OBJECT_T/JSON_ARRAY_T→ manipulación JSON en PL/SQL.
Tip final:
Antes de la entrevista, repasar:
- Sintaxis rápida de bloque/procedimiento/función/paquete.
- Ejemplos BULK COLLECT / FORALL.
- Manejo de excepciones comunes y custom.
- Triggers simples vs complejos y cómo evitarlos.
- Casos de integración microservicios / REST / JSON.
- Anti-patterns para mostrar conocimiento avanzado y buenas prácticas.
¿Te gusta este contenido? Suscríbete vía RSS