First assignment uploaded
This commit is contained in:
parent
9c5714851a
commit
6531fb6d49
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,6 @@
|
||||
# ---> TeX
|
||||
out/
|
||||
|
||||
## Core latex/pdflatex auxiliary files:
|
||||
*.aux
|
||||
*.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