SELECT: operatore NOT IN e costruttore di tupla

In alcuni casi si ha la necessità di escludere un insieme di valori da un altro insieme. Il linguaggio SQL ci permette di escludere i valori da escludere restituiti da una query nidificata mediante l'operatore NOT IN. Qualora gli elementi da escludere siano identificati da un insieme di attributi possiamo usare il costruttore di tupla. Con alcuni esempi capiremo come usare questi costrutti in modo appropriato.

Share

Reading time: 3 minutes

Negli articoli precedenti, SELECT: struttura di una query semplice, SELECT: query con JOIN e GROUP BY e SELECT: operatore IN, abbiamo affrontato vari costrutti del linguaggio SQL. In particolare, nell’articolo SELECT: operatore IN abbiamo introdotto il concetto di appartenenza ad un insieme mediante il costrutto IN. Ciò ci ha permesso sia di dividere problemi complessi in sotto-problemi, sia di sfruttare il risultato di query per filtrare i record di altre tabelle. Come accennato, però, non esiste solo l’operatore IN, ma anche il suo duale l’operatore NOT IN.

 In questo articolo parleremo proprio di questo operatore e di come usarlo correttamente per rispondere ad alcuni quesiti che diversamente non riusciremmo ad esprimere con i costrutti visti fino a ora. Infine, introdurremo anche il costruttore di tupla che può essere usato sia con questo operatore che con la IN.

Useremo, anche in questo caso, lo schema degli altri articoli relativo alle proiezioni dei film nei cinema. Lo riportiamo qui sotto per chi non avesse letto gli altri articoli.

FILM (CodF, Titolo, Data_uscita, Genere, DurataMinuti)
CINEMA (CodC, Nome, Indirizzo, Città, SitoWeb*)
SALA (CodC, NumeroSala, Capienza)
PROIEZIONE (CodC, NumeroSala, Data, OraInizio, OraFine, CodF)

Vi ricordo che la notazione usata per descrivere lo schema usa la sottolineatura per indicare i campi che compongono la chiave primaria e l’asterisco per segnalare la possibilità di assegnare valori NULL al campo. Infine, per semplificare, le chiavi esterne hanno lo stesso nome delle chiavi primarie a cui si riferiscono. Procediamo quindi a vedere i vari operatori.

Concetto di esclusione

In alcuni contesti ci viene richiesto di escludere dal risultato di un’interrogazione dei valori perché non sono di interesse. Come facciamo? Dipende! Non c’è infatti una risposta univoca perché dipende da caso a caso. Ad esempio, se volessimo visualizzare tutti i cinema che non sono nella città di Torino la query sarebbe la seguente:

				
					SELECT *
FROM CINEMA
WHERE Città <> ’Torino';
				
			

In questo esempio semplicemente abbiamo indicato di includere nel risultato finale tutti i record che hanno un valore diverso da quello che non ci interessa, ossia la città di Torino.  Ma supponiamo di voler trovare i cinema che hanno solo sale con una capienza maggiore di 100. Proviamo a scrivere la query come segue:

				
					SELECT C.*
FROM SALA S, CINEMA C
WHERE S.CodC=C.CodC 
AND Capienza > 100;
				
			

Cosa stiamo ottenendo? In realtà ci vengono restituite i cinema che hanno almeno una sala con una capienza maggiore di 100. Se però in quel cinema esiste una sala con una capienza inferiore a 100, il cinema comunque verrà visualizzato. Perché? Il motivo è che stiamo solo filtrando le sale in base alla capienza e non i cinema.

Come facciamo allora ad escludere qualcosa dal risultato di una query? Abbiamo bisogno di un operatore che agisce proprio su un insieme di valori e che li escluda. Questo operatore è la NOT IN.

Operatore NOT IN

L’operatore NOT IN esprime proprio il concetto di esclusione da un insieme di valori. La sintassi è la seguente:

				
					NomeAttributo NOT IN (InterrogazioneNidificata)
				
			

dove il nome attributo deve essere compatibile con l’attributo restituito dalla query nidificata. La query nidificata può essere anche sostituita con una lista di valori, se necessario. Come per l’operatore IN, questa ultima opzione si usa solo nei casi in cui questi valori derivino da interazioni esterne con i dati del DB, come ad esempio quando un utente sceglie più opzioni in un form. Usare una query nidificata permette al DBMS di ottimizzare l’esecuzione della query e rendere il tutto più veloce ed efficiente.

Con l’operatore NOT IN si richiede di individuare in modo appropriato l’insieme da escludere affinché la query esegua le giuste esclusioni dei record interessati.

Attenzione

Non esiste una formulazione equivalente con il join

Riprendiamo quindi l’esempio visto in precedenza. Se vogliamo individuare i cinema che hanno solo sale con una capienza maggiore di 100, dobbiamo escludere i cinema e non le singole sale! Dividiamo, quindi, il problema in due parti:

  1. trovare i cinema che hanno sale con una capienza inferiore o uguale a 100
  2. escludere i cinema trovati nel punto precedente

