diff --git a/.gitignore b/.gitignore index 86176dc..d2cb545 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # ---> TeX out/ +# SQLite database files +*.db + ## Core latex/pdflatex auxiliary files: *.aux *.lof diff --git a/compitino/main.tex b/compitino/main.tex index 4ca9dd3..6c5c6fe 100644 --- a/compitino/main.tex +++ b/compitino/main.tex @@ -4,6 +4,7 @@ \usepackage{enumitem} \usepackage{forest} \usepackage{graphicx} +\usepackage[hidelinks]{hyperref} \usepackage[utf8]{inputenc} \usepackage{listings} \usepackage{pxfonts} @@ -11,6 +12,8 @@ \usepackage[normalem]{ulem} \usepackage{geometry} +\AfterEndEnvironment{figure}{\noindent} + \geometry{ a4paper, top=30mm, @@ -18,7 +21,13 @@ top=30mm, \forestset{qtree/.style={for tree={parent anchor=south, child anchor=north,align=center,inner sep=0pt}}} -\lstset{upquote=true,showstringspaces=false} +\lstset{ + upquote=true, + inputencoding=utf8, + extendedchars=true, + literate={à}{{\`a}}1, % Accept à in `lstlisting` environments + showstringspaces=false +} \lstdefinestyle{SQLu}{ language=SQL, basicstyle=\small\ttfamily, @@ -34,17 +43,22 @@ top=30mm, % First page information -\title{\textbf{Basi di dati prof. Ghelli}\linebreak\textit{``Sempre sul pezzo"}} +\title{\textbf{Basi di dati prof. Ghelli}\linebreak\textit{``Una cervecita fresca"}} \author{Davide Testa 613565} -\date{2020-05-15} +\date{2020-06-01} \begin{document} \maketitle % Insert the title, author and date + \input{\folder/source_code.tex} \section{Descrizione di massima del dominio (testo)}\label{sec:testo} \input{\folder/testo.tex} + \clearpage \section{Descrizione del dominio}\label{sec:dominio} \input{\folder/dominio.tex} +% \clearpage \section{Schema concettuale}\label{sec:schema-concettuale} + La figura~\ref{fig:schema-concettuale} mostra lo schema concettuale in formato + grafico. \begin{figure}[hb] \centering \includegraphics[width=\linewidth]{\folder/schema_concettuale.pdf} @@ -52,11 +66,14 @@ top=30mm, \label{fig:schema-concettuale} \end{figure} \input{\folder/schema_concettuale.tex} - \section{Schema logico}\label{sec:schema-logico} + \clearpage + \section{Schema logico relazionale}\label{sec:schema-logico} + La figura~\ref{fig:schema-logico} mostra lo schema logico relazionale in + formato grafico.\\ \begin{figure}[htb] \centering \includegraphics[width=\linewidth]{\folder/schema_logico.pdf} - \caption{Schema logico in formato grafico} + \caption{Schema logico relazionale in formato grafico} \label{fig:schema-logico} \end{figure} \input{\folder/schema_logico.tex} @@ -66,4 +83,6 @@ top=30mm, \vskip2pc \section{Piani di accesso}\label{sec:piani} \input{\folder/piani_di_accesso.tex} + \vfill + \input{\folder/source_code.tex} \end{document} diff --git a/compitino/secondo_compitino/dominio.tex b/compitino/secondo_compitino/dominio.tex index 17aef8d..10f93e5 100644 --- a/compitino/secondo_compitino/dominio.tex +++ b/compitino/secondo_compitino/dominio.tex @@ -1,5 +1,75 @@ % !TEX root = ../main.tex -Descrizione del dominio. +L'applicazione ``Una cervecita fresca" deve fornire supporto ai birrai e alle +birraie artigianali nella produzione delle loro birre fatte in casa con il +metodo all-grain. -Nominare le classi di interesse, specificarne gli attributi e indicarne le relazioni con le altre classi. \ No newline at end of file +Ogni utente dell'app (birraio o birraia) può lavorare per uno o più birrifici, e può +visualizzare le ricette dei birrifici per cui lavora. +Del birraio o birraia sono rilevanti il nome, il cognome, il soprannome, +l'indirizzo email, il codice fiscale. +Ogni birrificio ha un nome, un anno di fondazione, un motto e uno stemma. +Il birrificio ha inoltre una capacità produttiva, cioè il numero massimo di +litri che può produrre in un singolo ciclo produttivo. +Per ogni birrificio possono lavorare più persone. +Ogni birrificio può lavorare a una sola produzione per volta, mettendo a +disposizione tutta la sua capacità produttiva, o solo una parte di questa. + +Ogni birrificio ha accesso a una o più ricette: ogni ricetta ha un nome, un +creatore o creatrice, una data di creazione, una eventuale ricetta madre +(ovvero la ricetta che è stata modificata per elaborarla) e la quantità +relativa di ciascun ingrediente. +Oltre alla creatrice o creatore di una ricetta, anche le birraie e i birrai di +un birrificio possono vedere le ricette del birrificio in cui lavorano. +La ricetta può essere archiviata o eliminata dal creatore o creatrice: lo stato +della ricetta può essere attiva, archiviata, eliminata. + +Gli ingredienti sono moltissimi, ma di solo 5 tipi: malti, luppoli, lieviti, +zuccheri e additivi. +Ciascun tipo ha un nome e la sua unità di misura appropriata (per esempio, i +luppoli vengono espressi in \textit{mash}, ovvero grammi per litro di +miscuglio, mentre i malti sono espressi in peso percentuale sugli ingredienti +secchi). +Ciascun ingrediente ha un tipo e una descrizione. +In ogni ricetta, è indicata la quantità di ciascun ingrediente come numero +puro: l'unità di misura (mash, peso percentuale, \textellipsis) dipende dal +tipo di ingrediente. +La quantità di acqua è ricavabile dagli altri ingredienti e non occorre quindi +memorizzarla: si miscelano in proporzione gli ingredienti secchi, dal +\textit{mash} si capisce quale volume finale deve raggiungere la soluzione. + +La visualizzazione delle ricette terrà conto della quantità di prodotto che si +vuole produrre (che dev'essere inferiore o uguale alla capacità produttiva del +birrificio) per mostrare le quantità assolute dei vari ingredienti in kg e L; +nel database invece le quantità verranno memorizzate in termini relativi come +descritto sopra. + +Una produzione è caratterizzata da una data di produzione, un numero di lotto +che la identifica univocamente, il numero di bottiglie da 500 mL prodotte +(questo è l'unico possibile formato di produzione) e uno stato di preparazione +(in corso, completa, annullata). +È prodotta seguendo una ricetta di un birrificio. + +A ogni produzione si possono accompagnare alcune note. +Ogni nota ha un testo. +Esistono particolari note, dette di degustazione, che esprimono anche un +giudizio da 1 a 10 sulla qualità del prodotto. + +Il birrificio tiene un registro degli acquisti, conservando i dati della +fattura e specificando per ogni ingrediente acquistato la quantità. +Ogni fattura registrata dal birrificio è caratterizzata da una data, un numero +di fattura, un importo e un fornitore. +I fornitori hanno una ragione sociale, una partita IVA e un indirizzo. +L'inventario mostra, per ogni ingrediente, la quantità disponibile e quella +totale (compresi cioè gli ingredienti ``prenotati" da preparazioni in corso). + +Oltre che come birrario o birraia, ci si può anche registrare come cliente, +specificando un indirizzo di spedizione. +I clienti sono caratterizzati, come chi produce birra, da nome, cognome, email +e codice fiscale, ma non hanno un soprannome. + +La clientela può effettuare prenotazioni per una quantità di bottiglie di un +dato lotto di produzione. +Ogni prenotazione ha uno stato, che rimane in sospeso fino al termine della +produzione, quando il birrificio può impostarlo su `confermato' se intende +procedere alla vendita oppure `annullato' se il prodotto non è soddisfacente. diff --git a/compitino/secondo_compitino/piani_di_accesso.tex b/compitino/secondo_compitino/piani_di_accesso.tex index 3ae00b9..e1f2fda 100644 --- a/compitino/secondo_compitino/piani_di_accesso.tex +++ b/compitino/secondo_compitino/piani_di_accesso.tex @@ -3,33 +3,35 @@ \paragraph{Piano di accesso logico della query a} \begin{center} - \begin{forest} - [{$\pi^{b}$ R.C, S.D} - [{$\bowtie$ R.E = S.F} - [{$\sigma$ C $>=$ 10} - [Tabella1 R] + \begin{forest}, baseline, qtree + [{$\pi^{b}$ r.IdRicetta , r.Nome} + [{$\bowtie$ p.IdPersona = r.IdCreatrice} + [{$\sigma$ p.Nome = 'Giovanni'} + [Persone p] ] - [Tabella2 S] + [Ricette r] ] ] \end{forest} \end{center} +Non c'è in questo caso differenza tra $\pi^{b}$ e $\pi$: non ci possono essere +duplicati. \paragraph{Piano di accesso fisico della query a senza indici} \begin{center} - \begin{forest} - [{Project(\{C, D\})} - [{SortMerge(R.E = S.F)} - [{Sort(\{E\})} - [{Project(\{E, C\})} - [{Filter(C $>=$ 10)} - [{TableScan(Tabella R)}] + \begin{forest}, baseline, qtree + [{Project(\{r.IdRicetta , r.Nome\})} + [{SortMerge(p.IdPersona = r.IdCreatrice)} + [{Sort([p.IdPersona])} + [{Project(\{p.IdPersona\})} + [{Filter(p.Nome = 'Giovanni')} + [{TableScan(Persone p)}] ] ] ] - [{Sort(\{F\})} - [{Project(\{C, F\})} - [{TableScan(Tabella S)}] + [{Sort([r.IdCreatrice])} + [{Project(\{r.IdRicetta, r.Nome, r.IdCreatrice\})} + [{TableScan(Ricette r)}] ] ] ] @@ -40,12 +42,210 @@ \paragraph{Piano di accesso fisico della query a con due indici} \begin{center} \begin{forest}, baseline, qtree - [{Project(\{C, D\})} - [{IndexNestedLoop(R.E = S.F)} - [{IndexFilter(Tabella R,\\ IndRC, C $>=$ 10)}] - [{IndexFilter(Tabella S,\\IndSF, S.F = R.E)}] + [{Project(\{r.IdRicetta , r.Nome\})} + [{IndexNestedLoop(p.IdPersona = r.IdCreatrice)} + [{IndexFilter(Persone p,\\ IndPN, p.Nome = 'Giovanni')}] + [{IndexFilter(Ricette r,\\IndRC, r.IdCreatrice = p.IdPersona)}] ] ] \end{forest} \end{center} -Indici necessari: \texttt{IndRC} (indice della tabella R sull’attributo C) e \texttt{IndSF} (indice della tabella S sull'attributo F). \ No newline at end of file +Indici necessari: \texttt{IndPN} (indice della tabella Persone sull’attributo +Nome) e \texttt{IndRC} (indice della tabella Ricette sull'attributo Creatrice). + +\clearpage +\subsection{Query b} + +\paragraph{Piano di accesso logico della query b} +\begin{center} + \begin{forest}, baseline, qtree + [{$\tau$[-DiversiFornitori]} + [{$\pi^{b}$ fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori} + [{$\sigma$ COUNT(DISTINCT fa.IdFornitore) $>=$ 3} + [\{fa.IdBirrificio\} {$\gamma$ \{COUNT(DISTINCT fa.IdFornitore)\}} + [{$\sigma$ fa.Data $>=$ '2020-01-01'} + [Fatture fa] + ] + ] + ] + ] + ] + \end{forest} +\end{center} + +Non c'è in questo caso differenza tra $\pi^{b}$ e $\pi$: non ci possono essere +duplicati, in quanto la GROUP BY raggruppa per IdBirrificio. +\paragraph{Piano di accesso fisico della query b senza indici} +\begin{center} + \begin{forest}, baseline, qtree + [{Sort[-DiversiFornitori]} + [{Project(\{fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori\})} + [{Filter(COUNT(DISTINCT fa.IdFornitore) $>=$ 3)} + [{GroupBy(\{fa.IdBirrificio\}, \{COUNT(DISTINCT fa.IdFornitore)\})} + [{Sort([fa.IdBirrificio])} + [{Filter(fa.Data $>=$ '2020-01-01')} + [{TableScan(Fatture fa)}] + ] + ] + ] + ] + ] + ] + \end{forest} +\end{center} +Il sort sull'attributo dimensione di analisi prima della GroupBy è necessario, +in quanto non è garantito che i record della tabella Fatture siano raggruppati +per IdBirrificio. +Lo sarebbero se l'organizzazione primaria della tabella fosse sequenziale +proprio su questo attributo, il che è estremamente poco probabile. +\clearpage +\paragraph{Piano di accesso fisico della query b con un indice} +\begin{center} + \begin{forest}, baseline, qtree + [{Sort[-DiversiFornitori]} + [{Project(\{fa.IdBirrificio, COUNT(DISTINCT fa.IdFornitore) DiversiFornitori\})} + [{Filter(COUNT(DISTINCT fa.IdFornitore) $>=$ 3)} + [{GroupBy(\{fa.IdBirrificio\}, \{COUNT(DISTINCT fa.IdFornitore)\})} + [{Sort([fa.IdBirrificio])} + [{IndexFilter(Fatture fa, IndFD, fa.Data $>=$ '2020-01-01')}] + ] + ] + ] + ] + ] + \end{forest} +\end{center} +Indice necessario: \texttt{IndFD} (indice della tabella Fatture sull’attributo +Data). +Il sort sull'attributo IdBirrificio prima della GroupBy è necessario, in quanto +i record in input sono ordinati per data, il che non ci garantisce che siano +raggruppati per IdBirrificio (che è dimensione di analisi). + +\subsection{Query c} + +\paragraph{Piano di accesso logico della query c} +\begin{center} + \begin{forest}, baseline, qtree + [{$\pi^{b}$ fo.RagioneSociale, SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio} + [$\sigma$ SUM(fa.Importo) $>$ 10 + [{\{fo.IdFornitore, fo.RagioneSociale\} $\gamma$ \{SUM(fa.Importo), AVG(fa.Importo)\}} + [{$\bowtie$ fa.IdFornitore = fo.IdFornitore} + [{Fornitori fo}] + [{$\bowtie$ fa.IdBirrificio = b.IdBirrificio} + [{$\sigma$ b.Nome = 'Pirati Rossi'} + [{Birrifici b}] + ] + [{Fatture fa}] + ] + ] + ] + ] + ] + \end{forest} +\end{center} + +In questo caso non ci dovrebbe essere differenza tra $\pi^{b}$ e $\pi$: non ci +devono essere due fornitori con la stessa ragione sociale (la ragione sociale +è chiave naturale); è comunque possibile un errore di inserimento se non ho +impostato un vincolo di unicità anche su questo attributo, che non ho scelto +come chiave primaria della tabella: ecco perché ho raggruppato anche per +IdFornitore e non solo per RagioneSociale. + +Ho scelto l'ordine di giunzione in modo da avere la restrizione il più distale +possibile. + +\clearpage + +\paragraph{Piano di accesso fisico della query c senza indici} +\begin{center} + \begin{forest}, baseline, qtree + [{Project(\{fo.RagioneSociale,\\SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio\})} + [{Filter(SUM(fa.Importo) $>$ 10)} + [{GroupBy(\{fo.IdFornitore,fo.RagioneSociale\}, \{SUM(fa.Importo), AVG(fa.Importo)\})} + [{MergeSort(fa.IdFornitore = fo.IdFornitore)} + [{Sort([fo.IdFornitore])} + [{Project(\{fo.IdFornitore,\\fo.RagioneSociale\})} + [{Fornitori fo}] + ] + ] + [{Sort([fa.IdFornitore])} + [{Project(\{fa.IdFornitore, fa.Importo\})} + [{MergeSort(fa.IdBirrificio = b.IdBirrificio)} + [{Sort([b.IdBirrificio])} + [{Project(\{b.IdBirrificio\})} + [{Filter(b.Nome = 'Pirati Rossi')} + [{TableScan(Birrifici b)}] + ] + ] + ] + [{Sort([fa.IdBirrificio])} + [{Project(\{fa.IdBirrificio,\\fa.IdFornitore fa.Importo\})} + [{Fatture fa}] + ] + ] + ] + ] + ] + ] + ] + ] + ] + \end{forest} +\end{center} +Non è necessario ordinare per \texttt{[fo.IdFornitore, fo.RagioneSociale]} prima +della GroupBy: per costruzione, l'ordine dell'operatore esterno della SortMerge +viene mantenuto nell'output, e questo ordine è sull'attributo fo.IdFornitore, +che a sua volta determina funzionalmente l'altra dimensione di analisi, fo.RagioneSociale. + +Pertanto, è garantito che l'input della GroupBy sarà già raggruppato per gli +attributi che sono dimensione di analisi e non occorre un ordinamento +preventivo. + +\clearpage +\paragraph{Piano di accesso fisico della query c con tre indici} +\begin{center} + \begin{forest}, baseline, qtree + [{Project(\{fo.RagioneSociale,\\SUM(fa.Importo) ImportoTotale, AVG(fa.Importo) ImportoMedio\})} + [{Filter(SUM(fa.Importo) $>$ 10)} + [{GroupBy(\{fo.IdFornitore, fo.RagioneSociale\},\\\{SUM(fa.Importo), AVG(fa.Importo)\})} + [{Sorted([fo.IdFornitore])} + [{Project(\{fo.IdFornitore, fo.RagioneSociale, fa.Importo\})} + [{IndexNestedLoop(fa.IdFornitore = fo.IdFornitore)} + [{IndexNestedLoop\\(fa.IdBirrificio = b.IdBirrificio)} + [{IndexFilter(Birrifici b, IndBN,\\b.Nome = 'Pirati Rossi')}] + [{IndexFilter(Fatture fa, IndFaIdB,\\fa.IdBirrificio = b.IdBirrificio)}] + ] + [{IndexFilter(Fornitori fo, IndFoIdF,\\fo.IdFornitore = fa.IdFornitore)}] + ] + ] + ] + ] + ] + ] + \end{forest} +\end{center} +Indici necessari: \texttt{IndBN} (indice della tabella Birrifici sull’attributo +Nome), \texttt{IndFaIdB} (indice della tabella Fatture sull'attributo +IdBirrificio) e \texttt{IndFoIdF} (indice della tabella Fornitori sull'attributo +IdFornitore). + +Occorre ordinare per IdFornitore prima della \texttt{GroupBy}, in quanto +l'output della IndexNestedLoop è ordinato come l'operatore esterno, ovvero +per nome del birrificio. + +Potrei spostare l'ordinamento tra le due giunzioni con IndexNestedLoop, tanto +ogni fattura ha un fornitore e l'output non andrà a decrecere dopo la seconda +giunzione (anzi, si arricchirà di campi). +Il sort andrebbe fatto con il minor numero possibile di dati, dato l'alto costo +dell'algoritmo, eliminando i campi superflui con una project prima. + +Il vantaggio dell'IndexNestedLoop sul SortMerge si ha solo se la condizione è +sufficientemente restrittiva da essere soddisfatta da una piccola minoranza +di record. +In questo caso, la restrizione sul nome del birrificio dovrebbe essere +abbastanza restrittiva (se ci sono abbastanza birrifici, il numero di +birrifici con il nome `Pirati Rossi' sarà trascurabile rispetto al totale) ed +è ragionevole che le fatture che riguardano quel birrificio siano una esigua +minoranza rispetto al totale delle fatture. +Se così non fosse, pur avendo i tre indici a disposizione, converrebbe +utilizzare comunque il SortMerge. diff --git a/compitino/secondo_compitino/queries.tex b/compitino/secondo_compitino/queries.tex index 6a98470..b76c379 100644 --- a/compitino/secondo_compitino/queries.tex +++ b/compitino/secondo_compitino/queries.tex @@ -1,14 +1,122 @@ % !TEX root = ../main.tex \begin{enumerate}[label=\alph*.] - \item Uso di proiezione, join e restrizione + \item Uso di proiezione, join e restrizione. - Per ogni record di R con valore di C maggiore o uguale a 10 e che ha un valore di E uguale a un valore di F nella tabella S, riportare R.C e S.D. -\begin{lstlisting}[style=SQLu] -SELECT R.C, S.D -FROM Tabella1 R -JOIN Tabella2 S ON R.E = S.F -WHERE R.C >= 10 + Mostrare l'IdRicetta e il Nome delle ricette create da birrai di nome + Giovanni. +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT r.IdRicetta, r.Nome +FROM Ricette r +JOIN Persone p ON p.IdPersona = r.IdCreatrice +WHERE p.Nome = 'Giovanni' +\end{lstlisting} + \item Uso di group by con having, where e sort. + + Per ogni birrificio che abbia fatto almeno un acquisto quest'anno, + riportare l'IdBirrificio e il numero di diversi fornitori da cui ha + acquistato quest'anno, se questo numero è almeno di 3. + Ordinare il risultato dal birrificio che ha avuto più fornitori a quello + che ne ha avuti meno. +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT fa.IdBirrificio, + COUNT(DISTINCT fa.IdFornitore) DiversiFornitori +FROM Fatture fa +WHERE fa.Data >= '2020-01-01' +GROUP BY fa.IdBirrificio +HAVING COUNT(DISTINCT fa.IdFornitore) >= 3 +ORDER BY COUNT(DISTINCT fa.IdFornitore) DESC +\end{lstlisting} + \item Uso di join, group by con having e where. + + Dei fornitori da cui ha ordinato il birrificio `Pirati Rossi', mostrare la + ragione sociale, l'importo totale e l'importo medio delle fatture, purché + l'importo totale sia superiore a 10 euro. +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT fo.RagioneSociale, SUM(fa.Importo) ImportoTotale, + AVG(fa.Importo) ImportoMedio +FROM Fornitori fo +JOIN Fatture fa ON fa.IdFornitore = fo.IdFornitore +JOIN Birrifici b ON b.IdBirrificio = fa.IdBirrificio +WHERE b.Nome = 'Pirati Rossi' +GROUP BY fo.IdFornitore, fo.RagioneSociale +HAVING SUM(fa.Importo) > 10 +\end{lstlisting} + \item Uso di select annidata con quantificazione esistenziale. + + Mostrare il soprannome de* birrai* che siano aut*r* di almeno una ricetta. +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT b.Soprannome +FROM Birraie b +WHERE EXISTS (SELECT * + FROM Ricette r + WHERE r.IdCreatrice = b.IdPersona) +\end{lstlisting} +\clearpage + + \item Uso di select annidata con quantificazione universale. + + Mostrare il nome e il cognome de* clienti che hanno ordinato da un solo + birrificio. + +\textbf{Traduco in notazione insiemistica:} +\begin{lstlisting}[style=SQLu,escapechar=@] +{p1.Nome, p1.Cognome | (p1 @$\in$@ Persone, pre1 @$\in$@ Prenotazioni, + pre1.IdCliente = p1.IdPersona, + pro1 @$\in$@ Produzioni, + pro1.IdProduzione = pre1.IdProduzione, + r1 @$\in$@ Ricette, + r1.IdRicetta = pro1.IdRicetta) . + @$\forall$@ (pre2 @$\in$@ Prenotazioni, pre2.IdCliente = pre1.IdCliente + pro2 @$\in$@ Produzioni, pro2.IdProduzione = pre2.IdProduzione, + r2 @$\in$@ Ricette, r2.IdRicetta = pro2.IdRicetta) . + (r2.IdBirrificio = r1.IdBirrificio)} +\end{lstlisting} + +\textbf{Sostituisco il $\forall x . P$ con $\neg\exists x . \neg P$} +\begin{lstlisting}[style=SQLu,escapechar=@] +{p1.Nome, p1.Cognome | (p1 @$\in$@ Persone, pre1 @$\in$@ Prenotazioni, + pre1.IdCliente = p1.IdPersona, + pro1 @$\in$@ Produzioni, + pro1.IdProduzione = pre1.IdProduzione, + r1 @$\in$@ Ricette, + r1.IdRicetta = pro1.IdRicetta) . + @$\neg\exists$@ (pre2 @$\in$@ Prenotazioni, pre2.IdCliente = pre1.IdCliente + pro2 @$\in$@ Produzioni, pro2.IdProduzione = pre2.IdProduzione, + r2 @$\in$@ Ricette, r2.IdRicetta = pro2.IdRicetta) . + (r2.IdBirrificio @$\neq$@ r1.IdBirrificio)} +\end{lstlisting} + + \textbf{Scrivo quindi la query}, inserendo l'IdPersona e la parola chiave + \texttt{DISTINCT} per rimuovere i duplicati (ma non le persone omonime). +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT DISTINCT p1.IdPersona, p1.Nome, p1.Cognome +FROM Persone p1 +JOIN Prenotazioni pre1 ON pre1.IdCliente = p1.IdPersona +JOIN Produzioni pro1 ON pro1.IdProduzione = pre1.IdProduzione +JOIN Ricette r1 ON r1.IdRicetta = pro1.IdRicetta +WHERE NOT EXISTS (SELECT * + FROM Prenotazioni pre2 + JOIN Produzioni pro2 + ON pro2.IdProduzione = pre2.IdProduzione + JOIN Ricette r2 ON r2.IdRicetta = pro2.IdRicetta + WHERE pre2.IdCliente = pre1.IdCliente + AND r2.IdBirrificio <> r1.IdBirrificio) +\end{lstlisting} + + \item Uso di subquery di confronto quantificato. + + Per ogni birrificio, mostrare l'IdBirrificio e l'ultimo NumeroLotto + prodotto in quel birrificio (sapendo che il NumeroLotto è progressivo). +\begin{lstlisting}[style=SQLu,escapechar=@] +SELECT r1.IdBirrificio, pro1.NumeroLotto +FROM Produzioni pro1 +JOIN Ricette r1 ON r1.IdRicetta = pro1.IdRicetta +WHERE pro1.NumeroLotto >= ANY (SELECT pro2.NumeroLotto + FROM Produzioni pro2 + JOIN Ricette r2 + ON r2.IdRicetta = pro2.IdRicetta + WHERE r2.IdBirrificio = r1.IdBirrificio) \end{lstlisting} \end{enumerate} \clearpage \ No newline at end of file diff --git a/compitino/secondo_compitino/schema.drawio b/compitino/secondo_compitino/schema.drawio index 4ff91ba..d4b5c1e 100644 --- a/compitino/secondo_compitino/schema.drawio +++ b/compitino/secondo_compitino/schema.drawio @@ -1 +1 @@ -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 \ No newline at end of file +7V1tc9u2sv41num5M/YQ4PvHxIlzPCdOe+xkevqRkRgZrUSqFNXE+fUXlAiK4kIiJBAEaaHTaS1KoiQ8u9hnF/tyZd8ufnzIouXzQzqN51fYmv64st9dYYxsz6X/K668bK/Y2NtemGVkWr5od+GJ/IzLi1Z5dU2m8Wp7rbyUp+k8J8vV3rsnaZLEk3zvWpRl6ff9l31L5/ufuoxmMbjwNInm8OrvZJo/b68G2N9d/3dMZs/sk5EXbp9ZROzF5ddePUfT9Hvtkv3+yr7N0jTf/rX4cRvPi8Vj67J9392BZ6svlsVJLvKGt0v7p/32ze9vn35+CL9kNnn8++XaKeFZ5S/sF8dTugDlwyRN6P/eZuk6mcbFfSz6KM3y53SWJtH8Y5ou6UVEL/4Z5/lLCV+0zlN66TlfzMtnV3mU5W8KOOiF948/4yz9nD5EyQt77o7M2WvjZLp75SJKpr9uvgO9XL7I2j4qP8yjj+gdZnH+W5yRRZzH2dMympBkVr50lWfpXxV4xSfAlSsXc5Wus0l8ZLlQUIrg5gOPvLAUj2Ita59QAvMhTun3zF7oC7J4HuXkn31hi0qZnVWv28FK/yiRPQFl7zjKO0Df764a0KvVQ4Kgu3hYqAf963Z50zq81j68X+fp5K/BQOsJQstkYCDQ+p7Ztk+BORSEGdmDgjmwzb7dA+r+sKy1HxrlPgFmht7IOFmAAcoG0lMhDaxBYYosR/uG3c7Ayld0iDQFOHv5X/H0jcse/lHdmD5492Pv0Uv5SMIRExSQsHNKvnkrXcropfaCZUqSfFW782/FBfqCMg5yzYIAZRQEOw1fHb7+6BvoH9uvsJPV6rdIiO/2I/+J5mu29oR+ComBUK++k8U82ojRtzTJmXwXsjB5JvPpx+glXRe4UDGc/MUevX1OM/KTvj7ak9xS7rC394qn4p2lnGTxir7mNyYnqHHpIfqx98KP0SovL0zS+TxarsjX6vstqMiQ5G2a5+mifFE0J7OE/j2h94oz9pu23wo5x+T0nzjL4x9HBYsh6u4Dyh5+3wWVkFdee64FlJhP2fle5QCwn9JlFiUJvT/Am/7IvNL823SeZrt95BvdRBqXVtv94mP8rfgVzu7KY/nDikspXbxv882O9Eym0zjZbIV5lEdbsApkSr2i38F9S/+l63NbbDEu/U639DHaPab/Fi/P8ts0oV8zIhukYioJ3+NCGvYwxVxMj+pEO9BMUz0xYNnrOgc2DACydCNfFcgYNZZWYxzs63EoqMfItlThHQK8Pxkd5mrEeJQYMftfQ/U2nZnNWRJYZk41AosBsO8XEZkbWCVg9QPtsNocfZ2SSXxHVpvTRAPv+fBWfrU+UgW19nZO6O8khlR1T6qqx9q8o9AHeN8nU0IB+Jk+LeMp+Ul4hPqClRoLo66BY/2efZg5c/zm/vuX28l/fv8z+1bs2ZA4A0Dr0btC2/OXx02gKE3qEbzmmtViczDu1gjSHgq9HtSresyL+7ts0UB3feUtns/CLp4WHAPRLMduxj4avtA23Fe+60hYzPFbblTGLZs3OiNAxl1ZDEk5kBgxWeAF51siuAcFoh4s5QtEMDSBaOKIzxUIHN6EYeD6yMHFf93jt1UtHtBonC0eVAZOkg7BzaNdVsKhy4qjRlaat1UtKzBKJ7mV/AqtS6usCB/T8WXFG7isOIESWQG3VSwrtgtk5TbKpiSh5Dy/urWv3lhAdkomWhMZwOQLqkaob/qmfGJB2eX2QLLwFA6yy4JAFmeQq1Iyu/EBHKexxpwDEp/HDjsIqx4V7tqi/1LwavSv8a91w92q1Ka21k6vaw0N5y/ola4158Cg37WGhmcj18nrW2sX6V5r6GFu5Po1rrXd31rzI7AwQgcWWd43a0+qOpVZSaW3DM3TR3YzzcHdv4UoAUOOd/xG3VEu7sJiWDGhLztv75WdiZhoKUv3OdEtKVRdY+kggOUA6iBasvA2sfWDaXib3avLjEvbUQJyayjQtnGvem3DtKf/rqMisHvAj6L3JMtVgdT3Z5LHBQTFM9+zaNlirjswsnbzXMSzbqzaPwiYXO7u3gxtdGZzXZOpfoqSsdOq9i1XNGDbT1qz4x+F2ZShdGRo+9mCcYOiVY9P5Wj0nxsbW46DwiAIXYuFNNmhvYtvwvo/Qhv9qZnVGIf7v8Y6nlndsD+Nl6vJqw40bJM6ygDO15FAtOBjaAV6MHD1mSzTIyxi9Rwti4vTdE0d9vfV9W3qBX3C1kM1/CYxs6A/3y+5CDlkzGjNnvTpc+HktAaGIL8kjIG/Iw9ktc6i16BDnm4dQnClH8mE6oOpBZCHG9Ro+eE+4RFMWqyyG7v3z2BFlykN4CvIINPW+KFJmIT0jq7qbRZHJilRFl3t9QEO3LHptplDSmlQHVF5AMYA1YdomkFd3cs3nX9Nv3caUhE9VeCGXn4F1Hhzy+JL0r/Z4eROsAr7f7VXGx7aAbvwR/WNDleHbx5VNJpd/EHy7d0szy4fVzejf+/uVTx4qT1o3ulEaWtl444oG3c6j+4dOENrBnrwfvTYaki7aNznunljFBy/cUehnkYwHPVSEg/Leu6TWRZPTe1HNyTatZpxB0F+paz0A8GYzrt4NclMycch3RgPd2ZCU6+Nz9Lpmg+t0eZTtfm6GV4XLeRSVx7vwhPfwl06AvvlanSlHiPSaJgb/Wm9oIT1YyH7BlsJbLX7wh6MdBhfWBZV7b4wQjCzfquyhbkiszmn35QBeEzF8pBAF33EyDcyMR5Th8cOrZzKVQUwjFGaYwWuBoyHR8FKhTdJkt6lydScKsiCq51IIUikHgw9lgN1ADyKw47jxQJmThhUR0SeXKirt1Gx/mV+zCZwQXnyPwZnGZw55Wo9O7ccizv5e01W5lihA5LcPFZAon06lR0r+FCvj1eeXK42V6oxHvrsQ5/3LsrzNeeI3yjzqcrcLBoTRVtdYp0PPeDiUMHoMFSI8ehwcCguudVkg64Mutp94BC6S/eLYmmMFyyDq3Y3OIC86i7NEpJTa2hsr7Tt9fyh2d4AKvJjNCtilE/phJhWy1zlGJEVhvkaVFuomxTdm5CHFLTaTXAAczWqpsoGWQlktRthZEHuPEmX9AfweDOr35uTpJgEO6RiTLaCzg3edX8s/nvMmra3ALBEGzWxPDrrBiEW4C9BrgL+NZRdXgSrm1ZO107D8J/bJqA5+6yakN6SHr67EXth+u3bKlbSFqYC6Fj3sDwjUTLbVGK0FJfSPS2eFE3Ci2e3e0EHVIwKwH6vA8T6r9T13uWovarcSg9SsU+pqS3tAOtmbSmvHWq/8WsPA6w/U9E2hpujDuNh2x4n5kU1+F08W1NlM2nxarS5ajauT5uhvftA1puxJkahoXaMR6ERgjPjTSuuiuaVhEnD3GBJ/wpmC/xGf3+63aNNoLMDdt2sL3Ww4CbNvG8Fugw5lymAOKQZY9qjYSDM5IJ0hq/2OCdCDkDw9fdFZZ0Z2N9/sJse7MrQhyFnwjAUQ47keqmi1yApEri7tiDuyHO7Bn7z1lObViDciKMils10sPU9eAdrA62200XV6MR0+T2ry6+4ZFoD25IG2Z726zwt3IuhoOuKohsMq9cmwpBNCjaZunRb4yNRzF01HZ1OtjWo2SLJK88M1VqOakkNp1ErZ/7Q9hZ4SPr6/RwZpDWyV0mkTVS5C1h90TyQvmA9HqjoY+ceV8t1hIWJIJtspJ0UhA1SwDJ5DjmgYTNh5/Q3+L20ZoSZosepbhFgfXncrHaa1CVabC5gXVLbN6ODMtYuOY6og9jbWD/cRBixlgInD/bDXtutFI8AQ5xxykBu5CdFHtjXJLYeNsduQGIBsGy28RMXC7Q/cdtuubFyIYGJMWcLCZWEk2REcCMRkBhRE6RRYs5NK22VmOaNlUuMQArpadvKr9DetEqMJL1hE4sHLDFWqEhiwI1VSwyGEkMp7Mrk3HWRzxH6TbnhTePptxctwqZzWtt5Px5f4ThiMwjrPXvSWWKQlURWfyYH2wpqyL5fRGRucJXBVX+9mg0rV27TKZnEd2Q1MTXEkvjq76KGbGhpb6NsShLKPVqy7I5NCWRjbt6UTywobtugaEGEDuJWQFPEQVfl8ndDcRBmoYxjHMfnrbsyhmNDU/hLIbToX69guQGl5Iw3cHpdbgfap1/Qa11uxOl83O9yezB0aFpbd+ezIbvR6WsnA/qaXSNujZyh9ly9GJHTximBMy2vuwNYv+/mQQpoul5L46rfd+N0zjWNr+WBHYDTxumRa3pfq4Bae/fr6jC76Scmr9Jx4ZSS9uwnYrjc6NUuN6e9Qs/LDcfGgnWWTzFpz5msPzqW9P/nerE8mLXbW8accNJrb4fPYXPSsctKd089fMZW8xwb3Er1cbMDkz31JeEfmT5+VFIlBFG8dnAo9RxWU/y8XmZeOy4QlAEUhLWkAW9iUAfzgDc7bKeJwI6nREYEhMDtO7PJgQGw4+0K6E3JclWg1dIoDzCLDvhA2CyfdXlsl2c2HHV84HjV92svwtv8Pvo3441Xu24B1k2Anatax4AbywqvjnUNKB5Un3wlnSPJzLKAVei8+upMq9CcbeOiXqwCrA9/bWJ6TCU5MtwLF8Fq+hgAsQqaZsY/N8U/wPjGxpbjoDAIKINupFl6LO+yxXzJV786VkunBfCOfjotOIMsuB9UmZUrvit3ztXlTD1nft9nsoSHDjuOxNphT9P113n8vrq+PYSlT9h6iBSymoEVn9e3sl8m5R6vNTe6Q5cIj1Z3YJTyS8K8jHfkgax47eSHr0lhM/YzAEXijFExHftry4MFVWPXsd/2bJjUoLBDv9tkL2czNmSxbbVZ8ttFk/4zwl7Nb4P7oGUB3H2AIpw3AyApLFBXRtlpLA5ik81qUoc5UtcMN3e4lcDohmkOUS1OIGqNu28YIAdrqIFqXQbSQ+sAh/lprRExhYgd7NioGa8TTmpV1v4fYRjSf0qXWZSYorUDqjGizFZmSOppVHNStD8x6iytzkHzeGkA2mzDdJNqsN7TMt6M9TD5zFwVGZFa+xBlM2NeXemJEwrqtbpRt8iHLa7MnPkDWjEmTYZ820ya7wxf/ZUnPmTXZtZ8B8jqrz1xYU3RfTLLKMUy9LqboxLQwlr75MtqzGrdCserSWZo9UH1GJExDqBKm9Fqneq03zz+HMBotYBXRGhGq/E1Y0TazJw2M1pNBb76qbULgyCPZBLnZuq4CvJlcxrc9B0DcWEMxLTfOKAUI9qoXRgDKUJbt1lsum/I4zuAjZpzwmgIliyuA4iAwLY5D9GUcwYhWOB0ZtaIaDEpN7uk1li7/tIqNQRvbkOXa1uh5PsOu8BKlGx2YVejtHlUFSlxKp6KF3RYuHRCOauawiU4BwT4eSzz4fSExObACa+ZCdtV1Qj4JNtrqRqB72iZj6LpHa2/owlX4zMUpVl60EPb9HUx0RZF0RZ3AI3PPZhtXrC9CnhD93gaMiI672EA8PZI86NpuSaLrn4y78GoiyHz0rjqJ/MeJ7ay0drCapHZnJMAbBAeV0+9AKrup9RES1UQLW5VX79H1QFU6M9U6M1GzdOI8dArHBxpPG5KNbrS6OtmDwwrDG7C2j+CBlvZsTUOOJll00oS0v+7BD2vC7MjqPQ7BRqT0sNQ6xbsiEQG6e6Q1u9fcbb3gqS9i2frVX7gPMxs79KELRDtg6yQsMEN/QNZbyp2LkHDhTnb+LZv5MPt+y7NEpJT/TLaLK3NsGLHE/W/VFbswGzSx2hWbOBP6YSYyXJ8DRmTVsPEUaozOcmjezOWQA7cAfAweDZZFdIabGWw1R/r9uER5JvJ32uyMnU7XVhj0OVC+NhZHbn2MYDcJIO3qcd4bDFGEN/f4mxlvOVOgqE2akZD3fCcaKi60YyY42LdT7cicBFc7KwAWaU1Y9J03immKQKQg1U738YIHlfepjPTg0oWWe1su+o2WUP2/SIic4OrDK7680nox3FUdkom8R1ZTUx8SxZg7ZMZMWtecqCUY1ercXhgDWecnPoe7F/naUG/m8PEpAaC7GpAvCC4qtWAVM8eqv/ottgDs/mNrcUelX4OpLco5kyeNAkrnfloYIKJcDdChTkqnCAqc8pM2kKrnozIK+OMOTVdZLsBV79v5sMpkK/Uyp849qvGCmxUFYJuWMGNtbvQFzNw9DEDfmHhNW7m2WDUMDaKJ1baltS8xdci2BJS5YoOba5GTWieitjM3HX2q1/V1LLa1vFJbhciZ52ORjxB9JhVVb6hIezsS5fNRvj1tKFhVrMgOovjNYmXjCwJu83MjA7FbcbQiarS/IEoGMdZmF6zZ4HfjERPM9mYKAWOMzwNqRd3XIJDdZbrXOnKiFznSmTNgWZ3sOp3mjGMdr5JkvQuTaamrZk8wPrPNTEMeT2YDheyuA7gXBND4/uUx4vFReQRKURW/4EmZ7rdbVRAUGaBbpoQ5ZTTG6jloHa1s6oQAwgv9ez6oJPU7jUHuiMwpwb/moVgbDM/1PruGgSo99+gJlqIw+NBnEuJFu6OTyzLu6odn9ALvn/V7/GJuKwHA4sQhcfzdExI8MCW5YkC3v3JhiTggQFcKeBeOCjAbes4mzGAH0hcEG2MXInGYAB3DEHoCXp3GMfW12GDiQYtfZ7hG5xT33DyJ7S9AZZ+7n8nRYfvyBCgc3TEE2a83rAIkI0MAVJ7CD40wLGxh5LQW4LQ20Nzdtg3N4NWlZV3W41qbrth9kWHNKrrpmRjWGx2P93JwUWcpp6VEuGeHL3XnxLhwpSI++lnsryMrqbqkNWeFWFzTuDMAOWO0NWeEmGj48n2hpYfINu+MC13h8XNHE7XhrnhZR3xMqfZdmcAJZ2cpoempLO96s8RBn8wJMyBprrqgPi0jKfGZMujrJ+Q2QggaAIrJxhvGwsbb3dYxtu2jx8qGug7hH5gMTWPP2XAkDZ50la1Hq96kXuCplxd9Ax7vOgZRfwi8lzPYmze+MYM2JxOa5SbV4NVL4Keq8NXP1fj9Eg0I92kcdUeNqviP2bmj2LL7O5b5gBzao38PsMpNqeb7dYwX8RmfZ5l7mRUCA9mhRoOZ8GY2U5dQMszyv1Cy75BvfM8/Z3pduM2cXAVLlUVaWt1qVg9kIIWDbwz6u3hx2Uw7fOyEbAw+kNxq3AANfzi3KqewNbuY2GX08iSrrIx01K46vexXOg7mwFAneE7gK4NLgx+PZJJnJuodhcUrC1F1A69veddQXGwlHnWFi8YupUIE/VuVaLx0DPb4p1t7HqlXQQ9U4evdkZmWzB2Qh2tLI7yjGqzgVcKXu3EzEa8hLJyn36IpplBWA7hIVAzuEObDofSuOpvp+XCc6t3dGGLvdnkBsoDrL+JlgtNrwmGyAPLAooagYVGF2AqmAtYwHBG4l9rUp9IZuCqyu0rEIt/kPx/5TPF39tGUm75aNdFqnjAmkhNo9VzldJ4KuTtGYKM3LRX3VqdJ4eWb4UtGq7qnvs1bpyQbH8U6F/fNmYBN+9zoA/+yW0x4NlPQ/xV9GfzoH7cpVlC8jQzJ3ry4STQc91niqLxQC/kOSIM9YvgMuelY4TC6A8lZFSVUdVjxdGsoKxP6YSY0aWSAGuPGWEfHs7T3TEneXRvevvKgas9YoR9DMCtCtMMtjLYDiBW5MBY0V2U52uOBTa8S5p3OaIFxQpn3YS8WTdbzC9iqz6voNgTxn4wrCvknciag7qO8NVPukIYDq45UAZeKXj10y6HH+03sMrAOgTGBYP8n9aLOEsvyAYrBFj/MZ3DCWwtitUx3pIctPoP6HyYrfxm8vearEwDpg7cpevmKGnXCvazIAWdJ3VtMS0Yyaycp4tgXGd5T5XajMd7si1evVGtAapBuzu09ftSvilXELbcp+Or3ZmqWgfxm1qbwoXeChc8TzQCqrC3NS/DuUyBNdt6qwqNyIhjXo6BMeJK0NZuxG0bknNjxDvDV7sRr4ak7LV+KMvCjf/dgfEGjR+cpjUXtN3KTi9txHPAd80BLkHFz0sbG99YChvxXPBL4mnqwNVurLEHwS2Oty5LldUBPABrjQHA23Ouj4VdM+jKoDuAY0zPNG5RAaz+40sPhkK3elvwUTKbE7Mzy0Gs/RjTRhhAeNLcoCibXI20/fzmZ5TOnHXMbRIYI1RiNr5JBBg6UZ/Jkpgxj5160+4IpjweGvx3CVv8eXHREfrRGDLxS8FYHazaPWgbQwb+JWGx7nfkgaxMNqEkyAq9aPowS9O8XkidRcvnh3QaF6/4fw== \ No newline at end of file diff --git a/compitino/secondo_compitino/schema_concettuale.pdf b/compitino/secondo_compitino/schema_concettuale.pdf index 9ddd060..2bc4c58 100644 Binary files a/compitino/secondo_compitino/schema_concettuale.pdf and b/compitino/secondo_compitino/schema_concettuale.pdf differ diff --git a/compitino/secondo_compitino/schema_concettuale.tex b/compitino/secondo_compitino/schema_concettuale.tex index 56f28b7..699468a 100644 --- a/compitino/secondo_compitino/schema_concettuale.tex +++ b/compitino/secondo_compitino/schema_concettuale.tex @@ -1,3 +1,100 @@ % !TEX root = ../main.tex -Vincoli non catturati graficamente: \textellipsis \ No newline at end of file +\paragraph{Elenco degli ingredienti disponibili} +*l* committente ha chiesto espressamente l'elenco degli ingredienti disponibili. +Tuttavia, questo è calcolabile a partire dagli acquisti e dalle produzioni. +Ho convinto *l* committente a non memorizzare separatamente l'inventario degli +ingredienti, rassicurandol* che avrei fornito una vista logica ``Inventario". + +\begin{lstlisting}[style=SQLu][float,floatplacement=H] +CREATE VIEW IngredientiAcquistatiTotali (IdIngrediente, Ingrediente, + Totale) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(a.Quantità) Totale + FROM Acquisti a + JOIN Ingredienti i ON i.IdIngrediente = a.IdIngrediente + GROUP BY i.IdIngrediente, i.Descrizione; + +CREATE VIEW IngredientiInUso (IdIngrediente, Ingrediente, InUso) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) InUso + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato IS NULL + GROUP BY i.IdIngrediente, i.Descrizione; + +CREATE VIEW IngredientiUsati (IdIngrediente, Ingrediente, + Usati) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) Usati + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato = 0 + GROUP BY i.IdIngrediente, i.Descrizione; + +CREATE VIEW Inventario (IdIngrediente, Ingrediente, QuantitàTotale, + QuantitàDisponibile) +AS SELECT iat.IdIngrediente IdIngrediente, + iat.Ingrediente Ingrediente, + (iat.Totale - COALESCE(iu.Usati, 0)) QuantitàTotale, + (iat.Totale - COALESCE(iu.Usati, 0) + - COALESCE(iiu.InUso, 0)) QuantitàDisponibile + FROM IngredientiAcquistatiTotali iat + LEFT JOIN IngredientiUsati iu + ON iu.idIngrediente = iat.IdIngrediente + LEFT JOIN IngredientiInUso iiu + ON iiu.idIngrediente = iat.IdIngrediente + WHERE iat.Totale - COALESCE(iu.Usati, 0) > 0; +\end{lstlisting} + +Ogni volta che si inizia una produzione, l'applicazione controlla che la +quantità di ingredienti disponibili superi la quantità degli ingredienti +necessari alla preparazione. + +L'applicazione può anche mostrare una ``lista della spesa" basandosi su ricette +che si vogliono preparare e sulla vista inventario. + +L'applicazione mostrerà ad ogni birrai* solo le ricette di cui è aut*r* o di un +birrificio per cui lavora. + +\begin{minipage}{\linewidth} + \paragraph{Vincoli intra-relazionali} + \begin{itemize} + \itemsep0em + \item Non possono esistere due persone con lo stesso codice fiscale. + \item Non possono esistere due birrai* con lo stesso soprannome. + \item Non possono esistere due fornitori con la stessa partita IVA né + con la stessa ragione sociale. + \item Il tipo di ingrediente determina l'unità di misura. + Esiste un breve elenco di tipi ingredienti disponibili con la relativa unità di + misura. + Non ho creato una classe ``TipiIngredienti" per contenere il numero di classi, + ma in effetti il tipo determina funzionalmente l'unità di misura ed esistono + pochi tipi, mentre ci sono molti ingredienti per ogni tipo. + \end{itemize} + \paragraph{Vincoli inter-relazionali} + \begin{itemize} + \itemsep0em + \item Alla registrazione, l'utente deve inserire un soprannome e/o un indirizzo + di spedizione: il vincolo di copertura impone che l'unione di Clienti e + Birraie sia Persone, non devono esistere persone che non sono né clienti + né birrai*. + \item In ogni produzione, il NumeroBottiglie diviso per 0.5 non deve superare la + CapacitàProduttiva del birrificio. + \item Ogni produzione deve iniziare con stato `in corso'; + non può iniziare una produzione se un altra è `in corso' nello stesso + birrificio. + \item Ogni nota deve fare riferimento a una produzione. + \item Ogni prenotazione deve fare riferimento a una produzione. + \item Ogni prenotazione deve fare riferimento ad un* cliente. + \item Ogni produzione deve seguire una ricetta. + \item Due produzioni di uno stesso birrificio non devono avere lo stesso lotto. + \item Ogni ricetta deve avere un* creat*r* e un birrificio di riferimento. + \item Ogni fattura deve fare riferimento ad un birrificio e un fornitore. + \item Ogni acquisto deve riferirsi a una fattura e un ingrediente. + \item Ogni ricetta deve avere almeno un ingrediente per ciascuno dei + seguenti tipi: malto, luppolo, lievito. + \end{itemize} +\end{minipage} diff --git a/compitino/secondo_compitino/schema_logico.pdf b/compitino/secondo_compitino/schema_logico.pdf index 8a0b33d..e21638c 100644 Binary files a/compitino/secondo_compitino/schema_logico.pdf and b/compitino/secondo_compitino/schema_logico.pdf differ diff --git a/compitino/secondo_compitino/schema_logico.tex b/compitino/secondo_compitino/schema_logico.tex index 2325a36..844e9cb 100644 --- a/compitino/secondo_compitino/schema_logico.tex +++ b/compitino/secondo_compitino/schema_logico.tex @@ -1,21 +1,63 @@ % !TEX root = ../main.tex - +\\ \textbf{Schema logico relazionale in formato testuale} + \begin{lstlisting}[style=SQLu,escapechar=@] -Tabella(@\underline{ChiavePrimaria}@, B, C, D) -AltraTabella(@\underline{ChiavePrimariaEdEsterna*}@, E) -@\textellipsis@ +Persone(@\underline{IdPersona}@, Nome, Cognome, Email, CodiceFiscale) +Clienti(@\underline{IdPersona*}@, IndirizzoSpedizione) +Birraie(@\underline{IdPersona*}@, Soprannome) +Birrifici(@\underline{IdBirrificio}@, Nome, AnnoFondazione, Motto, Stemma, + CapacitàProduttiva) +BirrificiBirraie(@\underline{IdBirrificio*, IdBirraia*}@) +Fornitori(@\underline{IdFornitore}@, RagioneSociale, PartitaIva, Indirizzo) +Fatture(@\underline{IdFattura}@, IdBirrificio*, IdFornitore*, Data, + NumeroFattura, Importo) +TipiIngredienti(@\underline{IdTipo}@, Tipo, UnitàDiMisura) +Ingredienti(@\underline{IdIngrediente}@, IdTipo*, Descrizione) +Acquisti(@\underline{IdFattura*, IdIngrediente*}@, Quantità) +Ricette(@\underline{IdRicetta}@, IdBirrificio*, IdCreatrice*, IdRicettaMadre*, + Nome, DataCreazione, Stato) +IngredientiRicette(@\underline{IdRicetta*, IdIngrediente*}@, Quantità) +Produzioni(@\underline{IdProduzione}@, IdRicetta*, DataProduzione, NumeroLotto, + Stato, NumeroBottiglie) +Prenotazioni(@\underline{IdCliente*, IdProduzione*}@, Stato, Quantità) +Note(@\underline{IdNota}@, IdProduzione*, Testo) +NoteDegustazione(@\underline{IdNota*}@, Giudizio) \end{lstlisting} \paragraph{Dipendenze funzionali} \begin{itemize} -\item Per ogni tabella la chiave primaria (sottolineata) determina ciascuno degli attributi della tabella -\item Altre eventuali dipendenze + \itemsep0em + \item Per ogni tabella la chiave primaria (sottolineata) determina ciascuno + degli attributi della tabella. + \begin{lstlisting}[style=SQLu,escapechar=@] + IdPersona @$\to$@ Nome, IdPersona @$\to$@ Cognome, IdPersona @$\to$@ Email, + IdPersona @$\to$@ CodiceFiscale, @$\textellipsis$@ + \end{lstlisting} + \item Nella tabella \texttt{Persone}, \texttt{CodiceFiscale} è chiave + naturale e determina tutti gli altri attributi. + Ho ritenuto prudente aggiungere una chiave artificiale perché, se è vero + che due persone diverse non avranno mai lo stesso codice fiscale, è vero + anche che ci possono essere errori umani nell'inserimento di un CF e voglio + riservarmi la possibilità di correggere un CF senza minare l'affidabiltà + della base di dati. + \item Stesso discorso per la RagioneSociale e la PartitaIva nella tabella + \texttt{Fornitori}: ciascuno è chiave separatamente. + \item Nella tabella \texttt{Fatture}, la coppia di attributi \texttt{\{IdFornitore, NumeroFattura\}} + è chiave. + \item Nella tabella \texttt{Produzioni}, il NumeroLotto \underline{non} è chiave, in + quanto birrifici diversi possono avere lotti uguali, è solo all'interno del + birrificio che il lotto identifica univocamente la produzione. \end{itemize} - Uno schema R, avente insieme di attributi T e insieme di dipendenze funzionali F, (\lstinline{R}) è in forma normale di Boyce-Codd (BCNF) se ogni dipendenza funzionale della chiusura di F o è banale o ha come determinante una superchiave di T. Esiste un teorema che semplifica il calcolo, asserendo che se la condizione di cui sopra vale per una qualsiasi copertura di F allora vale per l’intera chiusura di F. + +Nella copertura di F che ho descritto sopra (che peraltro è canonica: ogni dipendenza ha un +solo attributo come determinato, nessuna dipendenza è ridondante e non sono presenti +attributi estranei, in quanto ogni determinante è chiave), ogni dipendenza funzionale ha +come determinante o la chiave primaria o una chiave naturale che non è stata scelta come +primaria, in ogni caso una superchiave. \underline{La BCNF è pertanto rispettata}. diff --git a/compitino/secondo_compitino/source_code.tex b/compitino/secondo_compitino/source_code.tex new file mode 100644 index 0000000..c5be7d9 --- /dev/null +++ b/compitino/secondo_compitino/source_code.tex @@ -0,0 +1,5 @@ +% !TEX root = ../main.tex + +\begin{center} + Codice sorgente e test: \href{https://gogs.davte.it/Davte/basi_di_dati}{https://gogs.davte.it/Davte/basi\_di\_dati} +\end{center} diff --git a/compitino/secondo_compitino/test/data.sql b/compitino/secondo_compitino/test/data.sql new file mode 100644 index 0000000..6bfa138 --- /dev/null +++ b/compitino/secondo_compitino/test/data.sql @@ -0,0 +1,37 @@ +BEGIN TRANSACTION; +INSERT INTO "Fornitori" ("IdFornitore","RagioneSociale","PartitaIva","Indirizzo") VALUES (1,'Luppoli per tutti i gusti',121457,'Corso Torre 125'), + (2,'A tutto Malto',147963,'Piazza Dante 16'), + (3,'Lievitami',236541,'Corso Pavia 33'); +INSERT INTO "Fatture" ("IdFattura","IdBirrificio","IdFornitore","Data","NumeroFattura","Importo") VALUES (1,1,1,'2020-01-03',125,77), + (2,1,2,'2020-03-12',116,40), + (3,1,3,'2020-03-18',78,82), + (4,1,3,'2020-04-02',96,60); +INSERT INTO "Birrifici" ("IdBirrificio","Nome","AnnoFondazione","Motto","Stemma","CapacitàProduttiva") VALUES (1,'Pirati Rossi',2020,'Arrrr','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',0); +INSERT INTO "BirrificiBirraie" ("IdBirrificio","IdBirraia") VALUES (3,1), + (4,1); +INSERT INTO "Birraie" ("IdPersona","Soprannome") VALUES (3,'MaVe'), + (4,'GiuLe'); +INSERT INTO "Clienti" ("IdPersona","IndirizzoSpedizione") VALUES (1,'Via Ramazzini 14'), + (2,'Corso Milano 2'); +INSERT INTO "Persone" ("IdPersona","Nome","Cognome","Email","CodiceFiscale") VALUES (1,'Antonio','Rossi','a.r@g.i','NNNNRRRR'), + (2,'Enrico','Bianchi','e.b@g.c','EEEBBB'), + (3,'Giovanni','Verdi','m.v@l.i','MV'), + (4,'Giulia','Lelli','g.l@e.c','GL'); +INSERT INTO "Acquisti" ("IdFattura","IdIngrediente","Quantità") VALUES (1,1,12), + (2,2,7); +INSERT INTO "TipiIngredienti" ("IdTipo","Tipo","UnitàDiMisura") VALUES (1,'Luppolo','g / L (mash)'), + (2,'Malto','g%'), + (3,'Lievito','g%'), + (4,'Zuccheri','g%'), + (5,'Additivi','mg%'); +INSERT INTO "Ingredienti" ("IdIngrediente","IdTipo","Descrizione") VALUES (1,1,'Luppolo verde'), + (2,1,'Amarillo'); +INSERT INTO "IngredientiRicette" ("IdRicetta","IdIngrediente","Quantità") VALUES (1,1,4); +INSERT INTO "Ricette" ("IdRicetta","IdBirrificio","IdCreatrice","IdRicettaMadre","Nome","DataCreazione","Stato") VALUES (1,1,3,'','Bionda decisa','2020-01-01',''); +INSERT INTO "NoteDegustazione" ("IdNota","Giudizio") VALUES (1,7); +INSERT INTO "Note" ("IdNota","IdProduzione","Testo") VALUES (1,1,'Troppo freddo ad aprile-maggio, meglio farla d''estate'); +INSERT INTO "Produzioni" ("IdProduzione","IdRicetta","DataProduzione","NumeroLotto","Stato","NumeroBottiglie") VALUES (1,1,'2020-05-01',12447,NULL,12), + (2,1,'2020-04-15',12443,0,0); +INSERT INTO "Prenotazioni" ("IdCliente","IdProduzione","Stato","Quantità") VALUES (1,1,'',4), + (1,2,NULL,6); +COMMIT; diff --git a/compitino/secondo_compitino/test/data_and_schema.sql b/compitino/secondo_compitino/test/data_and_schema.sql new file mode 100644 index 0000000..753ab3d --- /dev/null +++ b/compitino/secondo_compitino/test/data_and_schema.sql @@ -0,0 +1,228 @@ +BEGIN TRANSACTION; +CREATE TABLE IF NOT EXISTS "Acquisti" ( + "IdFattura" INTEGER NOT NULL, + "IdIngrediente" INTEGER NOT NULL, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdFattura","IdIngrediente") +); +CREATE TABLE IF NOT EXISTS "Birraie" ( + "IdPersona" INTEGER NOT NULL, + "Soprannome" TEXT NOT NULL UNIQUE, + PRIMARY KEY("IdPersona") +); +CREATE TABLE IF NOT EXISTS "Birrifici" ( + "IdBirrificio" INTEGER PRIMARY KEY AUTOINCREMENT, + "Nome" TEXT, + "AnnoFondazione" INTEGER, + "Motto" TEXT, + "Stemma" BLOB, + "CapacitàProduttiva" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "BirrificiBirraie" ( + "IdBirrificio" INTEGER NOT NULL, + "IdBirraia" INTEGER NOT NULL, + PRIMARY KEY("IdBirrificio","IdBirraia") +); +CREATE TABLE IF NOT EXISTS "Clienti" ( + "IdPersona" INTEGER NOT NULL, + "IndirizzoSpedizione" TEXT NOT NULL, + PRIMARY KEY("IdPersona") +); +CREATE TABLE IF NOT EXISTS "Fatture" ( + "IdFattura" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdBirrificio" INTEGER NOT NULL, + "IdFornitore" INTEGER NOT NULL, + "Data" TEXT NOT NULL, + "NumeroFattura" INTEGER NOT NULL UNIQUE, + "Importo" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "Fornitori" ( + "IdFornitore" INTEGER PRIMARY KEY AUTOINCREMENT, + "RagioneSociale" TEXT NOT NULL UNIQUE, + "PartitaIva" INTEGER NOT NULL UNIQUE, + "Indirizzo" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "Ingredienti" ( + "IdIngrediente" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdTipo" INTEGER NOT NULL, + "Descrizione" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "IngredientiRicette" ( + "IdRicetta" INTEGER NOT NULL, + "IdIngrediente" INTEGER NOT NULL, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdRicetta","IdIngrediente") +); +CREATE TABLE IF NOT EXISTS "Note" ( + "IdNota" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdProduzione" INTEGER NOT NULL, + "Testo" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "NoteDegustazione" ( + "IdNota" INTEGER NOT NULL, + "Giudizio" INTEGER NOT NULL, + PRIMARY KEY("IdNota") +); +CREATE TABLE IF NOT EXISTS "Persone" ( + "IdPersona" INTEGER PRIMARY KEY AUTOINCREMENT, + "Nome" TEXT NOT NULL, + "Cognome" TEXT NOT NULL, + "Email" TEXT NOT NULL, + "CodiceFiscale" TEXT NOT NULL UNIQUE +); +CREATE TABLE IF NOT EXISTS "Prenotazioni" ( + "IdCliente" INTEGER NOT NULL, + "IdProduzione" INTEGER NOT NULL, + "Stato" INTEGER, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdProduzione","IdCliente") +); +CREATE TABLE IF NOT EXISTS "Produzioni" ( + "IdProduzione" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdRicetta" INTEGER NOT NULL, + "DataProduzione" TEXT NOT NULL, + "NumeroLotto" INTEGER NOT NULL, + "Stato" INTEGER, + "NumeroBottiglie" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "Ricette" ( + "IdRicetta" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdBirrificio" INTEGER NOT NULL, + "IdCreatrice" INTEGER NOT NULL, + "IdRicettaMadre" INTEGER, + "Nome" TEXT NOT NULL, + "DataCreazione" TEXT NOT NULL, + "Stato" INTEGER +); +CREATE TABLE IF NOT EXISTS "TipiIngredienti" ( + "IdTipo" INTEGER PRIMARY KEY AUTOINCREMENT, + "Tipo" TEXT NOT NULL, + "UnitàDiMisura" TEXT NOT NULL +); +INSERT INTO "Fornitori" ("IdFornitore","RagioneSociale","PartitaIva","Indirizzo") VALUES (1,'Luppoli per tutti i gusti',121457,'Corso Torre 125'), + (2,'A tutto Malto',147963,'Piazza Dante 16'), + (3,'Lievitami',236541,'Corso Pavia 33'); +INSERT INTO "Fatture" ("IdFattura","IdBirrificio","IdFornitore","Data","NumeroFattura","Importo") VALUES (1,1,1,'2020-01-03',125,77), + (2,1,2,'2020-03-12',116,40), + (3,1,3,'2020-03-18',78,82), + (4,1,3,'2020-04-02',96,60); +INSERT INTO "Birrifici" ("IdBirrificio","Nome","AnnoFondazione","Motto","Stemma","CapacitàProduttiva") VALUES (1,'Pirati Rossi',2020,'Arrrr','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',0); +INSERT INTO "BirrificiBirraie" ("IdBirrificio","IdBirraia") VALUES (3,1), + (4,1); +INSERT INTO "Birraie" ("IdPersona","Soprannome") VALUES (3,'MaVe'), + (4,'GiuLe'); +INSERT INTO "Clienti" ("IdPersona","IndirizzoSpedizione") VALUES (1,'Via Ramazzini 14'), + (2,'Corso Milano 2'); +INSERT INTO "Persone" ("IdPersona","Nome","Cognome","Email","CodiceFiscale") VALUES (1,'Antonio','Rossi','a.r@g.i','NNNNRRRR'), + (2,'Enrico','Bianchi','e.b@g.c','EEEBBB'), + (3,'Giovanni','Verdi','m.v@l.i','MV'), + (4,'Giulia','Lelli','g.l@e.c','GL'); +INSERT INTO "Acquisti" ("IdFattura","IdIngrediente","Quantità") VALUES (1,1,12), + (2,2,7); +INSERT INTO "TipiIngredienti" ("IdTipo","Tipo","UnitàDiMisura") VALUES (1,'Luppolo','g / L (mash)'), + (2,'Malto','g%'), + (3,'Lievito','g%'), + (4,'Zuccheri','g%'), + (5,'Additivi','mg%'); +INSERT INTO "Ingredienti" ("IdIngrediente","IdTipo","Descrizione") VALUES (1,1,'Luppolo verde'), + (2,1,'Amarillo'); +INSERT INTO "IngredientiRicette" ("IdRicetta","IdIngrediente","Quantità") VALUES (1,1,4); +INSERT INTO "Ricette" ("IdRicetta","IdBirrificio","IdCreatrice","IdRicettaMadre","Nome","DataCreazione","Stato") VALUES (1,1,3,'','Bionda decisa','2020-01-01',''); +INSERT INTO "NoteDegustazione" ("IdNota","Giudizio") VALUES (1,7); +INSERT INTO "Note" ("IdNota","IdProduzione","Testo") VALUES (1,1,'Troppo freddo ad aprile-maggio, meglio farla d''estate'); +INSERT INTO "Produzioni" ("IdProduzione","IdRicetta","DataProduzione","NumeroLotto","Stato","NumeroBottiglie") VALUES (1,1,'2020-05-01',12447,NULL,12), + (2,1,'2020-04-15',12443,0,0); +INSERT INTO "Prenotazioni" ("IdCliente","IdProduzione","Stato","Quantità") VALUES (1,1,'',4), + (1,2,NULL,6); + +CREATE VIEW Query_a +AS SELECT r.IdRicetta, r.Nome + FROM Ricette r + JOIN Persone p ON p.IdPersona = r.IdCreatrice + WHERE p.Nome = 'Giovanni'; +CREATE VIEW Query_b +AS SELECT fa.IdBirrificio, + COUNT(DISTINCT fa.IdFornitore) DiversiFornitori + FROM Fatture fa + WHERE fa.Data >= '2020-01-01' + GROUP BY fa.IdBirrificio + HAVING COUNT(DISTINCT fa.IdFornitore) >= 3 + ORDER BY COUNT(DISTINCT fa.IdFornitore) DESC; +CREATE VIEW Query_c +AS SELECT fo.RagioneSociale, SUM(fa.Importo) ImportoTotale, + AVG(fa.Importo) ImportoMedio + FROM Fornitori fo + JOIN Fatture fa ON fa.IdFornitore = fo.IdFornitore + JOIN Birrifici b ON b.IdBirrificio = fa.IdBirrificio + WHERE b.Nome = 'Pirati Rossi' + GROUP BY fo.IdFornitore, fo.RagioneSociale + HAVING SUM(fa.Importo) > 10; +CREATE VIEW Query_d +AS SELECT b.Soprannome + FROM Birraie b + WHERE EXISTS (SELECT * + FROM Ricette r + WHERE r.IdCreatrice = b.IdPersona); +CREATE VIEW Query_e +AS SELECT DISTINCT p1.IdPersona, p1.Nome, p1.Cognome + FROM Persone p1 + JOIN Prenotazioni pre1 + ON pre1.IdCliente = p1.IdPersona + JOIN Produzioni pro1 + ON pro1.IdProduzione = pre1.IdProduzione + JOIN Ricette r1 + ON r1.IdRicetta = pro1.IdRicetta + WHERE NOT EXISTS (SELECT * + FROM Prenotazioni pre2 + JOIN Produzioni pro2 + ON pro2.IdProduzione = pre2.IdProduzione + JOIN Ricette r2 ON r2.IdRicetta = pro2.IdRicetta + WHERE pre2.IdCliente = pre1.IdCliente + AND r2.IdBirrificio <> r1.IdBirrificio); +CREATE VIEW Query_f +AS SELECT r1.IdBirrificio, pro1.NumeroLotto + FROM Produzioni pro1 + JOIN Ricette r1 ON r1.IdRicetta = pro1.IdRicetta + WHERE pro1.NumeroLotto = (SELECT MAX(pro2.NumeroLotto) + FROM Produzioni pro2 + JOIN Ricette r2 + ON r2.IdRicetta = pro2.IdRicetta + WHERE r2.IdBirrificio = r1.IdBirrificio); +CREATE VIEW IngredientiUsati (IdIngrediente, Ingrediente, + Usati) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) Usati + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato = 0 + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW IngredientiInUso (IdIngrediente, Ingrediente, InUso) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) InUso + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato IS NULL + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW IngredientiAcquistatiTotali (IdIngrediente, Ingrediente, + Totale) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(a.Quantità) Totale + FROM Acquisti a + JOIN Ingredienti i ON i.IdIngrediente = a.IdIngrediente + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW Inventario (IdIngrediente, Ingrediente, QuantitàTotale, + QuantitàDisponibile) +AS SELECT iat.IdIngrediente IdIngrediente, + iat.Ingrediente Ingrediente, + (iat.Totale - COALESCE(iu.Usati, 0)) QuantitàTotale, + (iat.Totale - COALESCE(iu.Usati, 0) + - COALESCE(iiu.InUso, 0)) QuantitàDisponibile + FROM IngredientiAcquistatiTotali iat + LEFT JOIN IngredientiUsati iu + ON iu.idIngrediente = iat.IdIngrediente + LEFT JOIN IngredientiInUso iiu + ON iiu.idIngrediente = iat.IdIngrediente + WHERE iat.Totale - COALESCE(iu.Usati, 0) > 0; +COMMIT; diff --git a/compitino/secondo_compitino/test/schema.sql b/compitino/secondo_compitino/test/schema.sql new file mode 100644 index 0000000..e521a4f --- /dev/null +++ b/compitino/secondo_compitino/test/schema.sql @@ -0,0 +1,192 @@ +BEGIN TRANSACTION; +CREATE TABLE IF NOT EXISTS "Acquisti" ( + "IdFattura" INTEGER NOT NULL, + "IdIngrediente" INTEGER NOT NULL, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdFattura","IdIngrediente") +); +CREATE TABLE IF NOT EXISTS "Birraie" ( + "IdPersona" INTEGER NOT NULL, + "Soprannome" TEXT NOT NULL UNIQUE, + PRIMARY KEY("IdPersona") +); +CREATE TABLE IF NOT EXISTS "Birrifici" ( + "IdBirrificio" INTEGER PRIMARY KEY AUTOINCREMENT, + "Nome" TEXT, + "AnnoFondazione" INTEGER, + "Motto" TEXT, + "Stemma" BLOB, + "CapacitàProduttiva" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "BirrificiBirraie" ( + "IdBirrificio" INTEGER NOT NULL, + "IdBirraia" INTEGER NOT NULL, + PRIMARY KEY("IdBirrificio","IdBirraia") +); +CREATE TABLE IF NOT EXISTS "Clienti" ( + "IdPersona" INTEGER NOT NULL, + "IndirizzoSpedizione" TEXT NOT NULL, + PRIMARY KEY("IdPersona") +); +CREATE TABLE IF NOT EXISTS "Fatture" ( + "IdFattura" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdBirrificio" INTEGER NOT NULL, + "IdFornitore" INTEGER NOT NULL, + "Data" TEXT NOT NULL, + "NumeroFattura" INTEGER NOT NULL UNIQUE, + "Importo" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "Fornitori" ( + "IdFornitore" INTEGER PRIMARY KEY AUTOINCREMENT, + "RagioneSociale" TEXT NOT NULL UNIQUE, + "PartitaIva" INTEGER NOT NULL UNIQUE, + "Indirizzo" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "Ingredienti" ( + "IdIngrediente" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdTipo" INTEGER NOT NULL, + "Descrizione" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "IngredientiRicette" ( + "IdRicetta" INTEGER NOT NULL, + "IdIngrediente" INTEGER NOT NULL, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdRicetta","IdIngrediente") +); +CREATE TABLE IF NOT EXISTS "Note" ( + "IdNota" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdProduzione" INTEGER NOT NULL, + "Testo" TEXT NOT NULL +); +CREATE TABLE IF NOT EXISTS "NoteDegustazione" ( + "IdNota" INTEGER NOT NULL, + "Giudizio" INTEGER NOT NULL, + PRIMARY KEY("IdNota") +); +CREATE TABLE IF NOT EXISTS "Persone" ( + "IdPersona" INTEGER PRIMARY KEY AUTOINCREMENT, + "Nome" TEXT NOT NULL, + "Cognome" TEXT NOT NULL, + "Email" TEXT NOT NULL, + "CodiceFiscale" TEXT NOT NULL UNIQUE +); +CREATE TABLE IF NOT EXISTS "Prenotazioni" ( + "IdCliente" INTEGER NOT NULL, + "IdProduzione" INTEGER NOT NULL, + "Stato" INTEGER, + "Quantità" INTEGER NOT NULL, + PRIMARY KEY("IdProduzione","IdCliente") +); +CREATE TABLE IF NOT EXISTS "Produzioni" ( + "IdProduzione" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdRicetta" INTEGER NOT NULL, + "DataProduzione" TEXT NOT NULL, + "NumeroLotto" INTEGER NOT NULL, + "Stato" INTEGER, + "NumeroBottiglie" INTEGER NOT NULL +); +CREATE TABLE IF NOT EXISTS "Ricette" ( + "IdRicetta" INTEGER PRIMARY KEY AUTOINCREMENT, + "IdBirrificio" INTEGER NOT NULL, + "IdCreatrice" INTEGER NOT NULL, + "IdRicettaMadre" INTEGER, + "Nome" TEXT NOT NULL, + "DataCreazione" TEXT NOT NULL, + "Stato" INTEGER +); +CREATE TABLE IF NOT EXISTS "TipiIngredienti" ( + "IdTipo" INTEGER PRIMARY KEY AUTOINCREMENT, + "Tipo" TEXT NOT NULL, + "UnitàDiMisura" TEXT NOT NULL +); +CREATE VIEW Query_a +AS SELECT r.IdRicetta, r.Nome + FROM Ricette r + JOIN Persone p ON p.IdPersona = r.IdCreatrice + WHERE p.Nome = 'Giovanni'; +CREATE VIEW Query_b +AS SELECT fa.IdBirrificio, + COUNT(DISTINCT fa.IdFornitore) DiversiFornitori + FROM Fatture fa + WHERE fa.Data >= '2020-01-01' + GROUP BY fa.IdBirrificio + HAVING COUNT(DISTINCT fa.IdFornitore) >= 3 + ORDER BY COUNT(DISTINCT fa.IdFornitore) DESC; +CREATE VIEW Query_c +AS SELECT fo.RagioneSociale, SUM(fa.Importo) ImportoTotale, + AVG(fa.Importo) ImportoMedio + FROM Fornitori fo + JOIN Fatture fa ON fa.IdFornitore = fo.IdFornitore + JOIN Birrifici b ON b.IdBirrificio = fa.IdBirrificio + WHERE b.Nome = 'Pirati Rossi' + GROUP BY fo.IdFornitore, fo.RagioneSociale + HAVING SUM(fa.Importo) > 10; +CREATE VIEW Query_d +AS SELECT b.Soprannome + FROM Birraie b + WHERE EXISTS (SELECT * + FROM Ricette r + WHERE r.IdCreatrice = b.IdPersona); +CREATE VIEW Query_e +AS SELECT DISTINCT p1.IdPersona, p1.Nome, p1.Cognome + FROM Persone p1 + JOIN Prenotazioni pre1 + ON pre1.IdCliente = p1.IdPersona + JOIN Produzioni pro1 + ON pro1.IdProduzione = pre1.IdProduzione + JOIN Ricette r1 + ON r1.IdRicetta = pro1.IdRicetta + WHERE NOT EXISTS (SELECT * + FROM Prenotazioni pre2 + JOIN Produzioni pro2 + ON pro2.IdProduzione = pre2.IdProduzione + JOIN Ricette r2 ON r2.IdRicetta = pro2.IdRicetta + WHERE pre2.IdCliente = pre1.IdCliente + AND r2.IdBirrificio <> r1.IdBirrificio); +CREATE VIEW Query_f +AS SELECT r1.IdBirrificio, pro1.NumeroLotto + FROM Produzioni pro1 + JOIN Ricette r1 ON r1.IdRicetta = pro1.IdRicetta + WHERE pro1.NumeroLotto = (SELECT MAX(pro2.NumeroLotto) + FROM Produzioni pro2 + JOIN Ricette r2 + ON r2.IdRicetta = pro2.IdRicetta + WHERE r2.IdBirrificio = r1.IdBirrificio); +CREATE VIEW IngredientiUsati (IdIngrediente, Ingrediente, + Usati) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) Usati + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato = 0 + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW IngredientiInUso (IdIngrediente, Ingrediente, InUso) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(ir.Quantità) InUso + FROM IngredientiRicette ir + JOIN Ingredienti i ON i.IdIngrediente = ir.IdIngrediente + JOIN Produzioni p ON p.IdRicetta = ir.IdRicetta + WHERE p.Stato IS NULL + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW IngredientiAcquistatiTotali (IdIngrediente, Ingrediente, + Totale) +AS SELECT i.IdIngrediente IdIngrediente, i.Descrizione Ingrediente, + SUM(a.Quantità) Totale + FROM Acquisti a + JOIN Ingredienti i ON i.IdIngrediente = a.IdIngrediente + GROUP BY i.IdIngrediente, i.Descrizione; +CREATE VIEW Inventario (IdIngrediente, Ingrediente, QuantitàTotale, + QuantitàDisponibile) +AS SELECT iat.IdIngrediente IdIngrediente, + iat.Ingrediente Ingrediente, + (iat.Totale - COALESCE(iu.Usati, 0)) QuantitàTotale, + (iat.Totale - COALESCE(iu.Usati, 0) + - COALESCE(iiu.InUso, 0)) QuantitàDisponibile + FROM IngredientiAcquistatiTotali iat + LEFT JOIN IngredientiUsati iu + ON iu.idIngrediente = iat.IdIngrediente + LEFT JOIN IngredientiInUso iiu + ON iiu.idIngrediente = iat.IdIngrediente + WHERE iat.Totale - COALESCE(iu.Usati, 0) > 0; +COMMIT; diff --git a/compitino/secondo_compitino/testo.tex b/compitino/secondo_compitino/testo.tex index d1fbd69..f54f774 100644 --- a/compitino/secondo_compitino/testo.tex +++ b/compitino/secondo_compitino/testo.tex @@ -1,3 +1,88 @@ % !TEX root = ../main.tex -Il testo viene assegnato dal Professore. \ No newline at end of file +\paragraph{Introduzione} +La birra fatta in casa è un'attività che riceve crescente attenzione da parte degli appassionati. +Ogni birraio amatoriale possiede un'attrezzatura per il processo di produzione della birra su +piccola scala (bollitori, fermentatori, tubi, ecc.) con una certa capacità massima di +fermentazione: il numero di litri che l'attrezzatura è in grado di gestire in un unico ``lotto". La +preparazione della birra richiede anche ingredienti, le cui quantità effettive variano da una +ricetta all'altra, questi sono vari tipi di malto, luppolo, lieviti e zuccheri (e, naturalmente, acqua). + +Ai birrai piace registrare le proprie ricette per riferimento futuro e mantenere un elenco +aggiornato degli ingredienti disponibili per fare acquisti prima della successiva produzione. + +L'obiettivo di questo progetto è quello di sviluppare un'applicazione per i birrai domestici che +consenta loro di mantenere un elenco di ricette e adattare quelle esistenti. L'applicazione deve +anche: +\begin{itemize} + \itemsep0em + \item mantenere un elenco di ingredienti disponibili; + \item aggiornare questo elenco dopo un ciclo di produzione e quando vengono acquistati nuovi ingredienti; + \item produrre liste della spesa per il lotto successivo; + \item guidare il birraio nel processo di produzione. +\end{itemize} + +\paragraph{Descrizione del progetto} +``Una cervecita fresca" è un'applicazione che consente ai produttori amatoriali di birra di +mantenere un database organizzato delle loro ricette di birra. L'applicazione consente agli +utenti di creare, archiviare e modificare ricette, e successivamente eliminarle, se l'utente +desidera farlo. L'applicazione è destinata solo ai produttori di birra con metodo +\href{https://www.birradegliamici.com/fare-la-birra/all-grain/}{all-grain}, e +quindi tutte le ricette sono per questo tipo di birre (le birre ``estratto" non +sono supportate). + +Ogni birrificio domestico dispone di un'attrezzatura specifica, le cui caratteristiche portano a +una particolare ``dimensione del lotto": il numero massimo di litri che possono essere prodotti +in una singola produzione. +Le ricette prevedono, oltre all'acqua: + +\begin{itemize} + \itemsep0em + \item malti + \item luppolo + \item lieviti + \item zuccheri + \item additivi +\end{itemize} + +Mentre i produttori di birra preferiscono creare ricette riferendosi a valori concreti, come +chilogrammi di un particolare malto o grammi di un particolare luppolo, l'applicazione deve +memorizzare queste ricette in una misura ``assoluta", che consente una conversione diretta +della ricetta quando l'apparecchiatura, e di conseguenza la dimensione del lotto, è diversa. +Ad esempio, una possibilità è esprimere la quantità di malto in percentuale del totale e usare +i grammi per litro di miscuglio (mash) per il luppolo. + +Oltre alle ricette, l'applicazione deve conservare le \textbf{istanze} della ricetta, ovvero singole +produzioni basate su una ricetta; queste istanze possono essere accompagnate da note per +fare riferimento a problemi che possono influire sulla birra risultante, note che i produttori di +birra vorrebbero rimanessero memorizzate. Un particolare tipo di nota sono le note di +degustazione, che consentono ai birrai di tenere traccia delle opinioni su una birra di un dato +lotto. + +Oltre a queste funzionalità più tradizionali, l'applicazione “Una cervecita fresca”, mantiene un +elenco di ingredienti disponibili. Ciò consente ai birrai di avere la lista degli ingredienti +mancanti per la prossima produzione. Un'istanza della ricetta, ovvero una produzione di birra, +dovrebbe consentire agli utenti di aggiornare l'elenco degli ingredienti disponibili, sottraendo +gli ingredienti usati da quelli disponibili. + +Sarà inoltre possibile per i birrai vendere la birra prodotta. L’applicazione deve offrire +un’interfaccia web per la prenotazione e la vendita. Un cliente registrato può prenotare un lotto +di birra in produzione, oppure parte di esso. Quando il lotto è stato prodotto, il birraio può +confermare le prenotazioni e procedere con la vendita oppure, se non è soddisfatto del +prodotto, cancellarle, per non danneggiare il proprio buon nome. La birra non prenotata può +essere messa in vendita e comprata da utenti registrati. + +\paragraph{Scopo dell’applicazione} +Il sistema deve implementare le funzionalità sopra descritte, ovvero creazione, modifica e +cancellazione di ricette, creazione di istanze di ricette (birre), supporto per le note sulle birre, +controllo degli ingredienti disponibili, supporto alla produzione con allarmi, supporto alla +vendita. + +\paragraph{Scopo del progetto per quanto riguarda Basi di Dati} +Si integrano i requisiti già specificati con le seguenti ulteriori informazioni: +\begin{itemize} + \itemsep0em + \item le ricette sono relative ad un solo birrificio ma possono essere condivise tra +diversi birrai che sono autorizzati al loro utilizzo; + \item gli ingredienti possono essere acquistati da più fornitori (registrati). +\end{itemize}