Queer European MD passionate about IT

queries.tex 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. % !TEX root = ../main.tex
  2. \begin{enumerate}[label=\alph*.]
  3. \item Uso di proiezione, join e restrizione
  4. Riportare il titolo e l’URL dei siti web il cui titolo inizia con la lettera G (compreso il caso
  5. in cui il titolo sia esattamente 'G’).
  6. \begin{lstlisting}[style=SQLu]
  7. SELECT e.Titolo, sw.Url
  8. FROM Edizioni e
  9. JOIN SitiWeb sw ON e.IdEdizione = sw.IdEdizione
  10. WHERE e.Titolo >= 'G' AND e.Titolo < 'H'
  11. \end{lstlisting}
  12. \item Uso di group by con having, where e sort
  13. Riportare IdUtente e tempo totale di lettura, purché superiore a 10 minuti, escludendo
  14. le sessioni di lettura lunghe un’ora o più (probabilmente l’utente avrà lasciato aperta la
  15. pagina, non stava davvero leggendo: sui nostri siti peraltro dopo 55 minuti di inattività
  16. si attiva una animazione che copre l’articolo e chiede di premere un pulsante per
  17. continuare a leggere, altrimenti esegue il logout dell’utente dopo 5 minuti) e ordinando
  18. dall’utente che ha passato più minuti a leggere a quello che ne ha passati meno.
  19. \begin{lstlisting}[style=SQLu]
  20. SELECT v.IdUtente, SUM(v.TempoLettura) TempoTotaleLettura
  21. FROM Visite v
  22. WHERE v.TempoLettura < 60
  23. GROUP BY v.IdUtente
  24. HAVING SUM(v.TempoLettura) > 10
  25. ORDER BY SUM(v.TempoLettura) DESC
  26. \end{lstlisting}
  27. \item Uso di join, group by con having e where
  28. Riportare il codice articolo, il titolo, il numero di visite e il tempo totale di lettura degli
  29. articoli ad accesso libero (ovvero non premium) visti almeno 3 volte.
  30. \begin{lstlisting}[style=SQLu]
  31. SELECT a.IdArticolo, a.Titolo, COUNT(*) NumeroVisite,
  32. SUM(v.TempoLettura) TempoTotaleLettura
  33. FROM Visite v
  34. JOIN Articoli a ON a.IdArticolo = v.IdArticolo
  35. WHERE a.Premium = 'N'
  36. GROUP BY a.IdArticolo, a.Titolo
  37. HAVING COUNT(*) >= 3
  38. \end{lstlisting}
  39. Posso fare COUNT(*) perché la giunzione con chiave esterna IdArticolo (che è chiave
  40. primaria della tabella Articoli) avrà tante righe quante ce ne sono nella tabella Visite:
  41. per ogni riga di Visite c’è una sola riga di Articoli.
  42. Raggruppo anche per titolo oltre che per IdArticolo (anche se IdArticolo → Titolo)
  43. perché proietto poi anche il Titolo.
  44. \item Uso di select annidata con quantificazione esistenziale
  45. Riportare Cognome e Nome dei giornalisti che hanno scritto almeno un articolo sul
  46. giornale “Il Titanio".
  47. \begin{lstlisting}[style=SQLu]
  48. SELECT g.Cognome, g.Nome
  49. FROM Giornalisti g
  50. WHERE EXISTS (SELECT *
  51. FROM ArticoliGiornalisti ag
  52. JOIN Articoli a ON a.IdArticolo = ag.IdArticolo
  53. JOIN Edizioni e ON e.IdEdizione = a.IdEdizione
  54. WHERE ag.IdGiornalista = g.IdGiornalista
  55. AND e.Titolo = 'Il Titanio')
  56. \end{lstlisting}
  57. NOTA: avrei potuto fare una giunzione su IdGiornalista anziché una quantificazione
  58. esistenziale.
  59. \item Uso di select annidata con quantificazione universale
  60. Riportare Cognome e Nome dei giornalisti che hanno scritto solo articoli per giornali
  61. diretti da Peppone.
  62. Esprimo in notazione insiemistica:
  63. \begin{lstlisting}[style=SQLu,escapechar=@]
  64. {g.Cognome, g.Nome | g @$\in$@ Giornalisti .
  65. @$\forall$@ (ag @$\in$@ ArticoliGiornalisti, a @$\in$@ Articoli, e @$\in$@ Edizioni,
  66. a.IdArticolo = ag.IdArticolo,
  67. e.IdEdizione = a.IdEdizione,
  68. ag.IdGiornalista = g.IdGiornalista) .
  69. (e.Direttore = 'Peppone')}
  70. \end{lstlisting}
  71. Trasformando il $\forall x.P$ in $\neg\exists x.\neg P$:
  72. \begin{lstlisting}[style=SQLu,escapechar=@]
  73. {g.Cognome, g.Nome | g @$\in$@ Giornalisti .
  74. @$\neg\exists$@ (ag @$\in$@ ArticoliGiornalisti, a @$\in$@ Articoli, e @$\in$@ Edizioni,
  75. a.IdArticolo = ag.IdArticolo,
  76. e.IdEdizione = a.IdEdizione,
  77. ag.IdGiornalista = g.IdGiornalista) .
  78. (e.Direttore = 'Peppone')}
  79. \end{lstlisting}
  80. Scrivo quindi la query:
  81. \begin{lstlisting}[style=SQLu,escapechar=@]
  82. SELECT g.Cognome, g.Nome
  83. FROM Giornalisti g
  84. WHERE NOT EXISTS (SELECT *
  85. FROM ArticoliGiornalisti ag
  86. JOIN Articoli a
  87. ON a.IdArticolo = ag.IdArticolo
  88. JOIN Edizioni e
  89. ON e.IdEdizione = a.IdEdizione
  90. WHERE ag.IdGiornalista = g.IdGiornalista
  91. AND e.Direttore != 'Peppone')
  92. \end{lstlisting}
  93. NOTA: i giornalisti che non hanno scritto articoli compariranno nel risultato.
  94. \item Uso di subquery di confronto quantificato usando una subquery di tipo scalare
  95. Voglio premiare il dipendente che esercita la professione da più tempo: per fare questo,
  96. ho bisogno di sapere il codice INPS del giornalista con numero di iscrizione all’albo più
  97. basso.
  98. \begin{lstlisting}[style=SQLu,escapechar=@]
  99. SELECT gd.CodiceInps
  100. FROM GiornalistiDipendenti gd
  101. JOIN Giornalisti g ON g.IdGiornalista = gd.IdGiornalista
  102. WHERE g.NumeroAlbo = ANY(SELECT MIN(g2.NumeroALbo)
  103. FROM Giornalisti g2
  104. JOIN GiornalistiDipendenti gd2
  105. ON g2.IdGiornalista = gd2.IdGiornalista)
  106. \end{lstlisting}
  107. La subquery scalare restituisce un singolo valore, mentre il confronto quantificato è utile
  108. quando la subquery restituisce un insieme di più valori. \lstinline[language=SQL]{= ANY} equivale a \lstinline[language=SQL]{IN}.
  109. \end{enumerate}