Le subquery, ovvero le query annidate all'interno di altre query, sono uno degli strumenti più potenti e flessibili in SQL. Offrono la possibilità di eseguire operazioni complesse sui dati, consentendo di prendere decisioni basate su valori calcolati o su insiemi di dati derivati da altre tabelle. In questo contesto, esploreremo come utilizzare le subquery in comandi SELECT, INSERT, DELETE e UPDATE, e come queste possano essere utilizzate in modo efficiente per risolvere scenari complessi.

Prendiamo come esempio una query che restituisce l'EmpID di tutti i venditori che hanno effettuato una vendita pari almeno al doppio della media di tutte le vendite degli altri venditori. La query potrebbe essere scritta nel seguente modo:

sql
SELECT TM1.EmpID
FROM TRANSMASTER TM1 GROUP BY TM1.EmpID HAVING MAX(TM1.NetAmount) >= ALL (SELECT 2 * AVG(TM2.NetAmount) FROM TRANSMASTER TM2 WHERE TM1.EmpID <> TM2.EmpID);

In questa query, sono utilizzati due alias per la stessa tabella, TM1 e TM2, per differenziare i contesti in cui la tabella viene utilizzata. La tabella TRANSMASTER è, infatti, utilizzata per due scopi differenti all'interno della stessa query: nel gruppo esterno per raccogliere i dati dei venditori e nella subquery interna per calcolare la media delle vendite degli altri venditori.

Il processo della query è il seguente:

  1. La query esterna raggruppa le righe della tabella TRANSMASTER per EmpID, utilizzando le clausole SELECT, FROM e GROUP BY.

  2. La clausola HAVING filtra i gruppi calcolando il valore massimo della colonna NetAmount per ogni gruppo.

  3. La subquery interna calcola il doppio della media delle vendite (AVG) della colonna NetAmount per tutti i venditori il cui EmpID è diverso da quello del gruppo corrente della query esterna.

  4. La query finale confronta il massimo della colonna NetAmount di ciascun gruppo con il doppio della media calcolata nella subquery.

Le subquery possono essere utilizzate anche in altre dichiarazioni SQL come UPDATE, DELETE e INSERT. Per esempio, se si volesse applicare uno sconto retroattivo su tutte le transazioni di un determinato cliente, si potrebbe scrivere una query di tipo UPDATE come la seguente:

sql
UPDATE TRANSMASTER
SET NetAmount = NetAmount * 0.9 WHERE CustID = (SELECT CustID FROM CUSTOMER WHERE Company = 'Baker Electronic Sales');

In questo caso, la subquery viene utilizzata per identificare il CustID della compagnia specificata e applicare uno sconto sulle transazioni di quel cliente.

In maniera analoga, è possibile utilizzare le subquery in una dichiarazione UPDATE correlata, dove la subquery fa riferimento ai valori della stessa tabella che viene aggiornata. Ad esempio, per applicare uno sconto solo sulle transazioni che superano un determinato importo:

sql
UPDATE TRANSMASTER TM
SET NetAmount = NetAmount * 0.9 WHERE NetAmount > (SELECT LastMonthsMax FROM CUSTOMER C WHERE C.CustID = TM.CustID);

Questa è una subquery correlata, poiché il confronto avviene tra la colonna NetAmount della tabella TRANSMASTER e la colonna LastMonthsMax della tabella CUSTOMER, ma con un riferimento incrociato tra i record delle due tabelle.

Le subquery in DELETE possono funzionare in modo simile, per esempio, per eliminare tutte le righe di una tabella che superano una determinata soglia. Consideriamo il caso di voler eliminare tutte le righe di TRANSMASTER per i clienti il cui totale degli acquisti supera i $10,000:

sql
DELETE FROM TRANSMASTER TM1 WHERE 10000 < (SELECT SUM(NetAmount) FROM TRANSMASTER TM2 WHERE TM1.CustID = TM2.CustID);

Anche in questo caso, la subquery restituisce la somma delle vendite di ciascun cliente e la query DELETE elimina le righe che soddisfano il criterio.

Le dichiarazioni INSERT possono anch'esse includere una subquery, che consente di inserire dati in una tabella basandosi su valori derivati da un'altra tabella. Un esempio di utilizzo potrebbe essere il seguente:

sql
INSERT INTO TRANSMASTER_1027
(SELECT * FROM TRANSMASTER WHERE TransDate = '2018-10-27');

In questo caso, la subquery seleziona tutti i dati dalla tabella TRANSMASTER relativi a una data specifica, e li inserisce in una nuova tabella chiamata TRANSMASTER_1027.

Inoltre, quando si utilizzano subquery in UPDATE, DELETE e INSERT, è fondamentale comprendere che la valutazione delle subquery avviene con i valori originali delle righe, prima che venga applicato qualsiasi aggiornamento o cancellazione. Pertanto, le subquery in questi contesti non utilizzano i dati aggiornati in tempo reale, ma i valori esistenti al momento dell'esecuzione della query.

Un aspetto cruciale da comprendere, inoltre, è che quando si utilizzano comandi come DELETE o UPDATE su tabelle con relazioni di dipendenza (come una tabella TRANSDETAIL che dipende da TRANSMASTER), è necessario considerare l'integrità referenziale. In tali casi, la gestione delle cancellazioni a cascata (cascading deletes) è fondamentale per evitare che i dati rimangano orfani, ossia senza un riferimento valido nelle tabelle correlate.

Le subquery sono quindi uno strumento indispensabile per operazioni SQL avanzate, ma devono essere usate con attenzione, in particolare quando si lavora con tabelle collegate tra loro o con dati in continua evoluzione.

