CASE y los valores que faltan
En resumen: CASE WHEN devuelve un valor distinto según una condición, COALESCE sustituye NULL por un valor por defecto, y NULLIF convierte un valor dado en NULL.
Problema
Palabras en lugar de códigos
En la página «Mis pedidos», el cliente ve el estado tal como está en la base: paid, shipped. Los códigos son cómodos para el programa, pero el cliente espera «Pagado» y «En camino».
El sitio web quiere además un filtro «barato, medio, caro». En la base no existe esa columna, solo un precio.
La idea
CASE WHEN
CASE da un valor distinto según una condición:
Las condiciones se comprueban de arriba abajo. El primer WHEN verdadero da el valor del THEN que tiene al lado, y a los demás no se los mira. ELSE es para todo aquello para lo que nada es verdadero. END cierra la expresión, y AS le da un nombre.
Cuando comparas una columna con varios valores, hay una forma más corta: la columna se escribe una vez después de CASE, y cada WHEN lleva solo el valor:
Pruébalo
Los estados en palabras
Muestra el número, la fecha y el estado en palabras de cada pedido, en una columna llamada status_text: new es «Recibido», paid es «Pagado», shipped es «En camino», delivered es «Entregado», cancelled es «Cancelado».
Solución
SELECT id, ordered_at,
CASE status
WHEN 'new' THEN 'Recibido'
WHEN 'paid' THEN 'Pagado'
WHEN 'shipped' THEN 'En camino'
WHEN 'delivered' THEN 'Entregado'
WHEN 'cancelled' THEN 'Cancelado'
END AS status_text
FROM orders;Cinco WHEN en la forma corta CASE status … END AS status_text. Si algún día aparece un estado nuevo, sin ELSE saldrá como NULL. Al menos lo notarás.
Míralo
Los caros desaparecieron
Un compañero reescribe los grupos de precio con >. Ejecútalo y mira la cocina:
Una cosa más: si no hay ELSE y ningún WHEN es verdadero, el resultado es NULL. Los panes reciben una nota solo cuando están agotados o quedan pocos:
A veces es justo lo que quieres. Si no, escribe ELSE.
La idea
COALESCE y NULLIF
COALESCE(a, b, …) devuelve el primer valor que no es NULL. Así pones una palabra en lugar de lo que falta:
A veces «falta» se guarda no como NULL sino como texto vacío. En los dos ejemplos siguientes la base tiene un cliente más, Anna, guardada a través de un formulario que envía '' en lugar de NULL. COALESCE no la recoge, porque el texto vacío es un valor:
NULLIF(a, b) da NULL cuando a es igual a b, y a en caso contrario. Así el texto vacío se vuelve NULL, y COALESCE recoge a los dos clientes:
Más precisamente, para curiosos
NULLIF se usa también en la división: total / NULLIF(count, 0). Cuando count es 0, el divisor se vuelve NULL y el resultado también. En SQLite dividir entre cero da NULL de todas formas, pero en PostgreSQL es un error que detiene toda la consulta.
Pruébalo
La línea para el mensajero
Corrige la línea «nombre, ciudad» de la lección sobre texto: cuando falte la ciudad, en su lugar debe decir «sin ciudad». La columna debe llamarse contact.
Solución
SELECT name || ', ' || COALESCE(city, 'sin ciudad') AS contact FROM customers;name || ', ' || COALESCE(city, 'sin ciudad') AS contact. Ahora Boris Mitev también tiene una línea: «Boris Mitev, sin ciudad».
Ejercicio
Dos tareas
1. Junto a cada producto, el sitio muestra las existencias en palabras: «agotado» con 0, «últimas unidades» por debajo de 10, y si no «en existencia». Muestra el nombre, las existencias y las palabras en una columna llamada availability.
Las existencias en palabras de cada producto:
Solución
SELECT name, stock,
CASE
WHEN stock = 0 THEN 'agotado'
WHEN stock < 10 THEN 'últimas unidades'
ELSE 'en existencia'
END AS availability
FROM products;Primero WHEN stock = 0, luego WHEN stock < 10, y ELSE al final. Si cambias de sitio los dos primeros, los productos agotados pasan a ser «últimas unidades», porque 0 también es menor que 10.
2. El almacén trabaja en este orden: primero prepara los pedidos pagados (paid), luego mira los nuevos (new), y al final revisa los enviados (shipped). Muestra el número, el estado y la fecha de esos pedidos en el orden de trabajo, y dentro de un mismo estado el más antiguo primero. Con la misma fecha, primero el número menor.
Los pedidos abiertos en el orden en que los atiende el almacén:
Solución
SELECT id, status, ordered_at
FROM orders
WHERE status IN ('paid', 'new', 'shipped')
ORDER BY CASE status WHEN 'paid' THEN 1 WHEN 'new' THEN 2 ELSE 3 END, ordered_at, id;ORDER BY CASE status WHEN 'paid' THEN 1 WHEN 'new' THEN 2 ELSE 3 END, ordered_at, id. CASE convierte el estado en un número por el que se ordena. Aquí la comprobación también mira el orden.
Más precisamente, para curiosos
SQLite tiene también IIF(condición, si es verdadera, si no): un CASE corto con un WHEN y un ELSE. SQL Server lo tiene también, pero PostgreSQL no. CASE es la forma estándar y funciona en todas partes.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: NULL: sin valor · ORDER BY, LIMIT y DISTINCT · Aritmética en una consulta · Funciones de texto
- Continúa en: Funciones de agregación: COUNT, SUM, AVG · Muchas tablas, y una tabla unida consigo misma · Un informe por pasos: WITH · Árboles y secuencias: WITH RECURSIVE
- Ejercicios sobre el tema: Expresiones y funciones