Passa al contenuto principale

Capitolo 02

Identificare senza ambiguità: le chiavi

What’s in a name? That which we call a rose by any other name would smell as sweet.

William Shakespeare, Romeo e Giulietta (1597)

Nella lezione “Che cosa fa un DBMS al posto tuo” le tabelle del registro dei punti si collegavano attraverso i nomi, con un avviso: il collegamento per nome regge finché due studenti non hanno lo stesso nome. Anche le coppie delle associazioni di questo capitolo nominano gli studenti per nome, (Harry Potter, Grifondoro). In questa lezione due studenti con lo stesso nome arrivano davvero, e cerchiamo che cosa può distinguere un’occorrenza da tutte le altre. È il cerchio pieno che nei diagrammi della lezione “Entità e attributi” era rimasto in sospeso.

Due James Potter​

Finora il registro dei punti ha conservato gli studenti di un anno scolastico solo. Immaginiamo che Hogwarts voglia conservare nel database tutti gli studenti passati dalla scuola, anno dopo anno, senza cancellarne nessuno. In un archivio così due nomi uguali prima o poi arrivano, e nella famiglia di Harry sono già arrivati: James Potter, il padre di Harry, è stato studente di Grifondoro, e il figlio maggiore di Harry, che compare nell’epilogo dell’ultimo libro, si chiama James come il nonno.

Nella tabella studente del registro la colonna nome è la chiave della tabella: la colonna con cui il DBMS distingue una riga da tutte le altre, e con cui la colonna studente della tabella assegnazione indica a quale studente vanno i punti. Il blocco qui sotto registra i due James Potter, tutti e due al primo anno, a più di quarant’anni di distanza. L’ultimo libro della saga non dice in quale casa il Cappello Parlante metta il figlio: nel blocco lo mettiamo in Grifondoro, come il padre e il nonno. Le due istruzioni sono uguali, e si leggono come quella di Ginny nella lezione precedente. Prima di eseguire il blocco, prova a prevedere che cosa fa il DBMS.

INSERT INTO studente (nome, casa, anno)
VALUES ('James Potter', 'Grifondoro', 1);
INSERT INTO studente (nome, casa, anno)
VALUES ('James Potter', 'Grifondoro', 1);

Il DBMS, ligio alle regole come Percy Weasley, fa rispettare quella che ha ricevuto da chi ha creato la tabella: il nome distingue ogni studente. Per questo archivio la regola è falsa, e il risultato è che il database rifiuta uno studente vero. Questo è il primo modo in cui fallisce un identificatore sbagliato: con un errore, nel momento in cui qualcuno prova a scrivere.

Senza chiave​

La correzione più rapida è togliere la regola: senza chiave, la tabella studente accetta due righe con lo stesso nome. Il blocco qui sotto usa una versione del registro dei punti fatta così. La tabella studente non ha una chiave e contiene già i due James Potter; la tabella assegnazione contiene un’assegnazione in più, che immaginiamo data dalla professoressa McGonagall al padre di Harry: dieci punti a James Potter.

L’istruzione è la query del totale dei punti per casa della lezione sul DBMS, che adesso puoi leggere: la casa dello studente e la somma dei punti, dalle assegnazioni unite agli studenti con lo stesso nome, raggruppate per casa (GROUP BY), dalla casa con più punti a quella con meno. Nella lezione sul DBMS Grifondoro aveva tre punti, e l’assegnazione nuova ne aggiunge dieci. Prima di eseguire il blocco, prova a prevedere il totale di Grifondoro.

SELECT studente.casa, SUM(assegnazione.punti) AS totale
FROM assegnazione
JOIN studente ON studente.nome = assegnazione.studente
GROUP BY studente.casa
ORDER BY totale DESC;

La figura qui sotto ricostruisce l’unione.

Un’assegnazione unita a due studenti con lo stesso nomeL’assegnazione James Potter, 10, McGonagall e la tabella studente senza chiave, con due righe uguali: James Potter, Grifondoro, 1. Unendo le assegnazioni agli studenti con lo stesso nome, l’assegnazione si aggancia a tutte e due le righe e l’unione ne ha due. Nella somma di Grifondoro i dieci punti entrano due volte: 3 + 10 + 10 = 23, invece di 13.assegnazionestudentepuntiprofessoreJames Potter10McGonagallstudentenomecasaannoJames PotterGrifondoro1James PotterGrifondoro1assegnazione JOIN studentestudentepunticasaJames Potter10GrifondoroJames Potter10GrifondoroGrifondoro: 3 + 10 + 10 = 233 sono i punti degli altri studenti: con unJames solo, 13
Un’assegnazione unita a due studenti con lo stesso nomeL’assegnazione James Potter, 10, McGonagall e la tabella studente senza chiave, con due righe uguali: James Potter, Grifondoro, 1. Unendo le assegnazioni agli studenti con lo stesso nome, l’assegnazione si aggancia a tutte e due le righe e l’unione ne ha due. Nella somma di Grifondoro i dieci punti entrano due volte: 3 + 10 + 10 = 23, invece di 13.assegnazionestudentepuntiprofessoreJames Potter10McGonagallstudentenomecasaannoJames PotterGrifondoro1James PotterGrifondoro1assegnazione JOIN studentestudentepunticasaJames Potter10GrifondoroJames Potter10GrifondoroGrifondoro: 3 + 10 + 10 = 233 sono i punti degli altri studenti: con unJames solo, 13