Come Creare Grafici Complessi con Matplotlib per Analisi Dati

Quando si lavora con i dati, uno degli strumenti più potenti e versatili che possiamo utilizzare per rappresentarli graficamente è Matplotlib, una libreria di Python che consente di creare visualizzazioni chiare e dettagliate. Una delle operazioni fondamentali in questa libreria è la creazione di grafici, che possono variare dalla semplice rappresentazione di una singola linea alla visualizzazione complessa di più curve sovrapposte.

Matplotlib permette di aggiungere diversi elementi ai grafici, come linee multiple, etichette degli assi, griglie, e molto altro, che migliorano la comprensione dei dati. Quando si ha bisogno di confrontare due insiemi di dati, come nel caso di due set di valori che si vogliono visualizzare contemporaneamente, Matplotlib consente di tracciare più linee in un unico grafico.

Per esempio, supponiamo di avere due set di dati che rappresentano diverse sequenze di numeri. Per tracciare due linee sovrapposte su un unico grafico, basta chiamare plt.plot() due volte, una per ogni set di dati. Questo è un esempio pratico di come fare:

python
import matplotlib.pyplot as plt values1 = [1, 5, 8, 9, 2, 0, 3, 10, 4, 7] values2 = [3, 8, 9, 2, 1, 2, 4, 7, 6, 6] plt.plot(range(1, 11), values1) plt.plot(range(1, 11), values2) plt.show()

Con questo codice, visualizzeremo due linee, una per ciascun set di dati. Matplotlib, in modo automatico, assegnerà colori diversi a ciascuna linea, permettendo di distinguerle facilmente, anche se non visibile nel libro stampato. L’utilizzo di più linee su un singolo grafico è una pratica molto comune per confrontare e analizzare due o più serie di dati in modo chiaro ed efficace.

Un’altra funzionalità estremamente utile in Matplotlib è la possibilità di salvare i grafici che creiamo. Quando si lavora in ambienti come Jupyter Notebook, i grafici vengono automaticamente incorporati nel notebook. Tuttavia, se desideriamo salvare un grafico su disco, Matplotlib offre una funzione semplice da usare, plt.savefig(). Questa funzione consente di salvare un'immagine del grafico in vari formati, come PNG, PDF, SVG, EPS, e altro ancora.

Ecco un esempio di come si può salvare un grafico:

python
import matplotlib.pyplot as plt values = [1, 5, 8, 9, 2, 0, 3, 10, 4, 7] plt.plot(range(1, 11), values) plt.ioff() plt.savefig('MySamplePlot.png', format='png')

Qui, il grafico viene salvato in formato PNG. È possibile anche specificare un percorso per il salvataggio, nonché scegliere tra diversi formati di file. Questo approccio è molto utile per condividere i grafici con altre persone o per includerli in report o documenti.

Un altro aspetto importante nella creazione di grafici è la gestione degli assi, dei tick (le etichette sui vari punti degli assi) e delle griglie. Questi elementi non sono sempre necessari, ma in molti casi sono fondamentali per dare un contesto ai dati che vengono visualizzati. La comprensione dei valori e delle relazioni tra i vari punti diventa più facile quando i grafici sono ben strutturati, con assi etichettati correttamente e griglie che facilitano il confronto visivo.

Per esempio, se vogliamo regolare gli assi per avere valori specifici, possiamo farlo utilizzando le funzioni set_xlim() e set_ylim() per definire i limiti degli assi X e Y, rispettivamente. Inoltre, possiamo personalizzare i tick sugli assi utilizzando set_xticks() e set_yticks(). Ecco come:

python
import matplotlib.pyplot as plt plt.figure() values = [0, 5, 8, 9, 2, 0, 3, 10, 4, 7] ax = plt.axes() ax.set_xlim([0, 11]) ax.set_ylim([-1, 11]) ax.set_xticks([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
ax.set_yticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
plt.plot(
range(1, 11), values) plt.show()

In questo esempio, stiamo impostando i limiti degli assi e i tick su specifici valori per una visualizzazione più chiara. Modificando gli assi, possiamo concentrarci su intervalli specifici e migliorare la leggibilità dei grafici.

Per facilitare ulteriormente la lettura dei grafici, possiamo aggiungere una griglia che aiuta a individuare più facilmente i valori precisi sui grafici. Le griglie non sono sempre necessarie, poiché possono anche aggiungere “rumore” visivo, ma quando utilizzate con moderazione, sono uno strumento molto utile per il confronto visivo tra i dati. L’aggiunta di una griglia può essere fatta con il seguente codice:

python
import matplotlib.pyplot as plt
plt.figure() values = [0, 5, 8, 9, 2, 0, 3, 10, 4, 7] ax = plt.axes() ax.set_xlim([0, 11]) ax.set_ylim([-1, 11]) ax.set_xticks([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) ax.set_yticks([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) plt.grid(True) # Aggiungi una griglia plt.plot(range(1, 11), values) plt.show()

In questo modo, ogni punto del grafico sarà facilmente identificabile e comparabile grazie alle linee della griglia, che aiutano a determinare le coordinate precise dei dati. Sebbene le griglie possano rendere il grafico più complesso, offrono un grande vantaggio quando è necessario un livello di dettaglio maggiore.

Infine, va notato che il modo in cui visualizziamo e interagiamo con i grafici può variare a seconda dell'ambiente in cui lavoriamo. In ambienti come Jupyter Notebook, è possibile interagire con i grafici direttamente, zoomando e panando, cosa che rende l'esplorazione dei dati più dinamica e immediata. Tuttavia, la stessa interazione potrebbe non essere disponibile su altre piattaforme come Google Colab.