Bases de datos SQL

Ordenar, limitar, actualizar y borrar

Lección 5 de 8 · 15 min

Ordenar

ORDER BY se escribe igual en los tres motores: ASC de menor a mayor -es lo que hace por defecto- y DESC al revés.

ORDER BY, idéntico en los tres
-- De mayor a menor saldo
SELECT nombre, saldo FROM clientes ORDER BY saldo DESC;

-- Por dos criterios: primero ciudad, y dentro de cada ciudad por saldo
SELECT nombre, ciudad, saldo
FROM clientes
ORDER BY ciudad ASC, saldo DESC;

Limitar y paginar: aquí SQL Server se separa

Traer solo los diez primeros resultados, o «la página 3 de 20 en 20», es de lo más común que hay. Y es de las diferencias más visibles entre motores.

PostgreSQL y MySQL: LIMIT y OFFSET
-- Los 10 clientes con mas saldo
SELECT nombre, saldo FROM clientes
ORDER BY saldo DESC
LIMIT 10;

-- Pagina 3, de 20 en 20: saltar 40 y traer 20
SELECT nombre, saldo FROM clientes
ORDER BY saldo DESC
LIMIT 20 OFFSET 40;
SQL Server: TOP y OFFSET-FETCH
-- Los 10 primeros
SELECT TOP 10 nombre, saldo FROM clientes
ORDER BY saldo DESC;

-- Pagina 3, de 20 en 20
SELECT nombre, saldo FROM clientes
ORDER BY saldo DESC
OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;

Fíjate en dónde va cada cosa: TOP se coloca justo después de SELECT, mientras que LIMIT va al final. Y el OFFSET-FETCH de SQL Server exige un ORDER BY: sin él, no funciona.

Y esa exigencia de SQL Server tiene toda la razón de ser: sin ORDER BY, el orden en que la base de datos devuelve las filas no está garantizado. Puede cambiar entre dos ejecuciones de la misma consulta.

Consecuencia práctica: si paginas sin ordenar, un mismo registro puede aparecer en la página 1 y en la 2, y otro no salir nunca. Nadie da un error, y el usuario ve una lista que «a veces se salta cosas». Paginar sin ordenar está roto, aunque el motor te deje.

Modificar datos

UPDATE cambia filas existentes y se escribe igual en los tres motores. Lo importante no es la sintaxis: es el WHERE.

UPDATE y DELETE
-- Cambiar el saldo de un cliente concreto
UPDATE clientes SET saldo = 200000 WHERE id = 3;

-- Varias columnas a la vez
UPDATE clientes
SET ciudad = 'Medellin', activo = FALSE
WHERE id = 7;

-- Borrar una fila
DELETE FROM clientes WHERE id = 9;

Este es EL desastre clásico de SQL, y le ha pasado a todo el mundo:

UPDATE clientes SET saldo = 0; -sin WHERE- pone el saldo a cero de todos los clientes de la tabla. Y DELETE FROM clientes; borra la tabla entera.

No hay confirmación, no hay papelera, y si no estabas dentro de una transacción, no hay vuelta atrás. La única salida es la copia de seguridad.

El procedimiento para no destruir nada

  1. 1. Escribir el WHERE primero

    Literalmente: escribe la condición antes que el SET.

    Suena a superstición y funciona: el desastre ocurre cuando alguien ejecuta la consulta «a medio escribir».

  2. 2. Probarlo como SELECT

    Convierte el UPDATE en un SELECT con el mismo WHERE: SELECT * FROM clientes WHERE id = 3;

    Las filas que salen son exactamente las que vas a modificar. Si salen 4.000, no ejecutes nada.

  3. 3. Envolverlo en una transacción

    BEGIN; antes, ejecutar, mirar cuántas filas afectó, y entonces COMMIT; o ROLLBACK;.

    Es la red de seguridad de verdad, y se ve en la lección 8.

  4. 4. Comprobar el resultado

    El motor te dice cuántas filas cambió -UPDATE 1-. Si esperabas una y dice 340, ahí tienes el aviso.

    Y después, un SELECT para ver cómo quedó.

El mismo cambio, hecho con red
-- 1. Ver a quien va a afectar
SELECT id, nombre, saldo FROM clientes WHERE ciudad = 'Cali';

-- 2. Con red debajo
BEGIN;

UPDATE clientes SET activo = FALSE WHERE ciudad = 'Cali';
-- El motor responde: UPDATE 3

-- 3. Si son las 3 que esperabas:
COMMIT;
-- Si no:
-- ROLLBACK;

Tres formas de vaciar una tabla, y no son iguales

DELETE FROM tabla

Borra las filas una a una y puede deshacerse dentro de una transacción.

Es lento en tablas grandes, y es el único que admite WHERE.

TRUNCATE TABLE

Vacía la tabla de golpe. Mucho más rápido, pero no admite WHERE: es todo o nada.

Suele reiniciar el contador del id automático, cosa que DELETE no hace.

DROP TABLE

Elimina la tabla entera: datos y estructura.

Después de esto la tabla ya no existe. Es el más destructivo de los tres.

Preguntas de esta lección

¿No hay una protección contra el UPDATE sin WHERE?

MySQL tiene un modo de actualizaciones seguras que rechaza un UPDATE o DELETE sin condición sobre una clave, y su cliente gráfico lo suele traer activado.

Pero no está activo en todas partes y PostgreSQL no tiene nada equivalente de serie. No se puede confiar en él: la protección real es el procedimiento de arriba.

Ordenar por una columna con NULL

Los motores no coinciden en dónde colocan los NULL: unos los ponen al principio y otros al final.

PostgreSQL permite decirlo explícitamente con NULLS FIRST o NULLS LAST. Si el orden importa, conviene indicarlo en vez de confiar en el comportamiento por defecto.

Ordenar números guardados como texto

Si la columna es VARCHAR, el orden es alfabético: el 100 va antes que el 20, porque compara carácter a carácter.

No es un fallo del motor: es que el tipo estaba mal elegido. Vuelve a la lección 3.

Paginar tablas muy grandes

OFFSET es cómodo y se vuelve lento con offsets enormes: el motor tiene que recorrer y descartar todas las filas anteriores para llegar a la página 500.

Para volúmenes grandes se pagina «por la última clave vista» en vez de por número de página.

Compruébalo tú mismo

Ejecutas UPDATE clientes SET saldo = 0; por error. ¿Qué pasó?

Paginas resultados sin poner ORDER BY y los usuarios dicen que la lista «a veces se salta registros». ¿Por qué?

Vas a ejecutar un UPDATE sobre varias filas. ¿Cuál es la comprobación previa?

Lo que sigue

Hasta aquí has trabajado con una sola tabla. La siguiente lección es la que convierte esto en una base de datos relacional: repartir los datos en varias tablas, relacionarlas con claves foráneas y volver a unirlas con JOIN.

Siguiente: Relaciones y JOIN

Continuar ← Insertar y consultar