La prima query risulta

				
					SELECT CodC
FROM SALA
WHERE Capienza <= 100;
				
			

A questo punto, avendo selezionato il codice del cinema, possiamo filtrare i cinema escludendo i valori ritornati. Usiamo, pertanto, l’operatore NOT IN confrontando i codici dei cinema. La query risulterà:

				
					SELECT *
FROM CINEMA
WHERE CodC NOT IN (SELECT CodC
    FROM SALA
    WHERE Capienza <= 100);
				
			

Quando si usa la NOT IN?

A questo punto sorgono spontanee alcune domande:

  1. Come facciamo a capire che dobbiamo usare l’operatore NOT IN?
  2. Quale attributo usare per l’esclusione?
  3. Quali condizioni mettere nella query nidificata?

Partiamo dal primo quesito. L’operatore NOT IN serve per escludere un insieme di valori dal risultato finale e si usa solo nella clausola WHERE. Pertanto, quando dovete filtrare una tabella in base a delle condizioni che vengono espresse con gli avverbi “solo”, “sempre” e “mai” bisogna pensare che nella maggior parte dei casi si dovrà usare l’operatore NOT IN.

Partendo da questo presupposto, bisogna capire dal problema cosa vogliamo escludere. Ricordatevi di usare, ove possibile, le chiavi primarie al fine di escludere qualcosa.

Infine, per rispondere alla terza domanda, dovete sempre pensare qual è l’insieme da escludere e quali caratteristiche possiede. Nell’esempio precedente, le sale che avevano una capienza inferiore o uguale a 100 determinavano se il cinema doveva essere incluso o escluso dal risultato finale. Abbiamo, quindi, invertito la condizione rispetto alla richiesta originale. Questo approccio funziona quasi sempre, ma dipende molto dalle condizioni che vengono imposte.

Costruttore di tupla

Talvolta la chiave primaria su cui vogliamo fare un confronto/esclusione è composta da più attributi. Come visto in precedenza, la sintassi base degli operatori In e NOT IN agiscono su un solo attributo. È possibile usarli anche con più attributi? Certamente! Dobbiamo introdurre il concetto di costruttore di tupla che permette di definire una struttura temporanea di una tupla. Per far ciò si elencano gli attributi che ne fanno parte tra parentesi tonde, come mostrato di seguito

				
					(NomeAttributo1, NomeAttributo2, ...)
				
			

Attenzione

L’ordine degli attributi è importante e deve rispecchiare l’ordine restituito dalle query nidificate

Vediamo un esempio di applicazione del costruttore di tupla unito all’operatore NOT IN. Supponiamo di voler individuare le sale in cui non sono stati mai proiettati film di genere horror. Non possiamo scrivere sicuramente la query che segue:

				
					SELECT S.*
FROM SALA S, PROIEZIONE P, FILM F
WHERE S.CodC=P.CodC AND S.NumeroSala=P.CodC
AND P.CodF=F.CodF
AND Genere <> ‘Horror’;
				
			

Questa soluzione è sbagliata in quanto filtra le proiezioni in base al genere del film e non le sale. Dobbiamo usare l’operatore NOT IN. Dividiamo il problema in due componenti:

  1. Trovare le sale che hanno proiettati film di genere horror
  2. Escludiamo le sale trovate nel punto precedente dal risultato finale

Le sale sono identificate sia dal codice del cinema che dal numero della sala. Pertanto, la query dovrà selezionare entrambi i campi per poi effettuare l’esclusione in modo corretto. Diversamente selezionando solo i codici dei cinema o il numero di sala avremmo confrontato insiemi di dati diversi.

				
					SELECT CodC, NumeroSala
FROM PROIEZIONE P, FILM F
WHERE P.CodF=F.CodF
AND Genere=’Horror’;
				
			

Adesso possiamo usare il costruttore di tupla insieme all’operatore NOT IN per escludere correttamente le sale. La query finale sarà:

				
					SELECT *
FROM SALA
WHERE (CodC, NumeroSala) NOT IN (SELECT CodC, NumeroSala
    FROM PROIEZIONE P, FILM F
    WHERE P.CodF=F.CodF
    AND Genere=’Horror’);

				
			

More To Explore

Intelligenza artificiale

Gradio: applicazioni web in python per AI [parte2]

Gradio è una libraria python che ci permette di creare applicazioni web in modo veloce e intuitivo per i nostri modelli di machine learning e AI. Le nostre applicazioni richiedono sempre un’interazione con l’utente e una personalizzazione del layout. Scopriamo, mediante degli esempi, come migliorare le nostre applicazioni.

Intelligenza artificiale

Gradio: applicazioni web in python per AI [parte1]

Scrivere applicazioni web per i nostri modelli di machine learning e/o di intelligenza artificiale può richiedere molto tempo e competenze che non sono in nostro possesso. Per snellire e velocizzare questo compito ci viene in aiuto Gradio, una libreria Python pensata per creare applicazioni web con poche righe di codice. Scopriamo le sue funzionalità base con alcuni esempi.

Una risposta

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!