La relazione "molti-a-molti" è quando un record in una tabella può essere collegato a più record in un'altra tabella, e viceversa. Per esempio: - Uno studente (dalla tabella students) può essere iscritto a più corsi (dalla tabella courses). - Un corso può essere frequentato da più studenti.
Il problema è che gestire direttamente questa relazione è scomodo. Ecco perché ci viene in aiuto una tabella intermedia che tiene traccia di questi collegamenti.
Esempio dalla vita reale
Immagina di avere una tabella degli studenti e una dei corsi. Se provi ad aggiungere in ogni tabella una colonna per tutti i dati collegati, viene fuori un casino:
- Nella tabella
studentsdovresti salvare la lista di tutti i corsi a cui è iscritto uno studente. Ma come la salvi? Separati da virgole? In un array? Sarebbe un incubo per le query. - Nella tabella
coursesdovresti salvare la lista degli studenti, e qui proprio ti viene il mal di testa.
Quindi la soluzione giusta è creare una terza tabella che tiene le relazioni tra studenti e corsi.
La tabella intermedia: la nostra salvezza!
La tabella intermedia (a volte chiamata tabella di relazione) risolve tutto. Contiene due riferimenti esterni:
- Chiave esterna verso la tabella
students. - Chiave esterna verso la tabella
courses.
Ogni record in questa tabella crea un collegamento tra uno studente specifico e un corso specifico.
Creare le tabelle per la relazione "molti-a-molti"
Facciamo un po' di pratica! Ecco come possiamo creare le tabelle per collegare studenti e corsi:
Passo 1: Creare la tabella students
Questa è la nostra tabella degli studenti. Qui salviamo gli identificatori unici degli studenti e i loro nomi.
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
student_id— è l'identificatore unico dello studente (auto-incrementato, grazieSERIAL!).name— il nome dello studente.
Passo 2: Creare la tabella courses
Ora creiamo la tabella dei corsi. Qui salviamo gli identificatori unici dei corsi e i loro titoli.
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
course_id— identificatore unico del corso.title— titolo del corso.
Passo 3: Creare la tabella intermedia enrollments
Ora creiamo la nostra magica tabella di collegamento. Contiene due colonne, ognuna è una chiave esterna che punta alle rispettive tabelle.
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id),
course_id INT REFERENCES courses(course_id),
PRIMARY KEY (student_id, course_id)
);
Vediamo la struttura:
student_id— chiave esterna che punta astudent_idnella tabellastudents.course_id— chiave esterna che punta acourse_idnella tabellacourses.PRIMARY KEY (student_id, course_id)— la chiave primaria è la combinazione delle due chiavi esterne. Così ogni collegamento è unico.
Inserimento dati
Aggiungiamo un po' di dati per vedere come funziona tutto.
Passo 1: Aggiungere studenti
INSERT INTO students (name) VALUES
('Alice'),
('Bob'),
('Charlie');
Risultato:
| student_id | name |
|---|---|
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
Passo 2: Aggiungere corsi
INSERT INTO courses (title) VALUES
('Mathematics'),
('History'),
('Biology');
Risultato:
| course_id | title |
|---|---|
| 1 | Mathematics |
| 2 | History |
| 3 | Biology |
Passo 3: Aggiungere record in enrollments
Ora iscriviamo gli studenti ai corsi. Per esempio:
Aliceè iscritta aMathematicseHistory.Bobè iscritto solo aBiology.Charlieè iscritto a tutti e tre i corsi.
INSERT INTO enrollments (student_id, course_id) VALUES
(1, 1), -- Alice su Mathematics
(1, 2), -- Alice su History
(2, 3), -- Bob su Biology
(3, 1), -- Charlie su Mathematics
(3, 2), -- Charlie su History
(3, 3); -- Charlie su Biology
Risultato:
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
Query per la relazione "molti-a-molti"
Ora che abbiamo i dati, è il momento di sfruttarli!
Come trovare tutti i corsi a cui è iscritto uno studente?
Per esempio, per sapere a quali corsi è iscritta Alice (ID = 1), fai questa query:
SELECT c.title
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
WHERE e.student_id = 1;
Risultato:
| title |
|---|
| Mathematics |
| History |
Come trovare tutti gli studenti iscritti a un certo corso?
Supponiamo di voler sapere chi è iscritto al corso Mathematics (ID = 1):
SELECT s.name
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
WHERE e.course_id = 1;
Risultato:
| name |
|---|
| Alice |
| Charlie |
Come trovare studenti e i loro corsi?
Per avere la panoramica completa di chi è iscritto a cosa, fai questa query:
SELECT s.name AS student, c.title AS course
FROM students s
JOIN enrollments e ON s.student_id = e.student_id
JOIN courses c ON e.course_id = c.course_id;
Risultato:
| student | course |
|---|---|
| Alice | Mathematics |
| Alice | History |
| Bob | Biology |
| Charlie | Mathematics |
| Charlie | History |
| Charlie | Biology |
La tabella enrollments rende il nostro schema super flessibile — possiamo aggiungere o togliere collegamenti tra studenti e corsi senza toccare le tabelle principali. Grazie alle query JOIN trovi subito quello che ti serve, tipo chi è iscritto a quale corso. E le chiavi esterne controllano automaticamente che non ci siano errori — per esempio, che nessuno iscriva uno studente a un corso che non esiste.
Errori tipici nelle relazioni "molti-a-molti"
Mancanza di vincolo di unicità: Se non metti il PRIMARY KEY, rischi di inserire lo stesso collegamento più volte.
Violazione dell'integrità dei dati: Se provi a inserire un record con uno student_id o course_id che non esiste, ottieni un errore.
Ordine sbagliato nell'eliminazione dei dati: Se elimini prima un corso da courses, i record in enrollments restano "orfani". Per evitarlo usa ON DELETE CASCADE nella definizione delle chiavi esterne.
GO TO FULL VERSION