Saltar al contenido

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.

sql
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ónQué devuelveTrato de los nulos
COUNT(*)Número de filas del grupoLas cuenta todas, haya nulos o no
COUNT(columna)Número de valores presentes en esa columnaNo cuenta las filas con nulo
SUM(columna)Suma de los valoresIgnora los nulos
AVG(columna)Media de los valoresIgnora los nulos, y por eso divide entre menos filas
MAX y MINValor mayor y menor del grupoIgnoran los nulos
sql
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.

sql
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.

sql
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.

sql
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