DML: consultar y modificar
Las cinco sentencias que trabajan con las filas: la estructura completa del SELECT, la agrupación con GROUP BY y HAVING, las altas, las modificaciones, los borrados y la mezcla con MERGE.
Las sentencias del DML
El lenguaje de manipulación de datos es el que se usa a diario: consulta, inserta, modifica, borra y mezcla filas. La estructura de la tabla no la toca nunca, y por eso todo lo que hace se puede deshacer con un ROLLBACK mientras la transacción siga abierta.
- SELECT: consulta filas y no modifica nada.
- INSERT: da de alta filas nuevas.
- UPDATE: cambia valores de filas que ya existen.
- DELETE: da de baja filas.
- MERGE: mezcla una tabla origen sobre una destino, actualizando lo que ya está e insertando lo que falta.
Para el examen
Las cinco sentencias: SELECT, INSERT, UPDATE, DELETE y MERGE
Lo que nunca tocan: la estructura
Por eso: se deshacen con ROLLBACK mientras la transacción siga abierta
La estructura de un SELECT
El orden de las cláusulas de una consulta es fijo y no se puede alterar: primero qué columnas se quieren, de dónde salen, con qué se combinan, qué filas se filtran, cómo se agrupan, qué grupos se conservan y en qué orden se presenta el resultado.
SELECT DISTINCT a.nombre AS alumno, t.titulo AS tema
FROM intento i
JOIN alumno a ON a.id_alumno = i.id_alumno
JOIN tema t ON t.id_tema = i.id_tema
WHERE i.fallos > 5
ORDER BY a.nombre ASC, t.titulo DESC;- SELECT admite ALL, que es lo que se aplica si no se dice nada y conserva las filas repetidas, o DISTINCT, que elimina las repeticiones del resultado.
- AS da un alias a una columna o a una tabla. En las columnas es el nombre con el que aparece la cabecera; en las tablas es el prefijo corto con el que se cualifican las columnas y evita ambigüedades cuando dos tablas tienen columnas del mismo nombre.
- FROM acepta tablas y también vistas: para el que consulta son indistinguibles.
- WHERE filtra filas y admite condiciones encadenadas con AND, OR y NOT.
- ORDER BY ordena el resultado, ascendente por defecto (ASC) o descendente (DESC), y se puede ordenar por varias columnas.
Sin ORDER BY explícito, el orden de las filas de un resultado no está garantizado, por muy estable que parezca en las pruebas.
Para el examen
Orden fijo de las cláusulas: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY
ALL: el valor por defecto: conserva duplicados
DISTINCT: elimina duplicados
AS: pone alias a columnas y tablas
GROUP BY, funciones de agregado y HAVING
GROUP BY convierte muchas filas en una por grupo. A partir de ahí, cada columna del SELECT tiene que ser o bien una de las columnas por las que se agrupa, o bien el resultado de una función de agregado que resuma el grupo.
| Función | Qué devuelve | Trato de los nulos |
|---|---|---|
| COUNT(*) | Número de filas del grupo | Las cuenta todas, haya nulos o no |
| COUNT(columna) | Número de valores presentes en esa columna | No cuenta las filas con nulo |
| SUM(columna) | Suma de los valores | Ignora los nulos |
| AVG(columna) | Media de los valores | Ignora los nulos, y por eso divide entre menos filas |
| MAX y MIN | Valor mayor y menor del grupo | Ignoran los nulos |
SELECT a.nombre,
COUNT(*) AS intentos,
AVG(i.aciertos) AS media_aciertos
FROM intento i
JOIN alumno a ON a.id_alumno = i.id_alumno
WHERE i.realizado >= DATE '2026-01-01'
GROUP BY a.nombre
HAVING COUNT(*) >= 10
ORDER BY media_aciertos DESC;En esa consulta conviven los dos filtros y hacen cosas distintas. El WHERE actúa antes de agrupar y descarta filas sueltas: deja fuera los intentos anteriores a 2026, que ni siquiera llegan a contarse. El HAVING actúa después de agrupar y descarta grupos enteros: deja fuera a los alumnos con menos de diez intentos, que sí se han contado pero no superan el corte. De ahí que una función de agregado pueda aparecer en el HAVING y no pueda aparecer en el WHERE: cuando se evalúa el WHERE, los grupos todavía no existen.
WHERE filtra filas antes de agrupar; HAVING filtra grupos después de agrupar. Van casi siempre juntos y no son intercambiables.
Para el examen
WHERE: filtra filas ANTES de agrupar
HAVING: filtra grupos DESPUÉS de agrupar
Dónde cabe una función de agregado: solo en el HAVING, no en el WHERE
COUNT(*) frente al resto: COUNT(*) cuenta todas las filas; COUNT(columna), SUM, AVG, MAX y MIN ignoran los nulos
INSERT: dar de alta filas
INSERT tiene dos formas. La primera inserta una fila con valores literales; la segunda inserta de golpe tantas filas como devuelva una consulta, y es la que se usa para cargar tablas de resumen o para copiar datos de una tabla a otra.
INSERT INTO alumno (id_alumno, correo, nombre, modalidad)
VALUES (101, 'ana@ejemplo.es', 'Ana', 'largo');
INSERT INTO alumno_en_riesgo (id_alumno, media)
SELECT i.id_alumno, AVG(i.aciertos)
FROM intento i
GROUP BY i.id_alumno
HAVING AVG(i.aciertos) < 5;Nombrar las columnas entre paréntesis no es obligatorio, pero sí recomendable: si se omiten, los valores se asignan por la posición que tengan las columnas en la tabla, de modo que añadir una columna nueva más adelante rompe silenciosamente todas las inserciones escritas así.
Para el examen
INSERT … VALUES: inserta una fila
INSERT … SELECT: inserta tantas como devuelva la consulta
Sin lista de columnas: los valores se asignan por posición
UPDATE y DELETE
UPDATE cambia el valor de una o varias columnas en las filas que cumplan la condición. El valor nuevo puede ser un literal, la palabra DEFAULT para volver al valor por defecto de la columna, NULL para vaciarla, o el resultado de una consulta.
UPDATE alumno
SET modalidad = 'express'
WHERE fecha_alta > DATE '2026-06-01';
UPDATE intento
SET fallos = DEFAULT
WHERE id_intento = 4021;
UPDATE resumen_tema r
SET media_aciertos = (SELECT AVG(i.aciertos)
FROM intento i
WHERE i.id_tema = r.id_tema);
DELETE FROM intento
WHERE realizado < DATE '2024-01-01';En las dos sentencias el WHERE es opcional para el gestor y obligatorio para el sentido común: un UPDATE sin WHERE modifica todas las filas de la tabla y un DELETE sin WHERE las borra todas. La diferencia con TRUNCATE es que ese borrado sí es DML, se registra fila a fila, dispara los triggers y se deshace con un ROLLBACK mientras la transacción no se haya confirmado.
Para el examen
Sin WHERE: UPDATE y DELETE alcanzan a toda la tabla
Cómo se revierte: con ROLLBACK, porque son DML
Qué admite SET: literal, DEFAULT, NULL o una subconsulta
MERGE: actualizar o insertar en una sola sentencia
MERGE fusiona una tabla origen sobre una tabla destino comparándolas con una condición de búsqueda. Para cada fila del origen, si encuentra pareja en el destino la actualiza, y si no la encuentra la inserta. Es lo que en la práctica se llama una operación de tipo «upsert», y evita tener que preguntar primero si la fila existe.
MERGE INTO resumen_tema r
USING (SELECT id_tema, AVG(aciertos) AS media
FROM intento
GROUP BY id_tema) o
ON (r.id_tema = o.id_tema)
WHEN MATCHED THEN
UPDATE SET r.media_aciertos = o.media
WHEN NOT MATCHED THEN
INSERT (id_tema, media_aciertos) VALUES (o.id_tema, o.media);El origen que va detrás de USING no tiene por qué ser una tabla: puede ser una consulta entera, como en el ejemplo. Lo que sí es imprescindible es la condición del ON, porque es la que decide qué se considera una coincidencia y, con ello, qué rama se aplica a cada fila.
Para el examen
Nombre coloquial: el «upsert»
WHEN MATCHED: actualiza
WHEN NOT MATCHED: inserta
Cláusulas de origen y condición: USING y ON