Skip to content

3. Manipulación de Datos (DML)

Manipulación de Datos (DML – Data Manipulation Language)

Section titled “Manipulación de Datos (DML – Data Manipulation Language)”

El Lenguaje de Manipulación de Datos (DML) es un subconjunto de SQL que permite a los usuarios insertar, consultar, actualizar y eliminar datos en una base de datos. Estas operaciones son fundamentales para interactuar con los datos almacenados en las tablas.

El comando INSERT permite añadir nuevos registros a una tabla existente.

INSERT INTO nombre_tabla [(columna1, columna2, ...)] VALUES (valor1, valor2, ...);
-- Insertar un registro especificando todas las columnas
INSERT INTO empleados (id_empleado, nombre, apellido, email, fecha_contratacion, salario)
VALUES (1, 'Juan', 'Pérez', 'juan.perez@ejemplo.com', '2023-01-15', 35000.00);
-- Insertar un registro sin especificar columnas (debe seguir el orden de las columnas en la tabla)
INSERT INTO departamentos
VALUES (1, 'Ventas', 'Edificio A', 101);
-- Insertar ignorando duplicados
INSERT IGNORE INTO clientes (id_cliente, nombre, email)
VALUES (1, 'Ana García', 'ana@ejemplo.com');
-- Insertar o actualizar si existe (UPSERT)
INSERT INTO productos (id_producto, nombre, precio, stock)
VALUES (101, 'Teclado mecánico', 89.99, 30)
ON DUPLICATE KEY UPDATE
precio = VALUES(precio),
stock = stock + VALUES(stock);

El comando SELECT es uno de los más utilizados en SQL y permite recuperar datos de una o más tablas.

SELECT [DISTINCT] columna1, columna2, ...
FROM nombre_tabla
[WHERE condicion]
[GROUP BY columnas]
[HAVING condicion_grupo]
[ORDER BY columnas [ASC|DESC]]
[LIMIT n];
-- Seleccionar todas las columnas de una tabla
SELECT * FROM empleados;
-- Seleccionar columnas específicas
SELECT nombre, apellido, salario FROM empleados;
-- Seleccionar con alias de columna
SELECT
nombre AS nombre_empleado,
salario AS salario_mensual,
salario * 12 AS salario_anual
FROM empleados;
-- Obtener departamentos únicos donde trabajan empleados
SELECT DISTINCT departamento_id FROM empleados;
-- Combinaciones únicas de departamento y cargo
SELECT DISTINCT departamento_id, cargo FROM empleados;
-- Contar registros
SELECT COUNT(*) AS total_empleados FROM empleados;
-- Calcular suma, promedio, máximo y mínimo
SELECT
SUM(salario) AS suma_salarios,
AVG(salario) AS promedio_salario,
MAX(salario) AS salario_maximo,
MIN(salario) AS salario_minimo
FROM empleados;
-- Contar empleados por departamento
SELECT
departamento_id,
COUNT(*) AS num_empleados
FROM empleados
GROUP BY departamento_id;
-- Calcular salario promedio por departamento y cargo
SELECT
departamento_id,
cargo,
AVG(salario) AS salario_promedio
FROM empleados
GROUP BY departamento_id, cargo;
-- Encontrar departamentos con más de 5 empleados
SELECT
departamento_id,
COUNT(*) AS num_empleados
FROM empleados
GROUP BY departamento_id
HAVING COUNT(*) > 5;

La cláusula WHERE permite filtrar los registros que cumplen con una condición específica.

