Finora abbiamo visto delle novità non particolarmente eclatanti(1, 2, 3). Con l’introduzione delle “WITH queries” passiamo a qualcosa di più sostanzioso.
WITH (non ricorsivo)
Nella versione “liscia” WITH è un aiuto per scrivere le query in modo più chiaro, senza bisogno di sub-SELECT nidificate. Al posto di:
WITH regional_sales AS (
SELECT
region,
SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (
SELECT SUM(total_sales)/10
FROM regional_sales
)
)
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;
Avremmo dovuto scrivere:
SELECT region,
product,
SUM(quantity) AS product_units,
SUM(amount) AS product_sales
FROM orders
WHERE region IN (
SELECT region FROM (
SELECT region
FROM regional_sales
WHERE total_sales > (
SELECT SUM(total_sales)/10 FROM (
SELECT
region,
SUM(amount) AS total_sales
FROM orders
GROUP BY region
)
)
)
)
GROUP BY region, product;
Oltre a essere più chiara, notiamo che la stessa espressione — in questo caso, regional_sales — può essere richiamata già all’interno del blocco di WITH; inoltre, secondo la documentazione, l’espressione viene valutata una volta sola, anche se viene in seguito richiamata.
WITH RECURSIVE
Se la clausola WITH ha principalmente il vantaggio di rendere la query più chiara ed efficiente, la versione ricorsiva rende possibile l’espressione in SQL di problemi che avrebbero prima richiesto una soluzione procedurale.
Ad esempio diventa possibile formulare query che attraversano strutture gerarchiche (il classico problema del “bill of materials”). Eccone uno dalla documentazione:
WITH RECURSIVE included_parts(sub_part, part, quantity) AS (
SELECT
sub_part,
part,
quantity
FROM parts
WHERE part = 'our_product'
UNION ALL
SELECT p.sub_part, p.part, p.quantity
FROM included_parts pr, parts p
WHERE p.part = pr.sub_part
)
SELECT sub_part, SUM(quantity) as total_quantity
FROM included_parts
GROUP BY sub_part;
Come tutte le strutture ricorsive bisognerà fare attenzione ad evitare cicli infiniti ma, in linea generale, l’uso di WITH RECURSIVE non riserva grosse sorprese.