5. DML (Data Manipulation Language)
Introducción al DML
Section titled “Introducción al DML”El Lenguaje de Manipulación de Datos (Data Manipulation Language o DML) es un subconjunto de SQL utilizado para manipular los datos almacenados en una base de datos Oracle. Los comandos DML permiten insertar, actualizar, eliminar y consultar datos en tablas y vistas.
Características principales del DML
Section titled “Características principales del DML”- Transaccional: Los comandos DML forman parte de transacciones que pueden confirmarse (COMMIT) o revertirse (ROLLBACK)
- Afecta a los datos: Modifica el contenido de las tablas, no su estructura
- Genera redo/undo: Oracle registra la información necesaria para rehacer o deshacer los cambios
- Puede activar triggers: Los comandos DML pueden disparar triggers definidos en las tablas
INSERT - Inserción de registros
Section titled “INSERT - Inserción de registros”El comando INSERT se utiliza para agregar nuevas filas a una tabla o vista.
Sintaxis básica
Section titled “Sintaxis básica”-- Sintaxis básicaINSERT INTO tabla [(columna1, columna2, ...)]VALUES (valor1, valor2, ...);
-- Ejemplo simpleINSERT INTO empleados (empleado_id, nombre, apellido, email, fecha_contratacion)VALUES (1, 'Juan', 'Pérez', 'juan.perez@ejemplo.com', SYSDATE);Inserción de múltiples filas
Section titled “Inserción de múltiples filas”-- Insertar múltiples filas en una sola sentenciaINSERT ALL INTO empleados (empleado_id, nombre, apellido) VALUES (1, 'Juan', 'Pérez') INTO empleados (empleado_id, nombre, apellido) VALUES (2, 'María', 'Gómez') INTO empleados (empleado_id, nombre, apellido) VALUES (3, 'Carlos', 'López')SELECT * FROM dual;-- Inserción condicional en diferentes tablasINSERT ALL WHEN salario > 5000 THEN INTO empleados_senior (empleado_id, nombre, salario) VALUES (id, nombre, salario) WHEN salario <= 5000 THEN INTO empleados_junior (empleado_id, nombre, salario) VALUES (id, nombre, salario)SELECT id, nombre, salario FROM candidatos;Inserción basada en consulta
Section titled “Inserción basada en consulta”-- Insertar datos desde otra tablaINSERT INTO empleados_marketing (empleado_id, nombre, apellido, email)SELECT empleado_id, nombre, apellido, emailFROM empleadosWHERE departamento_id = 20;
-- Insertar con subconsulta para obtener valoresINSERT INTO salarios (empleado_id, salario, fecha_revision)VALUES ( (SELECT empleado_id FROM empleados WHERE email = 'juan.perez@ejemplo.com'), 5000, ADD_MONTHS(SYSDATE, 6));Inserción con valores por defecto y nulos
Section titled “Inserción con valores por defecto y nulos”-- Uso de valores por defectoINSERT INTO empleados (empleado_id, nombre, apellido)VALUES (seq_empleados.NEXTVAL, 'Ana', 'Martínez');-- Las columnas no especificadas recibirán NULL o su valor DEFAULT si está definido
-- Especificar NULL explícitamenteINSERT INTO empleados (empleado_id, nombre, apellido, telefono)VALUES (seq_empleados.NEXTVAL, 'Pedro', 'Sánchez', NULL);Errores comunes en INSERT
Section titled “Errores comunes en INSERT”-
Violación de restricción de unicidad
- Ocurre al intentar insertar un valor duplicado en una columna con restricción UNIQUE o PRIMARY KEY
- Error: ORA-00001: unique constraint violated
-
Violación de restricción de integridad referencial
- Ocurre al intentar insertar un valor en una columna con restricción FOREIGN KEY que no existe en la tabla referenciada
- Error: ORA-02291: integrity constraint violated - parent key not found
-
Violación de restricción CHECK
- Ocurre al intentar insertar un valor que no cumple con una restricción CHECK
- Error: ORA-02290: check constraint violated
-
Columna NOT NULL sin valor
- Ocurre al omitir una columna con restricción NOT NULL sin valor DEFAULT
- Error: ORA-01400: cannot insert NULL into column
UPDATE - Actualización de datos
Section titled “UPDATE - Actualización de datos”El comando UPDATE se utiliza para modificar datos existentes en una tabla o vista.
Sintaxis básica
Section titled “Sintaxis básica”-- Sintaxis básicaUPDATE tablaSET columna1 = valor1, columna2 = valor2, ...[WHERE condición];
-- Ejemplo simpleUPDATE empleadosSET salario = 5500WHERE empleado_id = 101;Actualización con subconsultas
Section titled “Actualización con subconsultas”-- Actualizar basado en datos de otra tablaUPDATE empleados eSET e.salario = e.salario * 1.1WHERE e.departamento_id IN ( SELECT departamento_id FROM departamentos WHERE ubicacion = 'Madrid');
-- Actualizar múltiples columnas con subconsultasUPDATE empleados eSET (e.salario, e.comision) = ( SELECT AVG(salario) * 0.9, AVG(salario) * 0.05 FROM empleados WHERE departamento_id = e.departamento_id)WHERE e.rendimiento = 'En formación';Actualización con expresiones
Section titled “Actualización con expresiones”-- Actualizar usando valores existentesUPDATE productosSET precio = precio * 1.05, ultima_actualizacion = SYSDATE, descripcion = UPPER(descripcion)WHERE categoria = 'Electrónica';
-- Actualizar con expresiones condicionalesUPDATE empleadosSET salario = CASE WHEN antiguedad < 2 THEN salario * 1.03 WHEN antiguedad BETWEEN 2 AND 5 THEN salario * 1.05 ELSE salario * 1.07 END, nivel = CASE WHEN salario * 1.07 > 10000 THEN 'Senior' ELSE nivel ENDWHERE departamento_id = 10;Actualización con valores NULL
Section titled “Actualización con valores NULL”-- Establecer valores a NULLUPDATE empleadosSET telefono = NULLWHERE fecha_baja IS NOT NULL;
-- Reemplazar NULL con un valorUPDATE empleadosSET comision = 0WHERE comision IS NULL;DELETE - Eliminación de registros
Section titled “DELETE - Eliminación de registros”El comando DELETE se utiliza para eliminar filas existentes de una tabla o vista.
Sintaxis básica
Section titled “Sintaxis básica”-- Sintaxis básicaDELETE FROM tabla[WHERE condición];
-- Ejemplo simpleDELETE FROM empleadosWHERE empleado_id = 101;Eliminación con subconsultas
Section titled “Eliminación con subconsultas”-- Eliminar basado en datos de otra tablaDELETE FROM empleadosWHERE departamento_id IN ( SELECT departamento_id FROM departamentos WHERE presupuesto < 50000);
-- Eliminar con EXISTSDELETE FROM pedidos pWHERE EXISTS ( SELECT 1 FROM clientes c WHERE c.cliente_id = p.cliente_id AND c.estado = 'Inactivo');Diferencias entre DELETE y TRUNCATE
Section titled “Diferencias entre DELETE y TRUNCATE”| Característica | DELETE | TRUNCATE |
|---|---|---|
| Tipo de comando | DML | DDL |
| Cláusula WHERE | Permitida | No permitida |
| Transaccional | Sí | No (commit automático) |
| Rollback | Posible | No posible |
| Triggers | Se activan | No se activan |
| Velocidad | Más lento | Más rápido |
| Espacio | No libera automáticamente | Libera espacio |
MERGE - Operaciones de upsert
Section titled “MERGE - Operaciones de upsert”El comando MERGE combina las operaciones INSERT y UPDATE en una sola sentencia, permitiendo insertar nuevas filas o actualizar filas existentes en función de una condición.
Sintaxis básica
Section titled “Sintaxis básica”-- Sintaxis básicaMERGE INTO tabla_destino destUSING tabla_origen origON (condición_de_coincidencia)WHEN MATCHED THEN UPDATE SET columna1 = valor1, columna2 = valor2, ... [WHERE condición_update] [DELETE WHERE condición_delete]WHEN NOT MATCHED THEN INSERT (columna1, columna2, ...) VALUES (valor1, valor2, ...) [WHERE condición_insert];Ejemplo práctico
Section titled “Ejemplo práctico”-- Actualizar inventario desde tabla de envíosMERGE INTO inventario iUSING envios eON (i.producto_id = e.producto_id)WHEN MATCHED THEN UPDATE SET i.cantidad = i.cantidad + e.cantidad, i.ultima_actualizacion = SYSDATE WHERE e.fecha_envio > i.ultima_actualizacionWHEN NOT MATCHED THEN INSERT (producto_id, cantidad, ultima_actualizacion) VALUES (e.producto_id, e.cantidad, SYSDATE) WHERE e.cantidad > 0;Casos de uso comunes para MERGE
Section titled “Casos de uso comunes para MERGE”-
Sincronización de datos
- Actualizar una tabla de destino con datos de una tabla de origen, insertando nuevos registros y actualizando los existentes
-
Carga de datos ETL
- Procesos de extracción, transformación y carga donde se necesita actualizar datos existentes e insertar nuevos
-
Actualización de tablas de dimensiones
- En almacenes de datos, para mantener actualizadas las tablas de dimensiones con nuevos miembros
-
Procesamiento de lotes
- Procesar lotes de transacciones donde algunas son nuevas y otras son actualizaciones
Consultas básicas con SELECT
Section titled “Consultas básicas con SELECT”El comando SELECT se utiliza para recuperar datos de una o más tablas.
Sintaxis básica
Section titled “Sintaxis básica”-- Sintaxis básicaSELECT [DISTINCT] columna1, columna2, ...FROM tabla[WHERE condición][GROUP BY columnas][HAVING condición_grupo][ORDER BY columnas [ASC|DESC]];
-- Ejemplo simpleSELECT empleado_id, nombre, apellido, salarioFROM empleadosWHERE departamento_id = 10ORDER BY salario DESC;Proyección: Selección de columnas
Section titled “Proyección: Selección de columnas”-- Seleccionar todas las columnasSELECT * FROM empleados;
-- Seleccionar columnas específicasSELECT nombre, apellido, email FROM empleados;
-- Columnas calculadasSELECT nombre, salario, salario * 1.1 AS nuevo_salario, salario * 12 AS salario_anualFROM empleados;
-- Concatenación de columnasSELECT empleado_id, nombre || ' ' || apellido AS nombre_completo, 'Empleado: ' || nombre AS descripcionFROM empleados;Filtrado: Cláusula WHERE
Section titled “Filtrado: Cláusula WHERE”-- IgualdadSELECT * FROM empleados WHERE departamento_id = 20;
-- DesigualdadSELECT * FROM empleados WHERE salario > 5000;
-- RangoSELECT * FROM empleados WHERE salario BETWEEN 3000 AND 6000;
-- Lista de valoresSELECT * FROM empleados WHERE departamento_id IN (10, 20, 30);
-- PatronesSELECT * FROM empleados WHERE nombre LIKE 'J%';-- ANDSELECT * FROM empleadosWHERE departamento_id = 20 AND salario > 5000;
-- ORSELECT * FROM empleadosWHERE departamento_id = 10 OR departamento_id = 20;
-- NOTSELECT * FROM empleadosWHERE NOT (departamento_id = 30);
-- CombinaciónSELECT * FROM empleadosWHERE (departamento_id = 10 OR departamento_id = 20)AND salario > 5000;-- Buscar valores NULLSELECT * FROM empleados WHERE comision IS NULL;
-- Buscar valores no NULLSELECT * FROM empleados WHERE comision IS NOT NULL;Ordenamiento: Cláusula ORDER BY
Section titled “Ordenamiento: Cláusula ORDER BY”-- Ordenar por una columna ascendente (predeterminado)SELECT * FROM empleados ORDER BY apellido;
-- Ordenar por una columna descendenteSELECT * FROM empleados ORDER BY salario DESC;
-- Ordenar por múltiples columnasSELECT * FROM empleadosORDER BY departamento_id, salario DESC;
-- Ordenar por posición de columnaSELECT empleado_id, nombre, apellido FROM empleadosORDER BY 3; -- Ordena por la tercera columna (apellido)
-- Ordenar por expresiónSELECT empleado_id, nombre, salario FROM empleadosORDER BY salario * 12 DESC;Eliminación de duplicados: DISTINCT
Section titled “Eliminación de duplicados: DISTINCT”-- Eliminar valores duplicadosSELECT DISTINCT departamento_id FROM empleados;
-- DISTINCT con múltiples columnasSELECT DISTINCT departamento_id, puesto FROM empleados;Funciones de fila
Section titled “Funciones de fila”-- Mayúsculas y minúsculasSELECT UPPER(nombre) AS nombre_mayusculas, LOWER(email) AS email_minusculas, INITCAP(apellido) AS apellido_capitalizadoFROM empleados;
-- Manipulación de cadenasSELECT SUBSTR(nombre, 1, 3) AS iniciales, LENGTH(nombre) AS longitud_nombre, REPLACE(email, '@ejemplo.com', '@nuevaempresa.com') AS nuevo_email, LPAD(empleado_id, 5, '0') AS id_formateadoFROM empleados;-- RedondeoSELECT salario, ROUND(salario, -2) AS redondeado_centenas, TRUNC(salario, -3) AS truncado_miles, CEIL(salario) AS techo, FLOOR(salario) AS pisoFROM empleados;
-- MatemáticasSELECT ABS(-salario) AS valor_absoluto, POWER(salario, 2) AS salario_cuadrado, SQRT(salario) AS raiz_cuadrada, MOD(salario, 1000) AS restoFROM empleados;-- Operaciones con fechasSELECT fecha_contratacion, ADD_MONTHS(fecha_contratacion, 6) AS revision_semestral, ADD_MONTHS(fecha_contratacion, 12) AS revision_anual, LAST_DAY(fecha_contratacion) AS fin_de_mes, NEXT_DAY(fecha_contratacion, 'LUNES') AS proximo_lunesFROM empleados;
-- Diferencias entre fechasSELECT fecha_contratacion, SYSDATE AS fecha_actual, ROUND(MONTHS_BETWEEN(SYSDATE, fecha_contratacion)) AS meses_antiguedad, ROUND((SYSDATE - fecha_contratacion) / 365) AS años_antiguedadFROM empleados;-- Conversión de tiposSELECT TO_CHAR(fecha_contratacion, 'DD/MM/YYYY') AS fecha_formato_es, TO_CHAR(fecha_contratacion, 'Month DD, YYYY') AS fecha_larga, TO_CHAR(salario, '$999,999.99') AS salario_formateado, TO_DATE('01-01-2023', 'DD-MM-YYYY') AS fecha_convertida, TO_NUMBER('1,234.56', '9,999.99') AS numero_convertidoFROM empleados;Funciones de grupo y agregación
Section titled “Funciones de grupo y agregación”-- Funciones de agregación básicasSELECT COUNT(*) AS total_empleados, COUNT(comision) AS empleados_con_comision, SUM(salario) AS suma_salarios, AVG(salario) AS promedio_salario, MIN(salario) AS salario_minimo, MAX(salario) AS salario_maximo, STDDEV(salario) AS desviacion_estandarFROM empleados;
-- AgrupaciónSELECT departamento_id, COUNT(*) AS num_empleados, AVG(salario) AS salario_promedioFROM empleadosGROUP BY departamento_idORDER BY departamento_id;
-- Filtrado de grupos con HAVINGSELECT departamento_id, COUNT(*) AS num_empleados, AVG(salario) AS salario_promedioFROM empleadosGROUP BY departamento_idHAVING COUNT(*) > 5 AND AVG(salario) > 3000ORDER BY salario_promedio DESC;Transacciones en DML
Section titled “Transacciones en DML”Las transacciones son unidades lógicas de trabajo que agrupan una o más operaciones DML.
Control de transacciones
Section titled “Control de transacciones”-- Iniciar una transacción (implícito en Oracle)-- Realizar operaciones DMLINSERT INTO departamentos (departamento_id, nombre) VALUES (50, 'Marketing');INSERT INTO empleados (empleado_id, nombre, apellido, departamento_id) VALUES (201, 'Ana', 'García', 50);UPDATE empleados SET salario = 4000 WHERE empleado_id = 201;
-- Confirmar los cambiosCOMMIT;
-- O revertir los cambios-- ROLLBACK;Puntos de guardado (Savepoints)
Section titled “Puntos de guardado (Savepoints)”-- Iniciar transacciónINSERT INTO departamentos (departamento_id, nombre) VALUES (60, 'Investigación');
-- Crear un punto de guardadoSAVEPOINT sp1;
INSERT INTO empleados (empleado_id, nombre, apellido, departamento_id) VALUES (202, 'Carlos', 'Ruiz', 60);
-- Crear otro punto de guardadoSAVEPOINT sp2;
UPDATE empleados SET salario = 5000 WHERE empleado_id = 202;
-- Revertir hasta el punto de guardado sp2ROLLBACK TO SAVEPOINT sp2;
-- Confirmar los cambios restantesCOMMIT;Mejores prácticas para DML
Section titled “Mejores prácticas para DML”-
Usar transacciones adecuadamente
- Agrupe operaciones relacionadas en una sola transacción
- Mantenga las transacciones lo más cortas posible para evitar bloqueos prolongados
- Confirme (COMMIT) o revierta (ROLLBACK) explícitamente las transacciones
-
Optimizar operaciones masivas
- Use INSERT con múltiples filas o INSERT … SELECT para inserciones masivas
- Considere deshabilitar temporalmente índices y restricciones para cargas masivas
- Use MERGE para operaciones de upsert en lugar de lógica personalizada
-
Validar condiciones WHERE
- Siempre verifique las condiciones WHERE en UPDATE y DELETE
- Considere probar primero con un SELECT para verificar qué filas se verán afectadas
- Use transacciones para poder revertir cambios no deseados
-
Manejar errores adecuadamente
- Implemente manejo de excepciones en bloques PL/SQL
- Registre errores y realice acciones de recuperación cuando sea posible
- Considere usar savepoints para recuperación parcial
-
Considerar el rendimiento
- Evite subconsultas innecesarias en cláusulas WHERE
- Use índices apropiados para mejorar el rendimiento de las consultas
- Monitoree y optimice consultas lentas