21st Jul 2022 Tempo di lettura: 5 minuti Subquery SQL Patrycja Dybka sottoquery Indice Che cos'è una subquery? Subquery annidate Subquery con l'operatore ALL Subquery con operatore ANY Subquery annidata in un'altra subquery utilizzando l'operatore IN Subquery correlate Subquery correlate nella clausola WHERE Subquery con EXISTS Limitazioni delle subquery L'articolo descrive cos'è una subquery e come si presentano queste utili istruzioni. Verranno illustrati esempi di base con gli operatori IN, EXISTS, ANY e ALL, si analizzeranno le subquery nelle clausole FROM e WHERE e si analizzerà la differenza tra subquery correlate e nidificate. Innanzitutto, iniziamo con un database di esempio. Per presentare alcune di queste affermazioni è necessario disporre di una tabella di esempio e riempirla con alcuni dati. Che cos'è una subquery? Una subquery è un'istruzione SELECT con un'altra istruzione SQL, come nell'esempio seguente. SELECT * FROM product WHERE id IN ( SELECT product_id FROM provider_offer WHERE provider_id = 156 ); Le subquery sono ulteriormente classificate come subquery correlate o subquery annidate. Di solito sono costruite in modo da restituire: una tabella SELECT MAX(average.average_price) FROM ( SELECT product_category, AVG(price) AS average_price FROM product GROUP BY product_category ) average; o un valore SELECT id FROM purchase WHERE value > ( SELECT AVG(value) FROM purchase ); Volete saperne di più sulle subquery SQL? Date un'occhiata alla nostra serie We Learn SQL su Youtube. Ricordatevi di iscrivervi al nostro canale. Subquery annidate Lesubquery annidate sono subquery che non dipendono da una query esterna. In altre parole, entrambe le query di una subquery annidata possono essere eseguite come query separate. Questo tipo di subquery può essere usato quasi ovunque, ma di solito assume uno dei seguenti formati: SELECT FROM WHERE [NOT] IN (subquery) SELECT * FROM client WHERE city IN ( SELECT city FROM provider ); La subquery di esempio restituisce tutti i clienti che provengono dalla stessa città dei fornitori di prodotti. L'operatore IN controlla se il valore è presente nella tabella e recupera le righe corrispondenti. SELECT FROM WHERE expression comparison_operator [ANY| ALL] (subquery) Subquery con l'operatore ALL L'operatore ALL confronta un valore con tutti i valori della tabella dei risultati. Ad esempio, la seguente query restituisce tutti i modelli e i produttori di biciclette che hanno un prezzo superiore a quello delle cuffie più costose. SELECT producer, model FROM product WHERE product_category = 'bike' AND price > ALL( SELECT price FROM product WHERE product_category = 'headphones' ); Subquery simile ma con l'operatore ANY: Subquery con operatore ANY L'operatore ANY confronta un valore con ogni valore di una tabella e valuta se il risultato di una query interna contiene o meno almeno una riga. La seguente query restituisce tutti i modelli e i produttori di biciclette che hanno un prezzo superiore ad almeno una delle cuffie. SELECT producer, model FROM product WHERE product_category = 'bike' AND price > ANY( SELECT price FROM product WHERE product_category = 'headphones' ); È anche possibile annidare una sottoquery in un'altra aubquery. Ad esempio: Subquery annidata in un'altra subquery utilizzando l'operatore IN Questa query restituisce i produttori e i modelli di biciclette presenti nelle offerte dei fornitori DAGLI USA. SELECT producer, model FROM product WHERE product_category = 'bike' AND id IN ( SELECT distinct product_id FROM provider_offer WHERE provider_id IN ( SELECT id FROM provider WHERE country = 'USA' ) ); Lo stesso si può fare utilizzando i join. SELECT product.producer, product.model FROM product, provider_offer, provider WHERE provider_offer.product_id = product.id AND provider_offer.provider_id = provider.id AND product_category = 'bike' AND provider.country = 'USA'; Subquery correlate Lesottoquery sono correlate quando la query interna e quella esterna sono interdipendenti, cioè quando la query esterna è una query che contiene una sottoquery e la stessa sottoquery è una query interna. Gli utenti che conoscono i concetti di programmazione possono paragonarla a una struttura ad anello annidata. Cominciamo con un semplice esempio. La query interna calcola il valore medio e lo restituisce. Nella clausola WHERE della query esterna, filtriamo solo gli acquisti che hanno un valore superiore al valore restituito dalla query interna. Subquery correlate nella clausola WHERE SELECT id FROM purchase p1 WHERE date > '2013-07-15' AND value > ( SELECT AVG(value) FROM purchase p2 WHERE p1.date = p2.date ); La query restituisce gli acquisti successivi al 15/07/2014 con un prezzo totale superiore al valore medio Dallo stesso giorno. L'esempio equivalente, ma con tabelle unite. SELECT p1.id FROM purchase p1, purchase p2 WHERE p1.date = p2.date AND p1.date > '2013-07-15' GROUP BY p1.id HAVING p1.value > AVG(p2.value); Questo esempio può anche essere scritto come un'istruzione SELECT con una subquery correlata in una clausola FROM. La sottoquery restituisce la tabella che contiene il valore medio di ogni acquisto per ogni giorno. Uniamo questo risultato alla tabella Acquisti sulla colonna 'data' per verificare la condizione data > '15/07/2014′. SELECT id FROM purchase, ( SELECT date, AVG(value) AS average_value FROM purchase WHERE date > '2013-07-15' GROUP BY date ) average WHERE purchase.date = average.date AND purchase.date > '2013-07-15' AND purchase.value > average.average_value; In genere, questo tipo di subquery dovrebbe essere evitato perché gli indici non possono essere utilizzati su una tabella temporanea in memoria. Subquery con EXISTS SELECT FROM WHERE [NOT] EXISTS (subquery) L'operatore EXISTS controlla se la riga dalla subquery corrisponde a una riga della query esterna. Se non ci sono dati corrispondenti, l'operatore EXISTS restituisce FALSE. Questa query restituisce tutti i clienti che hanno ordinato dopo il 10/07/2013. SELECT id, company_name FROM client WHERE EXISTS( SELECT * FROM purchase WHERE client.id = purchase.client_id WHERE date > '2013-07-10' ); Quando si utilizza una sottoquery, l'ottimizzatore di query esegue ulteriori passaggi prima di utilizzare i risultati dalla sottoquery. Se una query che contiene una sottoquery può essere scritta utilizzando una join, è meglio farlo in questo modo. I join di solito consentono all'ottimizzatore di query di recuperare i dati in modo più efficiente. Limitazioni delle subquery L'uso delle subquery presenta alcune limitazioni: In Oracle è possibile annidare fino a 255 livelli di subquery in una clausola WHERE. In SQL Server è possibile annidare fino a 32 livelli. Tags: sottoquery