Lecciones del módulo (2/4)
Self-JOIN: una tabla con ella misma
A veces la relación que deseas atravesar no es entre dos
tablas diferentes, pero entre filas de la misma tabla. Ejemplo típico: un
Jerarquía de "categoría → subcategoría", donde tanto el padre como el hijo son filas de
la misma tabla categories, unida por un parent_id.
Para leer juntos una fila (secundaria) y "su" otra fila (principal), utilice un
autounión: la misma tabla aparece dos veces en FROM, con dos
diferentes alias.
La sintaxis
SELECT colonne
FROM tabella AS alias_a
JOIN tabella AS alias_b ON alias_a.foreign_key = alias_b.id;El alias es obligatorio: si omitimos AS a / AS b, PostgreSQL no tiene
manera de saber a cuál de las dos copias nos referimos cuando escribimos name o id.
-- Ogni sotto-categoria con il nome della categoria padre:
SELECT child.name AS subcategory,
parent.name AS category
FROM categories AS child
JOIN categories AS parent ON child.parent_id = parent.id;Leer en inglés sencillo: "tome las filas de categories denominadas niño y
para cada uno encuentre la fila de categories llamada padre cuyo id es el
CÓDIGOPH3 del niño".
El resultado excluye las categorías raíz (aquellas con parent_id = NULL)
porque un INNER JOIN omite filas que no coinciden. Si quieres incluir
ellos, utilice LEFT JOIN.
Autounirse con IZQUIERDA para "conservar las raíces también"
-- Tutte le categorie, con nome del padre o NULL se sono radice:
SELECT child.name AS category,
parent.name AS parent
FROM categories AS child
LEFT JOIN categories AS parent ON child.parent_id = parent.id;Ahora obtienes 9 filas (cada categoría en el conjunto de datos), con parent = NULL
para las 3 raíces.
Agregando con una autounión
Combina muy bien con GROUP BY para preguntar "¿cuántos niños tiene cada uno?"
padre tiene":
SELECT p.name AS parent_category,
COUNT(c.id) AS children
FROM categories AS p
LEFT JOIN categories AS c ON c.parent_id = p.id
WHERE p.parent_id IS NULL -- solo le radici
GROUP BY p.name
ORDER BY p.name;Tenga en cuenta dos detalles importantes:
WHERE p.parent_id IS NULLfiltra antes de JOIN: tomamos solo el raíces como la "tabla de la izquierda".COUNT(c.id)(noCOUNT(*)) devuelve 0 para raíces sin hijos, mientras queCOUNT(*)devolvería 1 debido a la filaLEFT JOINcon NULO.
Pruébalo tú mismo
Para cada subcategoría (categoría con parent_id NOT NULL), muestra el nombre de la subcategoría y el nombre de su categoría-padre. Columna debida: subcategoría, categoría. Ordina por categoría poi por subcategoría.
Mostrar pista
La condición de self-JOIN es child.parent_id = parent.id.
Solución disponible después de 3 intentos
Ejercicio de revisión
Por cada categoría-radice (parent_id IS NULL), muestra el nombre y el número de subcategoría. Columna debida: nombre, hijos. Ordina por nombre. Includi una eventuale radice senza figlie con 0.
Mostrar pista
LEFT JOIN en categorías dos veces (alias p para padre, c para hijo). Utilice COUNT(c.id), no COUNT(*), para obtener 0 en raíces sin hijos.
Solución disponible después de 3 intentos