Nella somma di Grifondoro i dieci punti entrano due volte: 23 invece di 13.

  1. Un’assegnazione a James Potter, e nella tabella studente, senza chiave, due righe con quel nome.
  2. Unendo per nome, l’assegnazione si aggancia a tutte e due le righe: l’unione ne ha due.
  3. Nella somma di Grifondoro i dieci punti entrano due volte: 23 invece di 13.

Questa volta il DBMS non segnala niente. La query è corretta, il DBMS la esegue sui dati che ha, e il risultato è sbagliato. Questo è il secondo modo di fallire, ed è il più pericoloso dei due: nessuno se ne accorge finché qualcuno non rifà il conto a mano. Senza un identificatore, il nome scritto nell’assegnazione non indica uno studente ma due, e il database non ha modo di sapere quale dei due abbia ricevuto i punti.

Che cosa distingue uno studente​

Per uscire dai due guasti serve un attributo, o un gruppo di attributi, con un valore diverso per ogni studente. Nel modello E/R si chiama identificatore; nelle tabelle, a partire dal capitolo 3, diventerà la chiave primaria.

La parola che conta nella definizione è “tutte”. Il nome da solo distingueva gli studenti del registro finché l’archivio conteneva un anno solo. Nome e anno di corso non bastano, perché i due James Potter erano tutti e due al primo anno. Nome e data di nascita distinguono i due James, nati a più di quarant’anni di distanza, ma non due omonimi nati lo stesso giorno, che sono rari e non impossibili. Anche la profezia su Voldemort aveva un problema di identificatore: indicava un bambino nato alla fine di luglio, e i bambini erano due, Harry e Neville. Ogni attributo aggiunto rende il caso più raro, e nessuno lo rende impossibile.

La strada che regge è un identificatore nato apposta per essere unico, come il numero di matricola che la segreteria assegna a ogni studente quando lo registra, senza mai riassegnarlo. Il numero di matricola non contiene nessuna informazione sullo studente, e proprio per questo non lo mettono in difficoltà né un omonimo né un cambio di cognome, né due gemelli che si scambiano il nome per far confondere la madre: a garantire che sia unico è chi lo assegna. Il DBMS può anche assegnarlo da solo: la colonna id della tabella assegnazione, il numero progressivo che il database dà a ogni riga, è un identificatore di questo tipo.

Un identificatore preso dal dominio non è sempre sbagliato. Il nome di una casa è un buon identificatore: le case sono quattro, i loro nomi sono diversi, e una regola del dominio dice che restano quelle: in mille anni nessuno ne ha fondata una quinta. Vale lo stesso criterio delle associazioni derivate della lezione “Le associazioni”: i dati di oggi non dimostrano niente, serve una regola del dominio che garantisca valori diversi anche domani. Per i nomi delle persone quella regola non esiste.

Identificatori composti​

A volte nessun attributo da solo distingue le occorrenze, e due attributi insieme sì. Immaginiamo di registrare i corsi di Hogwarts: Pozioni del primo anno, Pozioni del secondo anno, Incantesimi del primo anno, e così via, e supponiamo che per ogni materia e per ogni anno ci sia un corso solo. La materia da sola non distingue un corso, perché Pozioni si studia in più anni. L’anno da solo neppure, perché al primo anno si studiano molte materie. La coppia materia e anno invece è diversa per ogni corso, ed è un identificatore composto. Nessuno dei due attributi è superfluo: senza l’anno, i corsi di Pozioni avrebbero tutti lo stesso valore.

Lo studente identificato dalla matricola, il corso da materia e annoL'entità studente ha gli attributi matricola, nome e anno: matricola è l'identificatore, con il cerchio pieno. L'entità corso ha gli attributi materia e anno, che formano insieme un identificatore composto: un segmento attraversa i loro due steli e finisce in un cerchio pieno. Le due entità non sono collegate.studentematricolanomeannocorsomateriaanno

Nel diagramma l’identificatore semplice è il cerchio pieno in fondo allo stelo di matricola. L’identificatore composto è un segmento che attraversa gli steli di materia e di anno e finisce in un cerchio pieno; i cerchi dei due attributi restano vuoti, perché nessuno dei due, da solo, identifica un corso. Ogni entità ha il suo identificatore: senza, una coppia di un’associazione non indicherebbe un’occorrenza precisa.

Mettiti alla provaDomanda 1 / 3

Nel registro dei punti la tabella professore ha come chiave la colonna nome, che contiene il cognome del professore. Immaginiamo che a Hogwarts arrivi un secondo professore con un cognome già presente nella tabella. Che cosa succede quando la segreteria prova a registrarlo?

Scegli la risposta corretta