First assignment uploaded
This commit is contained in:
parent
9c5714851a
commit
6531fb6d49
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
# ---> TeX
|
# ---> TeX
|
||||||
|
out/
|
||||||
|
|
||||||
## Core latex/pdflatex auxiliary files:
|
## Core latex/pdflatex auxiliary files:
|
||||||
*.aux
|
*.aux
|
||||||
*.lof
|
*.lof
|
||||||
|
69
compitino/main.tex
Normal file
69
compitino/main.tex
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
\documentclass [11pt, a4paper]{article}
|
||||||
|
|
||||||
|
\usepackage[main= italian, english]{babel}
|
||||||
|
\usepackage{enumitem}
|
||||||
|
\usepackage{forest}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage{listings}
|
||||||
|
\usepackage{pxfonts}
|
||||||
|
\usepackage{textcomp}
|
||||||
|
\usepackage[normalem]{ulem}
|
||||||
|
\usepackage{geometry}
|
||||||
|
|
||||||
|
\geometry{
|
||||||
|
a4paper,
|
||||||
|
top=30mm,
|
||||||
|
}
|
||||||
|
|
||||||
|
\forestset{qtree/.style={for tree={parent anchor=south,
|
||||||
|
child anchor=north,align=center,inner sep=0pt}}}
|
||||||
|
\lstset{upquote=true,showstringspaces=false}
|
||||||
|
\lstdefinestyle{SQLu}{
|
||||||
|
language=SQL,
|
||||||
|
basicstyle=\small\ttfamily,
|
||||||
|
keywordstyle=\bfseries,
|
||||||
|
moredelim=[is][\underbar]{_}{_},
|
||||||
|
keepspaces=true
|
||||||
|
}
|
||||||
|
\selectlanguage{italian}
|
||||||
|
|
||||||
|
\setcounter{section}{-1}
|
||||||
|
\newcommand{\folder}{primo_compitino}
|
||||||
|
%\newcommand{\folder}{secondo_compitino}
|
||||||
|
|
||||||
|
|
||||||
|
% First page information
|
||||||
|
\title{\textbf{Basi di dati prof. Ghelli}\linebreak\textit{``Sempre sul pezzo"}}
|
||||||
|
\author{Davide Testa 613565}
|
||||||
|
\date{2020-05-15}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\maketitle % Insert the title, author and date
|
||||||
|
\section{Descrizione di massima del dominio (testo)}\label{sec:testo}
|
||||||
|
\input{\folder/testo.tex}
|
||||||
|
\section{Descrizione del dominio}\label{sec:dominio}
|
||||||
|
\input{\folder/dominio.tex}
|
||||||
|
\section{Schema concettuale}\label{sec:schema-concettuale}
|
||||||
|
\begin{figure}[hb]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=\linewidth]{\folder/schema_concettuale.pdf}
|
||||||
|
\caption{Schema concettuale in formato grafico}
|
||||||
|
\label{fig:schema-concettuale}
|
||||||
|
\end{figure}
|
||||||
|
\input{\folder/schema_concettuale.tex}
|
||||||
|
\section{Schema logico}\label{sec:schema-logico}
|
||||||
|
\begin{figure}[htb]
|
||||||
|
\centering
|
||||||
|
\includegraphics[width=\linewidth]{\folder/schema_logico.pdf}
|
||||||
|
\caption{Schema logico in formato grafico}
|
||||||
|
\label{fig:schema-logico}
|
||||||
|
\end{figure}
|
||||||
|
\input{\folder/schema_logico.tex}
|
||||||
|
\clearpage
|
||||||
|
\section{Interrogazioni}\label{sec:queries}
|
||||||
|
\input{\folder/queries.tex}
|
||||||
|
\vskip2pc
|
||||||
|
\section{Piani di accesso}\label{sec:piani}
|
||||||
|
\input{\folder/piani_di_accesso.tex}
|
||||||
|
\end{document}
|
22
compitino/primo_compitino/dominio.tex
Normal file
22
compitino/primo_compitino/dominio.tex
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
|
||||||
|
La catena editoriale ``Sempre sul pezzo" pubblica giornali cartacei e gestisce siti di notizie. Per
|
||||||
|
ciascuna modalità editoriale, interessa conoscere il titolo, il direttore e l’anno di fondazione.
|
||||||
|
Per la modalità cartacea interessa anche il comune di stampa, mentre per la modalità
|
||||||
|
digitalizzata interessa l’URL.
|
||||||
|
Per ogni modalità editoriale lavorano dei giornalisti, che possono essere dipendenti oppure
|
||||||
|
free-lance e possono pubblicare articoli per più modalità editoriali. Di tutti i giornalisti
|
||||||
|
interessa conoscere il numero di iscrizione all’Albo dei Giornalisti (se presente), il cognome, il
|
||||||
|
nome e tenere traccia degli articoli pubblicati (ogni articolo può avere uno o più autori). Dei
|
||||||
|
dipendenti interessa il codice INPS per versare i tributi, mentre dei free-lance la partita IVA per
|
||||||
|
emettere fatture.
|
||||||
|
Degli articoli interessa il titolo, il sottotitolo, l’edizione (cartacea o digitale) in cui sono
|
||||||
|
pubblicati (ogni articolo è pubblicato in una sola edizione) e la data di pubblicazione. Ci sono
|
||||||
|
articoli visibili a tutti e articoli premium riservati agli abbonati.
|
||||||
|
I siti Web sono dotati di un sistema di tracciamento che registra, per ogni articolo, il numero di
|
||||||
|
visite e il tempo dedicato alla lettura per ogni visita.
|
||||||
|
Gli utenti possono avere un abbonamento: in questo caso, l’identità dell’utente è associata
|
||||||
|
all’accesso all’articolo online. Degli utenti interessa nome, cognome e indirizzo.
|
||||||
|
Degli abbonamenti, si vuole tenere traccia della data di sottoscrizione e quella di scadenza.
|
||||||
|
Ogni abbonamento è associato a un sito web di notizie, ogni utente può avere più
|
||||||
|
abbonamenti.
|
191
compitino/primo_compitino/piani_di_accesso.tex
Normal file
191
compitino/primo_compitino/piani_di_accesso.tex
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
\subsection{Query a}
|
||||||
|
|
||||||
|
\paragraph{Piano di accesso logico della query a}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}
|
||||||
|
[{$\pi^{b}$ e.Titolo, sw.Url}
|
||||||
|
[{$\bowtie$ e.IdEdizione = sw.IdEdizione}
|
||||||
|
[{$\sigma$e.Titolo $>=$'G' $\wedge$ e.Titolo $<$ 'H'}
|
||||||
|
[Edizioni e]
|
||||||
|
]
|
||||||
|
[SitiWeb sw]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\paragraph{Piano di accesso fisico della query a senza indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}
|
||||||
|
[{Project(\{e.Titolo, sw.Url\})}
|
||||||
|
[{SortMerge(e.IdEdizione = sw.IdEdizione)}
|
||||||
|
[{Sort(\{e.IdEdizione\})}
|
||||||
|
[{Project(\{e.Titolo, e.IdEdizione\})}
|
||||||
|
[{Filter(e.Titolo $>=$ 'G' AND e.Titolo $<$ H)}
|
||||||
|
[{TableScan(Edizioni e)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[{Sort(\{sw.IdEdizione\})}
|
||||||
|
[{Project(\{sw.Url, sw.IdEdizione\})}
|
||||||
|
[{TableScan(SitiWeb sw)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\paragraph{Piano di accesso fisico della query a con due indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}, baseline, qtree
|
||||||
|
[{Project(\{e.Titolo, sw.Url\})}
|
||||||
|
[{IndexNestedLoop(e.IdEdizione = sw.IdEdizione)}
|
||||||
|
[{IndexFilter(Edizioni e, IndETit,\\ e.Titolo $>=$ 'G' AND e.Titolo $<$ H)}]
|
||||||
|
[{IndexFilter(SitiWeb sw, IndSWIdEd,\\ e.IdEdizione = sw.IdEdizione)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
Indici necessari: \texttt{IndETit} (indice della tabella Edizioni sull’attributo Titolo) e \texttt{IndSWIdEd} (indice della tabella SitiWeb sulla chiave IdEdizione).
|
||||||
|
|
||||||
|
\subsection{Query b}
|
||||||
|
\paragraph{Piano di accesso logico della query b}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}
|
||||||
|
[{$\tau$(\{$-$TempoTotaleLettura\})}
|
||||||
|
[{$\pi^{b}$ v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura}
|
||||||
|
[{$\sigma$ SUM(v.TempoLettura) $>$ 10}
|
||||||
|
[{\{v.IdUtente\} $\gamma$ \{SUM(v.TempoLettura)\}}
|
||||||
|
[{$\sigma$ v.TempoLettura $<$ 60}
|
||||||
|
[{Visite v}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
L’output dell’operatore $\gamma$ è già proiettato sulle sole dimensioni di analisi e risultati delle
|
||||||
|
funzioni di aggregazione, non occorrerebbe proiettare su \texttt{\{v.IdUtente, SUM(v.TempoLettura)\}}; lo faccio per poter rinominare in TempoTotaleLettura il risultato della SUM.
|
||||||
|
|
||||||
|
Nella $\tau$, l’ordinamento discendente è reso dal segno `$-$' per convenzione (in questo caso comunque il tipo è numerico).
|
||||||
|
|
||||||
|
\paragraph{Piano di accesso fisico della query b senza indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}
|
||||||
|
[{Sort(\{$-$TempoTotaleLettura\})}
|
||||||
|
[{Project(\{v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura\})}
|
||||||
|
[{Filter(SUM(v.TempoLettura) $>$ 10)}
|
||||||
|
[{GroupBy(\{v.IdUtente\}, \{SUM(v.TempoLettura)\})}
|
||||||
|
[{Sort(\{v.IdUtente\})}
|
||||||
|
[{Project(\{v.IdUtente, v.TempoLettura\})}
|
||||||
|
[{Filter(v.TempoLettura $<$ 60)}
|
||||||
|
[{TableScan(Visite v)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
|
||||||
|
\clearpage
|
||||||
|
\paragraph{Piano di accesso fisico della query b con indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}, baseline, qtree
|
||||||
|
[{Sort(\{$-$TempoTotaleLettura\})}
|
||||||
|
[{Project(\{v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura\})}
|
||||||
|
[{GroupBy(\{v.IdUtente\}, \{SUM(v.TempoLettura)\})}
|
||||||
|
[{\sout{Project(\{v.IdUtente, v.TempoLettura\})}}
|
||||||
|
[{IndexFilter(Visite v, IndVIdUt, v.TempoLettura $<$ 60)}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
Indice necessario: \texttt{IndVIdUt} (indice della tabella Visite sull’attributo IdUtente).
|
||||||
|
|
||||||
|
Non occorre ordinare prima di raggruppare: l’output di IndexFilter è già ordinato sull’insieme di attributi dell’indice (in questo caso \texttt{\{v.IdUtente\}}), che coincide nel nostro caso con l’insieme delle dimensioni di analisi.
|
||||||
|
|
||||||
|
Non occorre nemmeno proiettare su \texttt{\{v.IdUtente, v.TempoLettura\}} prima del raggruppamento, in quanto la groupby può ricevere il record direttamente dalla IndexFilter e scartare gli attributi non rilevanti (cioè quelli che non sono dimensione di analisi né input delle funzioni di aggregazione).
|
||||||
|
\vfill
|
||||||
|
\subsection{Query c}
|
||||||
|
\paragraph{Piano di accesso logico della query c}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}, baseline, qtree
|
||||||
|
[{$\pi$ a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura}
|
||||||
|
[{$\sigma$ COUNT(*) $>=$ 3}
|
||||||
|
[{\{a.IdArticolo, a.Titolo\} $\gamma$ \{COUNT(*), SUM(v.TempoLettura)\}}
|
||||||
|
[{$\bowtie$ a.IdArticolo = v.IdArticolo}
|
||||||
|
[{$\sigma$ a.Premium = 'N'}
|
||||||
|
[{Articoli a}]
|
||||||
|
]
|
||||||
|
[{Visite v}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
\clearpage
|
||||||
|
\paragraph{Piano di accesso fisico della query c senza indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}, baseline, qtree
|
||||||
|
[{Project(\{a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura\})}
|
||||||
|
[{Filter(COUNT(*) $>=$ 3)}
|
||||||
|
[{GroupBy(\{a.IdArticolo, a.Titolo\}, \{COUNT(*), SUM(v.TempoLettura)\})}
|
||||||
|
[{SortMerge(a.IdArticolo = v.IdArticolo)}
|
||||||
|
[{Sort(a.IdArticolo)}
|
||||||
|
[{Project(\{a.IdArticolo, a.Titolo\})}
|
||||||
|
[{Filter(a.Premium = 'N')}
|
||||||
|
[{TableScan(Articoli a)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[{Sort(v.IdArticolo)}
|
||||||
|
[{Project(\{v.IdArticolo, v.TempoLettura\})}
|
||||||
|
[{TableScan(Visite v)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
L’output di SortMerge è già ordinato per a.IdArticolo e, dato che \texttt{a.IdArticolo $\to$ a.Titolo},
|
||||||
|
non occorre ordinare prima della groupby.
|
||||||
|
|
||||||
|
\paragraph{Piano di accesso fisico della query c con due indici}
|
||||||
|
\begin{center}
|
||||||
|
\begin{forest}, baseline, qtree
|
||||||
|
[{Project(\{a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,\\SUM(v.TempoLettura) TempoTotaleLettura\})}
|
||||||
|
[{Filter(COUNT(*) $>=$ 3)}
|
||||||
|
[{GroupBy(\{a.IdArticolo, a.Titolo\}, \{COUNT(*), SUM(v.TempoLettura)\})}
|
||||||
|
[{IndexNestedLoop(a.IdArticolo = v.IdArticolo)}
|
||||||
|
[{Project(\{a.IdArticolo, a.Titolo\})}
|
||||||
|
[{IndexFilter(Articoli a,\\ IndAIdA, a.Premium = 'N')}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
[{Project(\{v.IdArticolo, v.TempoLettura\})}
|
||||||
|
[{IndexFilter(Visite v,\\IndVIdA, v.IdArticolo = a.IdArticolo)}]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
\end{forest}
|
||||||
|
\end{center}
|
||||||
|
Indici necessari: IndAIdA (indice della tabella Articoli sull’attributo IdArticolo), IndVIdA (indice
|
||||||
|
della tabella Visite sull’attributo IdArticolo).
|
||||||
|
Non occorre fare un ordinamento sull’output della IndexNestedLoop: avendo ricevuto input
|
||||||
|
ordinato su IdArticolo dalla IndexFilter, e sapendo che \texttt{a.IdArticolo $\to$ a.Titolo}, l’input
|
||||||
|
della groupby è già raggruppato per le dimensioni di analisi.
|
119
compitino/primo_compitino/queries.tex
Normal file
119
compitino/primo_compitino/queries.tex
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
|
||||||
|
\begin{enumerate}[label=\alph*.]
|
||||||
|
\item Uso di proiezione, join e restrizione
|
||||||
|
|
||||||
|
Riportare il titolo e l’URL dei siti web il cui titolo inizia con la lettera G (compreso il caso
|
||||||
|
in cui il titolo sia esattamente 'G’).
|
||||||
|
\begin{lstlisting}[style=SQLu]
|
||||||
|
SELECT e.Titolo, sw.Url
|
||||||
|
FROM Edizioni e
|
||||||
|
JOIN SitiWeb sw ON e.IdEdizione = sw.IdEdizione
|
||||||
|
WHERE e.Titolo >= 'G' AND e.Titolo < 'H'
|
||||||
|
\end{lstlisting}
|
||||||
|
\item Uso di group by con having, where e sort
|
||||||
|
|
||||||
|
Riportare IdUtente e tempo totale di lettura, purché superiore a 10 minuti, escludendo
|
||||||
|
le sessioni di lettura lunghe un’ora o più (probabilmente l’utente avrà lasciato aperta la
|
||||||
|
pagina, non stava davvero leggendo: sui nostri siti peraltro dopo 55 minuti di inattività
|
||||||
|
si attiva una animazione che copre l’articolo e chiede di premere un pulsante per
|
||||||
|
continuare a leggere, altrimenti esegue il logout dell’utente dopo 5 minuti) e ordinando
|
||||||
|
dall’utente che ha passato più minuti a leggere a quello che ne ha passati meno.
|
||||||
|
\begin{lstlisting}[style=SQLu]
|
||||||
|
SELECT v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura
|
||||||
|
FROM Visite v
|
||||||
|
WHERE v.TempoLettura < 60
|
||||||
|
GROUP BY v.IdUtente
|
||||||
|
HAVING SUM(v.TempoLettura) > 10
|
||||||
|
ORDER BY SUM(v.TempoLettura) DESC
|
||||||
|
\end{lstlisting}
|
||||||
|
\item Uso di join, group by con having e where
|
||||||
|
|
||||||
|
Riportare il codice articolo, il titolo, il numero di visite e il tempo totale di lettura degli
|
||||||
|
articoli ad accesso libero (ovvero non premium) visti almeno 3 volte.
|
||||||
|
\begin{lstlisting}[style=SQLu]
|
||||||
|
SELECT a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,
|
||||||
|
SUM(v.TempoLettura) TempoTotaleLettura
|
||||||
|
FROM Visite v
|
||||||
|
JOIN Articoli a ON a.IdArticolo = v.IdArticolo
|
||||||
|
WHERE a.Premium = 'N'
|
||||||
|
GROUP BY a.IdArticolo, a.Titolo
|
||||||
|
HAVING COUNT(*) >= 3
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Posso fare COUNT(*) perché la giunzione con chiave esterna IdArticolo (che è chiave
|
||||||
|
primaria della tabella Articoli) avrà tante righe quante ce ne sono nella tabella Visite:
|
||||||
|
per ogni riga di Visite c’è una sola riga di Articoli.
|
||||||
|
Raggruppo anche per titolo oltre che per IdArticolo (anche se IdArticolo → Titolo)
|
||||||
|
perché proietto poi anche il Titolo.
|
||||||
|
\item Uso di select annidata con quantificazione esistenziale
|
||||||
|
|
||||||
|
Riportare Cognome e Nome dei giornalisti che hanno scritto almeno un articolo sul
|
||||||
|
giornale “Il Titanio".
|
||||||
|
\begin{lstlisting}[style=SQLu]
|
||||||
|
SELECT g.Cognome, g.Nome
|
||||||
|
FROM Giornalisti g
|
||||||
|
WHERE EXISTS (SELECT *
|
||||||
|
FROM ArticoliGiornalisti ag
|
||||||
|
JOIN Articoli a ON a.IdArticolo = ag.IdArticolo
|
||||||
|
JOIN Edizioni e ON e.IdEdizione = a.IdEdizione
|
||||||
|
WHERE ag.IdGiornalista = g.IdGiornalista
|
||||||
|
AND e.Titolo = 'Il Titanio')
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
NOTA: avrei potuto fare una giunzione su IdGiornalista anziché una quantificazione
|
||||||
|
esistenziale.
|
||||||
|
\item Uso di select annidata con quantificazione universale
|
||||||
|
|
||||||
|
Riportare Cognome e Nome dei giornalisti che hanno scritto solo articoli per giornali
|
||||||
|
diretti da Peppone.
|
||||||
|
Esprimo in notazione insiemistica:
|
||||||
|
\begin{lstlisting}[style=SQLu,escapechar=@]
|
||||||
|
{g.Cognome, g.Nome | g @$\in$@ Giornalisti .
|
||||||
|
@$\forall$@ (ag @$\in$@ ArticoliGiornalisti, a @$\in$@ Articoli, e @$\in$@ Edizioni,
|
||||||
|
a.IdArticolo = ag.IdArticolo,
|
||||||
|
e.IdEdizione = a.IdEdizione,
|
||||||
|
ag.IdGiornalista = g.IdGiornalista) .
|
||||||
|
(e.Direttore = 'Peppone')}
|
||||||
|
\end{lstlisting}
|
||||||
|
Trasformando il $\forall x.P$ in $\neg\exists x.\neg P$:
|
||||||
|
\begin{lstlisting}[style=SQLu,escapechar=@]
|
||||||
|
{g.Cognome, g.Nome | g @$\in$@ Giornalisti .
|
||||||
|
@$\neg\exists$@ (ag @$\in$@ ArticoliGiornalisti, a @$\in$@ Articoli, e @$\in$@ Edizioni,
|
||||||
|
a.IdArticolo = ag.IdArticolo,
|
||||||
|
e.IdEdizione = a.IdEdizione,
|
||||||
|
ag.IdGiornalista = g.IdGiornalista) .
|
||||||
|
(e.Direttore = 'Peppone')}
|
||||||
|
\end{lstlisting}
|
||||||
|
Scrivo quindi la query:
|
||||||
|
\begin{lstlisting}[style=SQLu,escapechar=@]
|
||||||
|
SELECT g.Cognome, g.Nome
|
||||||
|
FROM Giornalisti g
|
||||||
|
WHERE NOT EXISTS (SELECT *
|
||||||
|
FROM ArticoliGiornalisti ag
|
||||||
|
JOIN Articoli a
|
||||||
|
ON a.IdArticolo = ag.IdArticolo
|
||||||
|
JOIN Edizioni e
|
||||||
|
ON e.IdEdizione = a.IdEdizione
|
||||||
|
WHERE ag.IdGiornalista = g.IdGiornalista
|
||||||
|
AND e.Direttore != 'Peppone')
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
NOTA: i giornalisti che non hanno scritto articoli compariranno nel risultato.
|
||||||
|
\item Uso di subquery di confronto quantificato usando una subquery di tipo scalare
|
||||||
|
|
||||||
|
Voglio premiare il dipendente che esercita la professione da più tempo: per fare questo,
|
||||||
|
ho bisogno di sapere il codice INPS del giornalista con numero di iscrizione all’albo più
|
||||||
|
basso.
|
||||||
|
\begin{lstlisting}[style=SQLu,escapechar=@]
|
||||||
|
SELECT gd.CodiceInps
|
||||||
|
FROM GiornalistiDipendenti gd
|
||||||
|
JOIN Giornalisti g ON g.IdGiornalista = gd.IdGiornalista
|
||||||
|
WHERE g.NumeroAlbo = ANY(SELECT MIN(g2.NumeroALbo)
|
||||||
|
FROM Giornalisti g2
|
||||||
|
JOIN GiornalistiDipendenti gd2
|
||||||
|
ON g2.IdGiornalista = gd2.IdGiornalista)
|
||||||
|
\end{lstlisting}
|
||||||
|
La subquery scalare restituisce un singolo valore, mentre il confronto quantificato è utile
|
||||||
|
quando la subquery restituisce un insieme di più valori. \lstinline[language=SQL]{= ANY} equivale a \lstinline[language=SQL]{IN}.
|
||||||
|
\end{enumerate}
|
BIN
compitino/primo_compitino/schema_concettuale.pdf
Normal file
BIN
compitino/primo_compitino/schema_concettuale.pdf
Normal file
Binary file not shown.
4
compitino/primo_compitino/schema_concettuale.tex
Normal file
4
compitino/primo_compitino/schema_concettuale.tex
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
|
||||||
|
Vincolo non catturato graficamente: un articolo può avere visite solo se la sua edizione è
|
||||||
|
online.
|
BIN
compitino/primo_compitino/schema_logico.pdf
Normal file
BIN
compitino/primo_compitino/schema_logico.pdf
Normal file
Binary file not shown.
38
compitino/primo_compitino/schema_logico.tex
Normal file
38
compitino/primo_compitino/schema_logico.tex
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
|
||||||
|
\textbf{Schema logico relazionale in formato testuale}
|
||||||
|
\begin{lstlisting}[style=SQLu,escapechar=@]
|
||||||
|
Giornali(@\underline{IdEdizione*}@, ComuneStampa)
|
||||||
|
SitiWeb(@\underline{IdEdizione*}@, Url)
|
||||||
|
Edizioni(@\underline{IdEdizione}@, Titolo, Direttore, AnnoFondazione)
|
||||||
|
Articoli(@\underline{IdArticolo}@, IdEdizione*, Titolo, Sottotitolo,
|
||||||
|
DataPubblicazione, Premium)
|
||||||
|
Visite(@\underline{IdVisita}@, IdArticolo*, TempoLettura, IdUtente*)
|
||||||
|
Utenti(@\underline{IdUtente}@, Nome, Cognome, Indirizzo)
|
||||||
|
Abbonamenti(@\underline{IdUtente*, IdEdizione*, DataSottoscrizione}@, DataScadenza)
|
||||||
|
ArticoliGiornalisti(@\underline{IdArticolo*, IdGiornalista*}@)
|
||||||
|
Giornalisti(@\underline{IdGiornalista}@, NumeroAlbo, Cognome, Nome)
|
||||||
|
GiornalistiDipendenti(@\underline{IdGiornalista*}@, CodiceInps)
|
||||||
|
GiornalistiFreeLance(@\underline{IdGiornalista*}@, PartitaIva)
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\paragraph{Dipendenze funzionali}
|
||||||
|
\begin{itemize}
|
||||||
|
\item Per ogni tabella la chiave primaria (sottolineata) determina ciascuno degli attributi della tabella ($\{IdEdizione \to Titolo, IdEdizione \to Direttore, \textellipsis\}$)
|
||||||
|
\item Nella tabella Giornalisti, vale inoltre che $\{NumeroAlbo \to Nome;$ $NumeroAlbo \to Cognome;$ $NumeroAlbo \to IdGiornalista\}$: NumeroAlbo è una chiave naturale (l’Ordine dei Giornalisti si cura di non attribuire lo stesso numero di iscrizione all’albo a due giornalisti diversi), ho scelto di aggiungere la chiave artificiale IdGiornalista prevedendo possibili errori di inserimento da parte della segreteria della catena editoriale: in queto modo, il NumeroAlbo può essere modificato senza problemi in caso di errori. Discorso analogo per CodiceInps e PartitaIva.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
|
||||||
|
Uno schema R, avente insieme di attributi T e insieme di dipendenze funzionali F, (\lstinline{R<T, F>}) è
|
||||||
|
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 i determinanti sono tutti 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}.
|
||||||
|
|
||||||
|
NOTA: assumo che la stringa “Indirizzo” e simili siano attributi atomici, anche se forse nella
|
||||||
|
realtà sarebbero meglio rappresentati in altro modo.
|
9
compitino/primo_compitino/testo.tex
Normal file
9
compitino/primo_compitino/testo.tex
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
% !TEX root = ../main.tex
|
||||||
|
|
||||||
|
Una catena di quotidiani vuole gestire informazioni relative ad articoli scritti da giornalisti che
|
||||||
|
possono essere dipendenti oppure free-lance, e i quali possono essere pubblicati sia su un
|
||||||
|
solo quotidiano che su diversi quotidiani del gruppo. La catena stampa versioni cartacee ma
|
||||||
|
pubblica anche siti web. I siti web sono muniti di sistemi di tracciamento che permettono di
|
||||||
|
conoscere il numero di click su ogni articolo e il tempo dedicato alla lettura. La catena è anche
|
||||||
|
interessata a gestire gli abbonamenti. Quando un abbonato opera sul sito web, la sua identità
|
||||||
|
è nota, e quindi i suoi click sono associati alla sua identità.
|
Loading…
x
Reference in New Issue
Block a user