# 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);
```