-- Igualdad
SELECT * FROM empleados WHERE departamento_id = 3;
-- Desigualdad
SELECT * FROM empleados WHERE salario > 50000;
SELECT * FROM productos WHERE categoria_id != 5;
-- Comparaciones
SELECT * FROM pedidos WHERE fecha_pedido >= '2023-01-01';
SELECT * FROM productos WHERE stock <= 10;
-- AND: ambas condiciones deben ser verdaderas
SELECT * FROM empleados
WHERE departamento_id = 3 AND salario > 40000;
-- OR: al menos una condición debe ser verdadera
SELECT * FROM productos
WHERE categoria_id = 1 OR categoria_id = 2;
-- NOT: niega una condición
SELECT * FROM clientes
WHERE NOT ciudad = 'Madrid';
-- Valores dentro de un rango (inclusivo)
SELECT * FROM productos
WHERE precio BETWEEN 10.00 AND 50.00;
-- Fechas dentro de un rango
SELECT * FROM pedidos
WHERE fecha_pedido BETWEEN '2023-01-01' AND '2023-03-31';
-- Valores que coinciden con cualquiera en una lista
SELECT * FROM empleados
WHERE departamento_id IN (1, 3, 5);
-- Subconsulta con IN
SELECT * FROM productos
WHERE categoria_id IN (SELECT id_categoria FROM categorias WHERE activo = 1);
-- Coincidencia de patrones con comodín %
SELECT * FROM empleados WHERE nombre LIKE 'Mar%'; -- Nombres que empiezan con "Mar"
SELECT * FROM productos WHERE descripcion LIKE '%portátil%'; -- Contiene "portátil"
SELECT * FROM clientes WHERE email LIKE '%@gmail.com'; -- Termina con "@gmail.com"
-- Comodín _ (un solo carácter)
SELECT * FROM empleados WHERE codigo LIKE 'E-___'; -- E- seguido de exactamente 3 caracteres
-- Encontrar valores nulos
SELECT * FROM empleados WHERE fecha_baja IS NULL;
-- Encontrar valores no nulos
SELECT * FROM clientes WHERE telefono IS NOT NULL;
-- Búsqueda de texto completo (requiere índice FULLTEXT)
SELECT * FROM articulos
WHERE MATCH(titulo, contenido) AGAINST('inteligencia artificial');
-- Expresiones regulares
SELECT * FROM productos
WHERE nombre REGEXP '^[A-Z][0-9]';

La cláusula ORDER BY permite ordenar los resultados de una consulta según una o más columnas.

SELECT columna1, columna2, ...
FROM nombre_tabla
[WHERE condicion]
ORDER BY columna1 [ASC|DESC], columna2 [ASC|DESC], ...;
-- Ordenar por una columna (ascendente por defecto)
SELECT nombre, apellido, salario FROM empleados
ORDER BY salario;
-- Ordenar de forma descendente
SELECT nombre, apellido, salario FROM empleados
ORDER BY salario DESC;
-- Ordenar por múltiples columnas
SELECT nombre, apellido, departamento_id, salario FROM empleados
ORDER BY departamento_id ASC, salario DESC;
-- Ordenar por la segunda columna seleccionada
SELECT nombre, fecha_contratacion, salario FROM empleados
ORDER BY 2 DESC; -- Ordena por fecha_contratacion descendente
-- Ordenar por una expresión calculada
SELECT
nombre,
apellido,
salario,
salario * 1.1 AS salario_con_aumento
FROM empleados
ORDER BY salario * 1.1 DESC;
-- También se puede ordenar por el alias
SELECT
nombre,
apellido,
salario,
salario * 1.1 AS salario_con_aumento
FROM empleados
ORDER BY salario_con_aumento DESC;
-- En MySQL, NULL se considera menor que cualquier valor no NULL
-- Por defecto, los NULL aparecen primero en orden ASC
-- Colocar NULL al final en ordenación ascendente
SELECT nombre, fecha_baja FROM empleados
ORDER BY fecha_baja IS NULL, fecha_baja ASC;

3.5. Limitar resultados (LIMIT en MySQL, ROWNUM en Oracle)

Section titled “3.5. Limitar resultados (LIMIT en MySQL, ROWNUM en Oracle)”

A menudo es útil limitar el número de filas devueltas por una consulta, especialmente cuando se trabaja con grandes conjuntos de datos.

