Esercizio - Interrogazioni sulle formule scientifiche (tema d'esame 22 gennaio 2025)
In questa pagina 7
Testo (esame di Basi di Dati, D.M. 270, 22 gennaio 2025, II e III parte, dal corso di Basi di Dati, Ing. Informatica UniPD). Degli studenti vogliono progettare un database per archiviare, categorizzare e collegare formule scientifiche e matematiche, una risorsa sulle loro origini, applicazioni ed evoluzione. Requisiti:
- gli utenti del database (ricercatori, educatori, storici della scienza) non sono da memorizzare;
- per ogni formula: il nome (per esempio legge di gravitazione di Newton), l'espressione (per esempio ), la descrizione, l'anno di scoperta (per esempio 1687), il campo di studio di riferimento e gli scienziati che l'hanno definita (ogni formula è definita da almeno uno scienziato);
- per ogni scienziato: nome, cognome e campo di studio principale;
- per ogni formula, le pubblicazioni scientifiche che la menzionano, di ciascuna con titolo, sommario, anno e un identificatore unico (per esempio un DOI); non si salvano pubblicazioni che non menzionano formule.
Interrogazioni, in SQL e in algebra relazionale (senza aggiungere attributi ridondanti):
- quali formule sono state attribuite a scienziati con cognome "Bernoulli";
- se esistono, gli scienziati che hanno la "Fisica" come campo di studio principale e che hanno definito formule per il campo di studio "Matematica";
- lo scienziato che ha definito il maggior numero di formule.
(Domanda 2, per la lode: modifiche allo schema ER e relazionale per rispondere in modo più efficiente ad almeno una query.)
La progettazione ER (formula come entità con ID seriale, campo di studio come entità e non come attributo, scienziato con id e non identificato da nome e cognome, pubblicazione con cardinalità ) è nell'esercizio di progettazione della stessa traccia. Teoria: SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni →, SQL - query nidificate, operatori insiemistici e visteUna sottoquery è una SELECT tra parentesi dentro un'altra: nella FROM (tabella derivata, con alias obbligatorio in PostgreSQL) oppure nella WHERE, come valore scalare con =, <, ..., come insieme con IN / NOT IN, ANY, ALL, oppure con EXISTS / NOT EXISTS. Una sottoquery correlata usa colonne della query esterna e va rivalutata per ogni riga. Le funzioni di aggregazione non si possono usare in WHERE: il massimo si ottiene con una sottoquery scalare (WHERE n = (SELECT MAX(n) ...)), con una vista o una CTE. NOT IN con una sottoquery che contiene NULL non restituisce mai righe: meglio NOT EXISTS, EXCEPT o LEFT JOIN ... IS NULL. "Per tutti" (divisione) = doppio NOT EXISTS o HAVING COUNT(DISTINCT ...) = numero totale. Gli operatori insiemistici UNION, INTERSECT, EXCEPT richiedono query compatibili e di default eliminano i duplicati (ALL li mantiene). Una vista è una tabella virtuale definita da una query (CREATE VIEW, DROP VIEW): semplifica le query, riusa sottoquery, nasconde i dati; la vista materializzata invece memorizza il risultato.SQL - query nidificate, operatori insiemistici e viste →, Algebra relazionale - operatori di base e joinLe operazioni sul modello relazionale sono di aggiornamento (inserimento, modifica, cancellazione, che possono violare i vincoli di integrità: si rifiuta, si corregge, si propaga con cascade o si imposta NULL/default) e di interrogazione (funzioni che da un'istanza del database producono una relazione). L'algebra relazionale è il linguaggio procedurale delle interrogazioni: gli operatori primitivi sono unione, differenza, prodotto, rinomina ρ, selezione σ e proiezione π; derivati sono intersezione, theta-join, equi-join, join naturale. Unione, intersezione e differenza richiedono relazioni compatibili all'unione (stessi attributi e domini). La selezione è una decomposizione orizzontale, la proiezione verticale (commutano solo se gli attributi della selezione sono nella proiezione). Il theta-join è σ_φ(R1×R2), il join naturale equivale a un equi-join sugli attributi omonimi seguito da una proiezione; la sua cardinalità è tra 0 e |R1||R2|, ≤|R1| se gli attributi comuni sono chiave di R2, =|R1| se sono anche chiave esterna di R1 con vincolo di integrità referenziale. Le tuple senza corrispondente sono "dangling". I valori NULL richiedono condizioni esplicite IS NULL / IS NOT NULL, perché σ_{A>40} ∪ σ_{A≤40} non restituisce le tuple con A nullo.Algebra relazionale - operatori di base e join →.
Progettazione ER e schema relazionale della stessa traccia: Esercizio - Progettazione ER e schema relazionale delle formule scientifiche (tema d'esame 22 gennaio 2025).
Schema relazionale (dalla soluzione del corso)
Chiavi in grassetto.
| Relazione | Attributi | Note |
|---|---|---|
PUBBLICAZIONE |
doi, titolo, sommario, anno | |
CAMPO_STUDIO |
id, nome | il campo è un'entità (condivisa da formule e scienziati), identificata da un id seriale |
FORMULA |
id, nome, descrizione, espressione, anno, campo CAMPO_STUDIO |
l'id è un seriale: il nome non basta (due formule possono avere lo stesso nome e espressione diversa) |
SCIENZIATO |
id, nome, cognome, campo CAMPO_STUDIO |
nome e cognome non identificano (omonimi), né c'è un codice fiscale nel testo |
pubblicazione PUBBLICAZIONE, formula FORMULA |
quali formule menziona una pubblicazione; vincolo: almeno una per pubblicazione | |
formula FORMULA, scienziato SCIENZIATO |
chi ha definito una formula; vincolo: almeno uno scienziato per formula |
La relazione FORMULA–CAMPO_STUDIO è un'associazione uno-a-molti (una formula ha un campo): diventa la chiave esterna FORMULA.campo; lo stesso per SCIENZIATO.campo.
Dati inventati. CAMPO_STUDIO: 1 Fisica, 2 Matematica, 3 Chimica. SCIENZIATO (id, nome cognome, campo): 1 Jacob Bernoulli (Matematica), 2 Daniel Bernoulli (Fisica), 3 Isaac Newton (Fisica), 4 Carl Gauss (Matematica), 5 Marie Curie (Chimica). FORMULA (id, nome, campo): 1 gravitazione universale (Fisica), 2 equazione di Bernoulli dei fluidi (Fisica), 3 legge dei grandi numeri (Matematica), 4 legge di Gauss (Fisica), 5 minimi quadrati (Matematica), 6 equazione di Bernoulli per le EDO (Matematica), 7 binomio di Newton (Matematica), 8 decadimento radioattivo (Fisica), 9 seconda legge della dinamica (Fisica). (formula, scienziato): (1,3), (2,2), (3,1), (4,4), (5,4), (6,1), (6,2), (7,3), (8,5), (9,3). La formula 6 è stata definita da due Bernoulli.
Query 1: le formule attribuite a scienziati con cognome "Bernoulli"
Idea. Si parte da SCIENZIATO filtrato per cognome, si passa per (chi ha definito cosa) e si arriva a FORMULA: una catena di due join.
Algebra. La rinomina degli attributi omonimi (id, nome) di SCIENZIATO evita ambiguità con FORMULA:
(la soluzione del corso proietta e dimentica nome; il nome della formula è utile e l'SQL del corso lo seleziona: conviene tenerlo in entrambi.) La proiezione elimina i duplicati.
SQL.
SELECT DISTINCT f.id, f.nome, f.descrizione, f.espressione, f.anno
FROM formula AS f
INNER JOIN r3 AS r ON f.id = r.formula
INNER JOIN scienziato AS s ON r.scienziato = s.id
WHERE s.cognome = 'Bernoulli';Risultato: formule 2 (equazione di Bernoulli dei fluidi, di Daniel), 3 (legge dei grandi numeri, di Jacob) e 6 (equazione di Bernoulli per le EDO, di Jacob e Daniel).
Errore nella soluzione del corso. L'SQL del corso manca del
DISTINCT. La formula 6 è definita da due Bernoulli, quindi il join produce due righe per essa: senzaDISTINCTla query restituisce 4 righe (2, 3, 6, 6) mentre l'algebra, dove la proiezione elimina i duplicati, ne dà 3. Algebra e SQL del corso non sono equivalenti. L'esempio è realistico: quando una proiezione scarta la chiave del join (quiscienziato), i duplicati sono da attendersi.
Query 2: scienziati di Fisica che hanno definito formule di Matematica
Idea. Due condizioni sul "campo", che sono due cose diverse: il campo principale dello scienziato (SCIENZIATO.campo) e il campo della formula (FORMULA.campo). Entrambi sono identificatori di CAMPO_STUDIO, non nomi: per confrontarli con 'Fisica' e 'Matematica' bisogna passare per CAMPO_STUDIO due volte (due ruoli diversi, quindi due alias).
Soluzione del corso (algebra).
SELECT s.id, s.nome, s.cognome
FROM scienziato AS s
INNER JOIN r3 AS r ON s.id = r.scienziato
INNER JOIN formula AS f ON r.formula = f.id
WHERE f.campo = 'Matematica' AND s.campo = 'Fisica';Errori nella soluzione del corso. (1)
campoè un identificatore (chiave esterna versoCAMPO_STUDIO.id), non il nome del campo:f.campo = 'Matematica'confronta un intero con una stringa e non trova nulla (provato: 0 righe). Bisogna fare il join conCAMPO_STUDIOe filtrare sunome. (2) Come nella query 1, manca ilDISTINCT: uno scienziato che ha definito due formule di Matematica comparirebbe due volte. (3) La rinomina è corretta, ma serve anche a evitare il conflitto tra gliiddiFORMULAe diSCIENZIATO.
Soluzione corretta (SQL).
SELECT DISTINCT s.id, s.nome, s.cognome
FROM scienziato AS s
INNER JOIN campo_studio AS cs ON cs.id = s.campo -- campo principale dello scienziato
INNER JOIN r3 AS r ON r.scienziato = s.id
INNER JOIN formula AS f ON f.id = r.formula
INNER JOIN campo_studio AS cf ON cf.id = f.campo -- campo della formula
WHERE cs.nome = 'Fisica' AND cf.nome = 'Matematica';campo_studio compare due volte, con alias cs e cf perché ha due ruoli. Risultato: Daniel Bernoulli (Fisica; ha definito la formula 6, di Matematica) e Isaac Newton (Fisica; ha definito il binomio di Newton, di Matematica). Jacob Bernoulli e Gauss hanno la Matematica come campo principale: esclusi; Curie ha la Chimica.
Algebra corretta. Si seleziona sul nome del campo e si porta l'id con un join, con le rinomine per gli id:
Provato con un interprete di algebra: stesso risultato dell'SQL (Daniel Bernoulli e Newton).
Query 3: lo scienziato che ha definito il maggior numero di formule
Idea. Il pattern del massimo: (1) numero di formule per scienziato, (2) il massimo di questi numeri, (3) gli scienziati con quel valore.
Algebra.
La soluzione del corso scrive l'ultimo passo come , con MAX_C una relazione: è una forma abbreviata del join.
SQL del corso (con vista):
CREATE VIEW Conteggio_F AS
SELECT scienziato, COUNT(*) AS conteggio
FROM r3
GROUP BY scienziato;
SELECT scienziato, conteggio
FROM Conteggio_F
WHERE conteggio = (SELECT MAX(conteggio) FROM Conteggio_F);Risultato sui dati: scienziato 3 (Newton), con 3 formule (1, 7, 9); gli altri ne hanno 2 (Daniel, Jacob, Gauss) o 1 (Curie). La vista evita di ripetere la tabella derivata. La query restituisce tutti gli scienziati a pari merito: se Gauss avesse 3 formule, comparirebbero entrambi (se ne avesse 4 vincerebbe lui, provato).
Per avere nome e cognome basta unire con SCIENZIATO:
SELECT s.id, s.nome, s.cognome, COUNT(*) AS formule
FROM scienziato AS s INNER JOIN r3 ON r3.scienziato = s.id
GROUP BY s.id, s.nome, s.cognome
HAVING COUNT(*) = (SELECT MAX(n) FROM (SELECT COUNT(*) AS n FROM r3 GROUP BY scienziato) AS t);(Si raggruppa per s.id: si evitano omonimi fusi in un gruppo.) Uno scienziato senza formule non compare in , ma per il massimo non conta. Nell'ER del corso ogni formula ha almeno uno scienziato; il viceversa non vale.
Domanda 2 (per la lode): modifiche per rispondere più in fretta
- Query 3: serve contare le righe di per scienziato e prendere il massimo. Un attributo derivato
n_formuleinSCIENZIATO(aggiornato con un trigger a ogni inserimento o cancellazione in ) rende la query una selezione: più veloce in lettura, ma ridondanza da mantenere coerente. Alternativa senza ridondanza: indice su e una vista materializzata dei conteggi. - Query 2: il campo di studio è un'entità, quindi servono due join con
CAMPO_STUDIOsolo per confrontare i nomi. Se il nome del campo fosse l'identificatore (chiave naturale),SCIENZIATO.campoeFORMULA.campoconterrebbero già 'Fisica' e 'Matematica' e i due join sparirebbero; il prezzo è una chiave testuale ripetuta (spazio) e la difficoltà di rinominare un campo (aggiornamenti a cascata). - Query 1: un indice su
SCIENZIATO(cognome)e su rende veloce la ricerca per cognome; nessuna modifica di schema.
Errori nel materiale del corso (riassunto)
- Query 1: SQL senza
DISTINCT(formula con due Bernoulli compare due volte);nomedella formula assente dall'algebra ma presente nell'SQL. - Query 2: confronto di
campo(un identificatore) con una stringa: manca il join conCAMPO_STUDIO; mancaDISTINCT. - Query 3: con una relazione al posto del join (abbreviazione); il resto è corretto.
Versione ripasso
Schema: PUBBLICAZIONE(doi, titolo, sommario, anno), CAMPO_STUDIO(id, nome), FORMULA(id, nome, descrizione, espressione, anno, campo), SCIENZIATO(id, nome, cognome, campo), (pubblicazione, formula), (formula, scienziato). Teoria: SQL - interrogazioni, join e aggregazioniUn'interrogazione SQL ha almeno SELECT e FROM; le altre clausole (WHERE, GROUP BY, HAVING, ORDER BY) sono opzionali e HAVING richiede GROUP BY. Ordine logico di valutazione: FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY. SELECT corrisponde a π (ma senza DISTINCT non elimina i duplicati), WHERE a σ, gli alias ad AS/ρ, i join a ⋈ (INNER, LEFT, RIGHT, FULL). WHERE seleziona le righe prima del raggruppamento, HAVING seleziona i gruppi dopo. Le funzioni COUNT, SUM, AVG, MIN, MAX ignorano i NULL (COUNT(*) conta le righe, DISTINCT toglie i duplicati dentro la funzione); con un aggregato o con GROUP BY nella SELECT possono comparire solo colonne di raggruppamento o aggregati. LIKE usa % (qualsiasi sequenza) e _ (un carattere). I confronti con NULL non sono veri: serve IS NULL. Un filtro sulla tabella di destra di un LEFT JOIN va nella clausola ON, non in WHERE, altrimenti il join diventa interno. Con interi COUNT(a)/COUNT(b) è una divisione intera: serve CAST.SQL - interrogazioni, join e aggregazioni →, SQL - query nidificate, operatori insiemistici e visteUna sottoquery è una SELECT tra parentesi dentro un'altra: nella FROM (tabella derivata, con alias obbligatorio in PostgreSQL) oppure nella WHERE, come valore scalare con =, <, ..., come insieme con IN / NOT IN, ANY, ALL, oppure con EXISTS / NOT EXISTS. Una sottoquery correlata usa colonne della query esterna e va rivalutata per ogni riga. Le funzioni di aggregazione non si possono usare in WHERE: il massimo si ottiene con una sottoquery scalare (WHERE n = (SELECT MAX(n) ...)), con una vista o una CTE. NOT IN con una sottoquery che contiene NULL non restituisce mai righe: meglio NOT EXISTS, EXCEPT o LEFT JOIN ... IS NULL. "Per tutti" (divisione) = doppio NOT EXISTS o HAVING COUNT(DISTINCT ...) = numero totale. Gli operatori insiemistici UNION, INTERSECT, EXCEPT richiedono query compatibili e di default eliminano i duplicati (ALL li mantiene). Una vista è una tabella virtuale definita da una query (CREATE VIEW, DROP VIEW): semplifica le query, riusa sottoquery, nasconde i dati; la vista materializzata invece memorizza il risultato.SQL - query nidificate, operatori insiemistici e viste →.
- Formule attribuite a un Bernoulli. Catena di due join:
FORMULASCIENZIATOfiltrato percognome = 'Bernoulli'. Risultato: formule 2, 3 e 6. La formula 6 ha due Bernoulli, quindiDISTINCTè indispensabile: senza, le righe sono 4; in algebra la elimina il duplicato.
SELECT DISTINCT f.id, f.nome, f.descrizione, f.espressione, f.anno
FROM formula AS f INNER JOIN r3 AS r ON f.id = r.formula
INNER JOIN scienziato AS s ON r.scienziato = s.id
WHERE s.cognome = 'Bernoulli';- Scienziati di Fisica che hanno definito formule di Matematica. In algebra: si selezionano i campi per nome con e , si porta l'id del campo con un join e si rinomina per evitare gli omonimi; poi si collega a e si proietta su
id,nomeecognome.campoè un identificatore diCAMPO_STUDIO, non un nome:f.campo = 'Matematica'confronta un intero con una stringa e dà zero righe. Serve un join conCAMPO_STUDIOdue volte (aliascsper lo scienziato,cfper la formula), con filtro sunome. Risultato: Daniel Bernoulli e Isaac Newton. Jacob Bernoulli e Gauss hanno la Matematica come campo principale, quindi sono esclusi.
SELECT DISTINCT s.id, s.nome, s.cognome
FROM scienziato AS s
INNER JOIN campo_studio AS cs ON cs.id = s.campo
INNER JOIN r3 AS r ON r.scienziato = s.id
INNER JOIN formula AS f ON f.id = r.formula
INNER JOIN campo_studio AS cf ON cf.id = f.campo
WHERE cs.nome = 'Fisica' AND cf.nome = 'Matematica';- Scienziato con più formule. Pattern del massimo: conteggio di per scienziato, massimo dei conteggi, confronto. Risultato: Newton con 3 formule (1, 7, 9). Se due scienziati pareggiano, la query li restituisce entrambi. Con la vista
Conteggio_F(conteggio per scienziato) la query èWHERE conteggio = (SELECT MAX(conteggio) FROM Conteggio_F). Per avere anche nome e cognome si raggruppa pers.id.
Errori del corso
- Query 1: SQL senza
DISTINCT, quindi la formula 6 compare due volte. - Query 2: confronto di
campo(un id) con una stringa: manca il join conCAMPO_STUDIO, e mancaDISTINCT. - Query 3: con una relazione al posto del join: è un'abbreviazione.
Domanda per la lode: attributo derivato n_formule in SCIENZIATO (con trigger) o vista materializzata per la query 3; indici su SCIENZIATO(cognome) e su ; per la query 2 il nome del campo come chiave eviterebbe i due join, a costo di una chiave testuale ripetuta.
Errori tipici
- Dimenticare
DISTINCTcon join che moltiplicano le righe. - Confrontare un id con un nome.
- Usare una sola copia di
CAMPO_STUDIOper due ruoli diversi. - con una relazione al posto di un valore.