21st Jul 2022 Tempo di lettura: 12 minuti Le 5 principali domande di intervista su SQL CTE Tihomir Babic sql CTE lavori e carriera Indice Tabella per le domande 1, 2 e 3 Domanda di intervista 1: Trovare lo stipendio medio per reparto Soluzione Query Spiegazione della soluzione La tabella dei risultati Spiegazione del risultato È possibile interpretare allo stesso modo le altre righe del risultato. Domanda di intervista 2: Trovare lo stipendio più alto per reparto Soluzione Query Spiegazione della query risolutiva La tabella dei risultati Spiegazione del risultato Domanda di intervista 3: Trovare tutti i dipendenti sotto un manager specifico Soluzione Query Spiegazione della soluzione La tabella dei risultati La spiegazione dei risultati Tabelle utilizzate per le domande 4 e 5 Domanda di intervista 4: Trovare il numero medio di ordini Soluzione Query Spiegazione della soluzione La tabella dei risultati La spiegazione del risultato Domanda di intervista 5: Trovare il numero di giorni consecutivi con un ordine Soluzione Query Spiegazione della soluzione La tabella dei risultati Spiegazione del risultato Quando sono utili i CTE? Volete saperne di più sulle espressioni di tabella comuni di SQL? Ecco cinque domande (e soluzioni!) sulle CTE che (probabilmente) vi verranno poste durante un colloquio. Non sto dicendo che riceverete queste domande sulle CTE SQL a ogni colloquio di lavoro. Ma quando vi capiterà, probabilmente saranno proprio come le cinque che sto per illustrarvi. A parte le domande teoriche sulle CTE, non ci sono molte variazioni negli scenari CTE valutati dagli intervistatori. Esaminando questi cinque esempi, otterrete una buona base per superare il vostro colloquio! Per questo, è necessario sapere cosa sono le espressioni comuni di tabella SQL e come funziona la loro sintassi. Siete pronti a dare un'occhiata alle domande? Andiamo! Tabella per le domande 1, 2 e 3 Per la prima serie di domande, utilizzeremo la tabella employees. Ecco come appare: idfirst_namelast_namedepartmentsalarymanager_id 1AngelikaVoulesMarketing5,293.742 2RozelleSwynleyMarketing8,295.0818 3WarrenWilleyEngineering9,126.7219 4LynelleWhitenManagement Board10,716.15NULL 5ConsolataRomanLegal8,456.064 6HoebartBaldockResearch and Development4,817.3420 7StarleneWatkissAccounting6,541.484 8BardeRibbensMarketing4,852.872 9LornePhilipsenEngineering7,235.593 10PedroNaldrettResearch and Development5,471.6220 11BrinaDillingerMarketing6,512.172 12VerileSonleyResearch and Development4,574.4120 13NobleGeerlingResearch and Development8,391.1820 14GareyMacAdamAccounting3,829.887 15TheoSorrellEngineering6,441.673 16ErminieGellingResearch and Development8,590.7020 17LoralieKoopAccounting5,248.467 18CalAndreyManagement Board11,258.82NULL 19QuinceyGamellManagement Board11,366.52NULL 20JanithMcGiffieResearch and Development7,428.8319 Cosa dicono i dati? La prima riga, ad esempio, dice che Angelika Voules lavora nel settore Marketing e il suo stipendio è di 5.293,74. Il suo capo ha un ID manager pari a 2; consultando la colonna id, si scopre che il capo di Angelika Voules è Rozelle Swynley. Ci sono tre righe con valori NULL nella colonna manager_id: idfirst_namelast_namedepartmentsalarymanager_id 4LynelleWhitenManagement Board10,716.15NULL 18CalAndreyManagement Board11,258.82NULL 19QuinceyGamellManagement Board11,366.52NULL Significa che questi tre employees non hanno manager. Questo ha senso perché tutti e tre fanno parte del consiglio di amministrazione. Vediamo ora le domande del colloquio. Domanda di intervista 1: Trovare lo stipendio medio per reparto Utilizzando la tabella dipendenti, mostrare tutti i dipendenti, i loro reparti, gli stipendi e lo stipendio medio nel rispettivo reparto. Ordinare il risultato per reparto. Soluzione Query WITH avg_salary AS ( SELECT AVG(salary) AS average_salary, department FROM employees GROUP BY department) SELECT e.first_name, e.last_name, e.department, e.salary, avgs.average_salary FROM employees e JOIN avg_salary avgs ON e.department = avgs.department ORDER BY department; Spiegazione della soluzione Questa query utilizza una CTE denominata avg_salary per calcolare la retribuzione media per reparto. L'istruzione SELECT nella CTE raggruppa le righe per reparto e utilizza la funzione aggregata AVG() per calcolare la media per ogni reparto. Una volta ottenuta la media, la si combina con altre colonne della tabella employees per completare la risposta alla domanda dell'intervista. Per farlo, uniamo la tabella employees con la CTE, come faremmo con due tabelle qualsiasi. Selezioniamo le colonne first_name, last_name, department e salary dalla tabella employeese la colonna average_salary dalla CTE. Per comodità, utilizziamo degli alias per la tabella e la CTE. Infine, ordiniamo i risultati per reparto. La tabella dei risultati Ecco come appare il risultato: first_namelast_namedepartmentsalaryaverage_salary GareyMacAdamAccounting3,829.885,206.61 LoralieKoopAccounting5,248.465,206.61 StarleneWatkissAccounting6,541.485,206.61 WarrenWilleyEngineering9,126.727,601.33 LornePhilipsenEngineering7,235.597,601.33 TheoSorrellEngineering6,441.677,601.33 ConsolataRomanLegal8,456.068,456.06 CalAndreyManagement Board11,258.8211,113.83 QuinceyGamellManagement Board11,366.5211,113.83 LynelleWhitenManagement Board10,716.1511,113.83 AngelikaVoulesMarketing5,293.746,238.47 RozelleSwynleyMarketing8,295.086,238.47 BardeRibbensMarketing4,852.876,238.47 BrinaDillingerMarketing6,512.176,238.47 NobleGeerlingResearch and Development8,391.186,545.68 ErminieGellingResearch and Development8,590.706,545.68 VerileSonleyResearch and Development4,574.416,545.68 PedroNaldrettResearch and Development5,471.626,545.68 HoebartBaldockResearch and Development4,817.346,545.68 JanithMcGiffieResearch and Development7,428.836,545.68 Spiegazione del risultato Questa tabella ci dice che, ad esempio, lo stipendio di Starlene Watkiss è di 6.541,48, mentre lo stipendio medio nel suo reparto (Contabilità) è di 5.206,61. first_namelast_namedepartmentsalaryaverage_salary StarleneWatkissAccounting6,541.485,206.61 È possibile interpretare allo stesso modo le altre righe del risultato. Domanda di intervista 2: Trovare lo stipendio più alto per reparto Trovate il dipendente con lo stipendio più alto in ogni reparto. Indicare nome e cognome, stipendio e reparto. Soluzione Query WITH highest_salary AS ( SELECT first_name, last_name, department, salary, RANK () OVER (PARTITION BY department ORDER BY salary DESC) AS salary_rank FROM employees) SELECT first_name, last_name, salary, department FROM highest_salary WHERE salary_rank = 1; Spiegazione della query risolutiva Questa volta la CTE si chiama highest_salary. La utilizziamo per classificare i dipendenti di ciascun reparto in base allo stipendio. Come? Utilizzando la funzione finestra RANK(). Si partizionano i dati in base alla colonna reparto. Ciò significa che classifichiamo gli stipendi solo all'interno di ciascun reparto, non in tutta l'azienda. I dati sono ordinati in base alla colonna stipendio in ordine decrescente, perché vogliamo che il più alto salary nel reparto abbia il rango 1. Selezioniamo anche diverse colonne dalla tabella employees nella stessa CTE. Abbiamo bisogno dei dati di questa CTE nella prossima istruzione SELECT. In questa istruzione SELECT selezioniamo le colonne necessarie per rispondere alla domanda dell'intervista. Tutte le colonne provengono dalla CTE. Filtriamo il risultato utilizzando la clausola WHERE per ottenere solo le righe in cui il grado di stipendio è 1, ovvero le righe con lo stipendio più alto. La tabella dei risultati first_namelast_namesalarydepartment StarleneWatkiss6,541.48Accounting WarrenWilley9,126.72Engineering ConsolataRoman8,456.06Legal QuinceyGamell11,366.52Management Board RozelleSwynley8,295.08Marketing ErminieGelling8,590.70Research and Development Spiegazione del risultato Non è difficile interpretare il risultato. Prendiamo come esempio questo dipendente: first_namelast_namesalarydepartment ConsolataRoman8,456.06Legal I dati mostrati ci dicono che Consolata Roman ha lo stipendio più alto nel reparto legale, pari a 8.456,06. Passiamo alla terza domanda di intervista SQL CTE. Domanda di intervista 3: Trovare tutti i dipendenti sotto un manager specifico Trovare tutti i dipendenti che lavorano direttamente o indirettamente sotto il dipendente il cui ID è 18. Soluzione Query WITH RECURSIVE subordinates AS ( SELECT id, first_name, last_name, manager_id FROM employees WHERE id = 18 UNION SELECT e.id, e.first_name, e.last_name, e.manager_id FROM employees e JOIN subordinates s ON e.manager_id = s.id ) SELECT * FROM subordinates WHERE id != 18; Spiegazione della soluzione In questo esempio, non si tratta di una normale CTE, ma di una CTE ricorsiva per ottenere il risultato. La differenza di sintassi è WITH RECURSIVE invece di WITH. La CTE si chiama subordinatese poi viene aggiunta l'istruzione SELECT, proprio come nelle CTE non ricorsive. Questa istruzione seleziona alcune colonne della tabella employees ma solo per il dipendente il cui ID è 18. Quindi, si utilizza l'operatore UNION per collegare il risultato di questa istruzione SELECT con il risultato di un'altra istruzione SELECT. Per questo, entrambe le istruzioni SELECT devono avere le stesse colonne. La seconda istruzione SELECT nella CTE seleziona le colonne in cui manager_id (dalla tabella employees) è uguale a id (dalla CTE). Si ottengono tutti i dati relativi al dipendente il cui ID è 18. Poi troviamo i subordinati diretti e, per ricorsione, i subordinati dei subordinati, fino a scendere nella gerarchia dell'organizzazione. Quindi prendiamo le colonne dei subordinati della CTE e rimuoviamo il dipendente il cui ID è 18. Ecco fatto! La tabella dei risultati idfirst_namelast_namemanager_id 2RozelleSwynley18 1AngelikaVoules2 8BardeRibbens2 11BrinaDillinger2 La spiegazione dei risultati Il capo diretto di Rozelle Swynley è il dipendente il cui ID del manager è 18. Ma Rozelle ha anche dei subordinati. Si tratta di Angelika Voules, Barde Ribbens e Brina Dillinger. Lo sappiamo perché la tabella mostra che l'ID del loro manager è 2, ovvero l'ID di Rozelle Swynley. Sono i diretti subordinati di Rozelle Swynley e sono anche i subordinati indiretti del dipendente il cui ID è 18. Il dipendente il cui ID è 18 è Calle Ribbens e Brina Dillinger. Il dipendente il cui ID è 18 è Cal Andrey, che non viene mostrato nel risultato perché viene filtrato nella clausola WHERE. Tabelle utilizzate per le domande 4 e 5 Per le ultime due domande del colloquio, utilizzeremo le tabelle customers e orders. La tabella customers si presenta come segue: idfirst_namelast_name 1SimonPaulson 2DylanBobson 3RebMackennack La tabella orders è un po' più grande: idorder_dateorder_amountcustomer_id 12021-10-0142.123 22021-10-01415.631 32021-10-0284.992 42021-10-0228.963 52021-10-0254.311 62021-10-0374.261 72021-10-0377.772 82021-10-0355.703 92021-10-0416.943 102021-10-0451.441 112021-10-0541.583 122021-10-0695.001 Questa seconda tabella contiene i dati relativi agli ordini effettuati. La colonna customer_id è una chiave esterna alla chiave primaria della prima tabella, in modo da poter identificare il cliente che ha effettuato l'ordine. Prendiamo come esempio la prima riga: idorder_dateorder_amountcustomer_id 12021-10-0142.123 Si tratta di un ordine effettuato il 1° ottobre 2021. Il valore della merce ordinata è di 42,12 e l'ordine è stato effettuato da un cliente il cui ID è 3. Dalla tabella si evince che si tratta di Reb Mackackack. customerssi vede che si tratta di Reb Mackennack. Vediamo i compiti da risolvere utilizzando queste tabelle. Domanda di intervista 4: Trovare il numero medio di ordini Questa domanda chiede di utilizzare un'espressione di tabella comune SQL per trovare il numero medio di ordini per cliente. Soluzione Query WITH orders_count AS ( SELECT customer_id, COUNT(*) AS no_of_orders FROM orders GROUP BY customer_id) SELECT AVG(no_of_orders) AS avg_no_of_orders FROM orders_count; Spiegazione della soluzione Per ottenere il risultato, occorre innanzitutto contare il numero di ordini per cliente. A tale scopo si utilizza la funzione CTE orders_count e la funzione COUNT(). Questa funzione conta il numero di righe nella tabella orders. Poiché non siamo interessati al conteggio totale degli ordini, ma piuttosto al numero di ordini per cliente, raggruppo il risultato in base alla colonna customer_id. Ora che abbiamo il numero di ordini, è facile calcolare il numero medio. È sufficiente utilizzare la funzione AVG() nell'istruzione SELECT per ottenere la risposta alla domanda. La tabella dei risultati avg_no_of_orders 4 La spiegazione del risultato Una tabella molto piccola richiede una spiegazione molto breve. La tabella precedente mostra semplicemente che il numero medio di ordini per cliente è quattro. Domanda di intervista 5: Trovare il numero di giorni consecutivi con un ordine In questo esempio CTE, si deve calcolare per quanti giorni di fila ogni cliente effettua un ordine. In pratica, si chiede di calcolare la lunghezza di una serie contigua senza spazi vuoti. Si noti che tutti gli ordini si riferiscono allo stesso mese. Soluzione Query WITH groupings_by_date AS ( SELECT c.id, c.first_name, c.last_name, RANK() OVER (PARTITION BY c.id ORDER BY o.order_date) AS row_number, o.order_date, EXTRACT(DAY FROM o.order_date) - RANK() OVER (PARTITION BY c.id ORDER BY o.order_date) AS date_group FROM customers c JOIN orders o ON c.id = o.customer_id ) SELECT id, first_name, last_name, COUNT(*) AS orders_in_row FROM groupings_by_date GROUP BY id, first_name, last_name, date_group; Spiegazione della soluzione Questa query piuttosto lunga inizia con una CTE. Seleziona alcune colonne dalle tabelle customers e orders. C'è la funzione RANK() come nella domanda 2. Questa volta, utilizziamo questa funzione per assegnare un numero di riga a ogni ordine all'interno dello stesso cliente. Per questo motivo, i dati vengono suddivisi in base all'id della colonna. La classificazione viene eseguita in base alla data dell'ordine (vogliamo che la classificazione sia sequenziale). L'altra funzione utilizzata è EXTRACT(). Il suo scopo è quello di estrarre la parte del giorno dalla data dell'ordine in modo da poterne dedurre il numero di riga. Perché lo facciamo? Stiamo semplicemente dando a un gruppo di ordini consecutivi un nome comune date_group. Se si esegue solo questa CTE, le prime due righe del risultato appaiono come queste: idfirst_namelast_namerow_numberorder_datedate_group 1SimonPaulson12021-10-010 1SimonPaulson22021-10-020 Come si può notare, Simon Paulson ha effettuato ordini sia il 1° che il 2 ottobre 2021. Poiché sono stati effettuati due giorni di seguito, appartengono allo stesso date_group. Come si ottiene questo dato? È il giorno estratto da order_date meno row_number. Nella prima riga, il giorno della data '2021-10-01' è 1. Anche il numero della riga è 1. Quindi, è 1-1 = 0, che è anche il valore in date_group. La seconda riga è 2-2 = 0, che è lo stesso date_group di cui sopra. Il valore specifico di date_group non ha molta importanza! È importante solo che i giorni consecutivi abbiano lo stesso valore date_group. Questo è un piccolo trucco per calcolare la lunghezza di una serie. Funziona perché, se gli ordini vengono effettuati ogni giorno, la differenza tra il numero di giorni in order_date e il valore in row_number è sempre la stessa per lo stesso cliente. Si noti che questi dati non appaiono da nessuna parte. Lo mostro solo per spiegare meglio cosa fa la CTE. È importante sottolineare che questo trucco funziona solo se i dati sono tutti dello stesso mese. Se la serie, ad esempio, inizia il 2021-10-31 e arriva al 2021-11-01, il trucco non funziona; questi due giorni, anche se sono uno dopo l'altro, non appartengono allo stesso date_group. Quindi, prima di decidere di utilizzare questo trucco per ottenere la lunghezza di una serie, è necessario comprendere i propri dati. Una volta ottenuta la CTE, utilizzatela come una tabella nell'istruzione SELECT. Utilizzerò la funzione COUNT() per ottenere il numero di ordini in una riga. Voglio vedere il risultato per ogni cliente, quindi raggruppo i dati per id, first_name e last_name. Raggruppo anche per la colonna date_group, in modo che gli ordini effettuati dallo stesso cliente vengano separati se c'è uno spazio tra loro. La tabella dei risultati idfirst_namelast_nameorders_in_row 1SimonPaulson4 3RebMackennack5 2DylanBobson2 1SimonPaulson1 Spiegazione del risultato Questa tabella mostra che Simon Paulson ha effettuato quattro ordini di fila. Reb Mackennack lo ha fatto per cinque giorni di fila, mentre Dylan Bobson ha effettuato solo due ordini di fila. Infine, c'è un ulteriore ordine di Simon Paulson. Quando sono utili i CTE? Come si vede in questi esempi, le CTE sono molto utili quando si deve calcolare qualcosa in almeno due fasi. Si usa una CTE per preparare il calcolo preliminare e poi si usa semplicemente l'istruzione SELECT, si fa riferimento alla CTE e si esegue un altro livello di calcolo. Nei calcoli più complessi, si possono usare anche più CTE o addirittura CTE annidate. È simile alle subquery, ma le CTE rendono il codice più leggibile e più facile da suddividere in fasi. Inoltre, con le CTE annidate, è possibile scrivere una query e fare immediatamente riferimento ad essa come a qualsiasi altra tabella. Alcuni di questi esempi mostrano che è possibile utilizzare anche funzioni di aggregazione e di finestra. Questo rende le CTE più potenti. Inoltre, le CTE sono ottime per i dati gerarchici, come le strutture organizzative, e per l'attraversamento di un grafo. In questi casi, tuttavia, è necessario scrivere una CTE ricorsiva, come ho fatto nella domanda 3. Infine, se volete scrivere query ricorsive e utilizzarle, il primo passo è imparare le CTE. Se avete bisogno di aiuto, ecco una guida su come imparare le CTE. Come si può vedere, le CTE hanno molti vantaggi e utilizzi pratici. Questi esempi mostrano solo un assaggio di soluzioni a problemi pratici che richiederebbero molto più tempo se non fosse per le CTE. Ne volete altri? Nessun problema, date un'occhiata ad altri usi pratici delle CTE. Una volta imparate le CTE e iniziate a usarle, cercate di pensare prima al problema. Scomponete le fasi di calcolo e poi traducete questa logica in un codice di espressione di tabella comune SQL. Le CTE sono adatte a questo scopo. Poiché si tratta di una versione delle tabelle temporanee, è necessario essere chiari nel nominarle: utilizzare un nome che indichi immediatamente l'attività della CTE ed essere coerenti con le convenzioni di denominazione. In generale, è bene seguire le best practice delle CTE, che facilitano la lettura del codice da parte vostra (e degli altri!). Volete saperne di più sulle espressioni di tabella comuni di SQL? Se vi state preparando per un colloquio di lavoro in SQL, se volete migliorare il vostro attuale lavoro o semplicemente se volete imparare qualcosa di nuovo nel tempo libero, date un'occhiata al nostro Recursive Queries corso. Qui troverete un approccio sistematico alle CTE, che vi spiegherà la teoria alla base, vi mostrerà la sintassi e vi fornirà alcuni esempi per fare pratica. L'intero corso fa parte della Advanced SQL che tratta altri due argomenti: le funzioni di finestra (che abbiamo usato in questo articolo) e le estensioni di GROUP BY. Buona fortuna! Tags: sql CTE lavori e carriera