-- Obtener los primeros 10 registros
SELECT * FROM productos
ORDER BY precio DESC
LIMIT 10;
-- Paginación: obtener registros del 11 al 20
-- LIMIT [offset], [count]
SELECT * FROM productos
ORDER BY precio DESC
LIMIT 10, 10;
-- Sintaxis alternativa para paginación
SELECT * FROM productos
ORDER BY precio DESC
LIMIT 10 OFFSET 10;

El comando UPDATE permite modificar datos existentes en una tabla.

UPDATE nombre_tabla
SET columna1 = valor1, columna2 = valor2, ...
[WHERE condicion];
-- Actualizar un solo registro
UPDATE empleados
SET salario = 55000
WHERE id_empleado = 101;
-- Actualizar múltiples columnas
UPDATE clientes
SET
telefono = '555-123-4567',
direccion = 'Calle Nueva 123',
fecha_actualizacion = CURRENT_DATE
WHERE id_cliente = 25;
-- Actualizar múltiples registros
UPDATE productos
SET precio = precio * 1.1
WHERE categoria_id = 3;
-- Actualizar basado en datos de otra tabla
UPDATE productos p
SET p.precio = p.precio * 1.2
WHERE p.categoria_id IN (
SELECT id_categoria
FROM categorias
WHERE nombre = 'Electrónica'
);
-- Actualizar con JOIN en MySQL
UPDATE productos p
JOIN categorias c ON p.categoria_id = c.id_categoria
SET p.precio = p.precio * 1.2
WHERE c.nombre = 'Electrónica';
-- Actualizar múltiples tablas
UPDATE pedidos p, detalles_pedido dp
SET
p.estado = 'Completado',
dp.estado_linea = 'Enviado'
WHERE p.id_pedido = dp.id_pedido
AND p.id_pedido = 1001;

El comando DELETE permite eliminar registros existentes de una tabla.

DELETE FROM nombre_tabla
[WHERE condicion];
-- Eliminar un registro específico
DELETE FROM clientes
WHERE id_cliente = 1001;
-- Eliminar múltiples registros
DELETE FROM productos
WHERE categoria_id = 5 AND stock = 0;
-- Eliminar registros basados en una fecha
DELETE FROM registros_log
WHERE fecha_registro < '2023-01-01';
-- Eliminar registros basados en datos de otra tabla
DELETE FROM pedidos
WHERE cliente_id IN (
SELECT id_cliente
FROM clientes
WHERE fecha_ultima_compra < '2020-01-01'
);
-- Eliminar con JOIN
DELETE p
FROM pedidos p
JOIN clientes c ON p.cliente_id = c.id_cliente
WHERE c.fecha_ultima_compra < '2020-01-01';
-- Eliminar con límite
DELETE FROM registros_log
ORDER BY fecha_registro
LIMIT 1000;
  • Es una operación DML (Data Manipulation Language)
  • Puede usar cláusula WHERE para eliminar registros específicos
  • Registra cada eliminación en el log de transacciones
  • Se puede hacer rollback
  • Activa disparadores (triggers)
  • No reinicia contadores de secuencia/autoincremento
  • Más lento para eliminar todos los registros

En muchas aplicaciones empresariales, es común implementar una “eliminación lógica” en lugar de eliminar físicamente los registros:

-- Estructura de tabla con columna para eliminación lógica
CREATE TABLE clientes (
id_cliente INT PRIMARY KEY,
nombre VARCHAR(100),
activo BOOLEAN DEFAULT TRUE, -- o bit, tinyint, etc.
fecha_eliminacion DATETIME NULL
);
-- "Eliminar" lógicamente un cliente
UPDATE clientes
SET
activo = FALSE,
fecha_eliminacion = CURRENT_TIMESTAMP
WHERE id_cliente = 1001;
-- Consultar solo clientes activos
SELECT * FROM clientes WHERE activo = TRUE;
🐝