# Distributori Automatici Si consideri il seguente schema: - Bevanda(**Codice**, Nome, Prezzo, QtaCL) - Vendita(**CodDistributore**, **Data**, **Ora**, CodBevanda, QtaZucchero, UsoChiavetta) - Distributore(**Codice**, CapienzaCL, DataRifornimento, OraRifornimento) **Domanda 1.** Trovare i codici delle bevande vendute il 15-7-2016. ```sql= -- Soluzione 1 select CodBevanda from Vendita where Data = '2016-07-15'; -- Soluzione 2 select distinct CodBevanda from Vendita where Data = '2016-07-15'; -- Soluzione 3.1 select Codice from Vendita join Bevanda on CodBevanda = Codice where Data = '2016-07-15'; -- Soluzione 3.2 select Bevanda.* from Vendita join Bevanda on CodBevanda = Codice where Data = '2016-07-15'; ``` --- **Domanda 2.** Trovare il codice del distributore e il codice della bevanda delle vendite effettuate nell’agosto 2016. ```sql= -- Soluzione 1 select CodDistributore, CodBevanda from Vendita where Data >= '2016-08-1' and Data <= '2016-08-31'; -- Soluzione 2 select CodDistributore, CodBevanda from Vendita where Data between '2016-08-1' and '2016-08-31'; -- Soluzione 3 select distinct CodDistributore, CodBevanda from Vendita where Data >= '2016-08-1' and Data <= '2016-08-31'; ``` Attenzione: `Data = '2016-08'` (o simili) è sbagliato! --- **Domanda 3.** Trovare la bevanda più costosa. ```sql= -- Soluzione 1 select Codice from Bevanda where Prezzo = (select max(Prezzo) from Bevanda); -- Soluzione 2 select * from Bevanda where Prezzo >= all (select Prezzo from Bevanda); ``` Attenzione: nella soluzione 2, non usare `all` è sbagliato, in quanto la subquery restituirebbe più di una riga! --- **Domanda 4.** Trovare le vendite fatte dai distributori successivamente al rifornimento. ```sql= -- Soluzione 1 select Vendita.* from Vendita join Distributore on CodDistributore = Codice where Data > DataRifornimento or (Data = DataRifornimento and Ora > OraRifornimento); -- Soluzione 2 select * from Vendita V where Data > (select DataRifornimento from Distributore D where D.Codice = V.CodDistributore) or Data = (select DataRifornimento from Distributore D where D.Codice = V.CodDistributore) and Ora > (select OraRifornimento from Distributore D where D.Codice = V.CodDistributore); ``` Attenzione: in questo caso l’uso delle subquery è giusto in quanto grazie al `where` siamo sicuri che la subquery restituisca un valore solo (per la tabella Distributore la chiave primaria). --- **Domanda 5.** Trovare i distributori che non hanno mai venduto niente. ```sql= -- Soluzione 1 select * from Distributore where Codice not in (select CodDistributore from Vendita); -- Soluzione 2 select * from Distributore where Codice <> all (select CodDistributore from Vendita); ``` --- **Domanda 6.** Trovare i distributori che non hanno effettuano alcuna vendita dopo il rifornimento. ```sql= -- Soluzione 1 select * from Distributore where Codice not in (select Codice from Distributore join Vendita on Codice = CodDistributore where Data > DataRifornimento or Data = DataRifornimento and Ora > OraRifornimento); -- Soluzione 2 select * from Distributore D where Codice not in ( select CodDistributore from Vendita V where V.Data > D.DataRifornimento or (V.Data = D.DataRifornimento and V.Ora > D.OraRifornimento) ); ``` --- **Domanda 7.** Trovare i distributori che non hanno mai venduto la bevanda di codice ‘B1’. ```sql= -- Soluzione 1 select * from Distributore where Codice not in ( select CodDistributore from Vendita where CodBevanda = 'B1'); ``` --- **Domanda 8.** Trovare i distributori che hanno venduto solo la bevanda “coca-cola” ```sql= -- Soluzione 1 select Distributore.* from Distributore join Vendita on CodDistributore = Codice where Codice not in ( select CodDistributore from Vendita join Bevanda on CodBevanda = Codice where Nome <> 'coca-cola' ); -- Soluzione 2 select distinct CodDistributore from Vendita where CodDistributore not in ( select CodDistributore from Vendita join Bevanda on CodBevanda = Codice where Nome <> 'coca-cola' ); -- Soluzione 3 select V.CodDistributore from Vendita V join Bevanda B on V.CodBevanda = B.Codice group by V.CodDistributore having count(distinct B.Nome) = 1 and max(B.Nome) = 'coca-cola'; ``` Attenzione: come mai non serve il controllo sul fatto che il codice del distributore ci sia nelle vendite? La join prende solo righe valide, altrimenti ci sono left join e right join. L'uso diretto di **`B.Nome = 'coca-cola'`** non è consentito, perché SQL non può verificare la condizione di un singolo valore **dopo il raggruppamento**, a meno che non venga chiarito come combinare i valori all'interno di ogni gruppo (con una funzione aggregata come `MAX`, `MIN`, ecc.). --- **Domanda 9.** Trovare i distributori che non hanno mai venduto ‘coca-cola’. ```sql= select * from Distributore where Codice not in ( select CodDistributore from Vendita join Bevanda on CodBevanda = Codice where Nome = 'coca-cola'); ``` Attenzione: restituisco anche i distributori che non hanno venduto nulla (visto che prendo i codici dei distributori dalla tabella Distributori). --- **Domanda 10.** Trovare le bevande che sono state vendute almeno due volte. ```sql= -- Soluzione 1 select CodBevanda from Vendita group by CodBevanda having count(*) >= 2; -- Soluzione 2 select distinct V1.CodBevanda from Vendita V1, Vendita V2 where V1.CodBevanda = V2.CodBevanda and (V1.CodDistributore <> V2.CodDistributore or V1.Data <> V2.Data or V1.Ora <> V2.Ora); ``` --- **Domanda 11.** Trovare i distributori che hanno fatto una sola vendita. ```sql= -- Soluzione 1 select CodDistributore from Vendita group by CodDistributore having count(*) = 1; -- Soluzione 2 (esclusione dai distributori -- che hanno fatto almeno due vendite) -- il distinct qua non serve select distinct CodDistributore from Vendita where CodDistributore not in ( select V1.CodDistributore from Vendita V1, Vendita V2 where V1.CodDsitributore = V2.CodDistributore and (V1.Data <> V2.Data or V1.Ora <> V2.Ora)); ``` --- **Domanda 12.** Trovare i distributori che hanno fatto almeno due vendite ma non hanno mai venduto ‘coca-cola’. ```sql= -- Soluzione 1 select distinct V1.CodDistributore from Vendita V1, Vendita V2 where V1.CodDistributore = V2.CodDistributore and (V1.Data <> V2.Data or V1.Ora <> V2.Ora) and V1.CodDistributore not in ( select CodDistributore from Vendita join Bevanda on CodBevanda = Codice where Nome = 'coca-cola' ) -- Soluzione 2 SELECT CodDistributore FROM Vendita WHERE CodDistributore NOT IN ( SELECT DISTINCT CodDistributore FROM Vendita JOIN Bevanda ON CodBevanda = Codice WHERE Nome = 'coca-cola' ) GROUP BY CodDistributore HAVING COUNT(*) >= 2; ``` --- **Domanda 12+1.** Trovare i distributori che hanno effettuato almeno una vendita per tutte le possibili bevande distribuite e distribuibili. ```sql= select CodDistributore from Vendita group by CodDistributore having count(distinct CodBevanda) = ( select count(*) from Bevanda); ```