Codice dei programmi nella directory:
///File: TutorialFormeNormali2026-CON-SOLUZIONE-ESERCIZI.html
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Tutorial Normalizzazione Database - 1NF, 2NF, 3NF - F. Sacco - Maggio 2026</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 2cm;
line-height: 1.4;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 5px; }
h2 { color: #2980b9; margin-top: 35px; border-left: 5px solid #3498db; padding-left: 15px; }
h3 { color: #16a085; margin-top: 25px; }
table {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
background: #f9f9f9;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
th, td {
border: 1px solid #aaa;
padding: 10px;
text-align: left;
vertical-align: top;
}
th { background: #ecf0f1; font-weight: bold; }
.wrong {
border-left: 5px solid #e74c3c;
padding-left: 15px;
background: #fceaea;
margin: 15px 0;
}
.correct {
border-left: 5px solid #2ecc71;
padding-left: 15px;
background: #e8f8f5;
margin: 15px 0;
}
.image-container {
text-align: center;
margin: 25px 0;
background: #fef9e7;
padding: 15px;
border-radius: 8px;
border: 1px solid #f39c12;
}
.image-container img {
max-width: 100%;
height: auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.image-container .caption {
font-style: italic;
margin-top: 10px;
color: #7f8c8d;
font-size: 0.9em;
}
.rule-box {
background: #e8f8f5;
padding: 15px;
border-radius: 8px;
margin: 20px 0;
border-left: 5px solid #1abc9c;
}
.summary-table {
background: #ecf0f1;
}
.salto-pagina {
page-break-before: always;
}
hr {
margin: 40px 0;
border: 1px solid #bdc3c7;
}
</style>
</head>
<body>
<h1>📘 Tutorial completo: Normalizzazione nei database</h1>
<p>La normalizzazione elimina ridondanze e anomalie di inserimento, cancellazione e aggiornamento. Vediamo le <strong>tre forme normali (1NF, 2NF, 3NF)</strong> con esempi reali e diagrammi illustrativi.</p>
<!-- ============================================= -->
<!-- PRIMA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔹 1. Prima Forma Normale (1NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 1NF:</strong>
<ul>
<li>Ogni colonna deve contenere valori <strong>atomici</strong> (indivisibili).</li>
<li>Non sono ammesse ripetizioni di gruppi di colonne (es. Telefono1, Telefono2).</li>
<li>Ogni riga deve essere univocamente identificabile (chiave primaria).</li>
</ul>
</div>
<h3>❌ Esempio che VIOLA la 1NF</h3>
<p>Tabella "Studenti" con numeri di telefono multipli nella stessa cella e attributi ripetuti.</p>
<table>
<tr><th>ID Studente</th><th>Nome</th><th>Telefoni</th><th>Telefono2</th></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331123456, 331654321</td><td>NULL</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392111222</td><td>392333444</td></tr>
</table>
<p><strong>⚠️ Problemi:</strong> I telefoni non sono atomici (nel primo caso ci sono due numeri separati da virgola). Colonne Telefono1/Telefono2 creano ridondanza e difficoltà di ricerca.</p>
<h3>✅ Esempio CORRETTO in 1NF</h3>
<p>Suddivido i telefoni su righe distinte e creo una chiave primaria composta (ID_Studente, Telefono).</p>
<table>
<tr><th>ID Studente</th><th>Nome</th><th>Telefono</th></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331123456</td></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331654321</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392111222</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392333444</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora ogni attributo è atomico e non esistono gruppi ripetuti. Ogni riga è univoca grazie alla coppia (ID_Studente, Telefono).
</div>
<!-- Immagine 1: Diagramma 1NF -->
<div class="image-container">
<img src="immagine1.jpg" alt="Diagramma 1NF - da valori multipli ad atomici" onerror="this.style.display='none'">
<div class="caption">Figura 1: Trasformazione dalla violazione della 1NF alla corretta 1NF</div>
</div>
<!-- ============================================= -->
<!-- SECONDA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔸 2. Seconda Forma Normale (2NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 2NF:</strong>
<ul>
<li>La tabella deve essere già in 1NF.</li>
<li><strong>Nessuna dipendenza parziale</strong> dalla chiave primaria: ogni colonna non chiave deve dipendere dall'<em>intera</em> chiave primaria (non solo da una parte).</li>
</ul>
<em>Nota: la 2NF ha senso solo con chiavi primarie composte.</em>
</div>
<h3>❌ Esempio che VIOLA la 2NF</h3>
<p>Tabella "IscrizioniCorsi" con chiave primaria composta (ID_Studente, ID_Corso).</p>
<table>
<tr><th>ID_Studente</th><th>ID_Corso</th><th>Nome_Studente</th><th>Nome_Corso</th><th>Data_Iscrizione</th></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">101</td><td>Marco</td><td>Matematica</td><td>2025-01-10</td></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">102</td><td>Marco</td><td>Fisica</td><td>2025-01-12</td></tr>
<tr><td style="text-align: center">2</td><td style="text-align: center">101</td><td>Laura</td><td>Matematica</td><td>2025-01-11</td></tr>
</table>
<p><strong>⚠️ Problema:</strong> "Nome_Studente" dipende solo da ID_Studente (non da ID_Corso), e "Nome_Corso" dipende solo da ID_Corso. Sono <strong>dipendenze parziali</strong> → violazione 2NF. Ridondanza: "Marco" e "Matematica" vengono ripetuti più volte.</p>
<h3>✅ Soluzione: scomposizione in 2NF</h3>
<p>Creo tre tabelle separate, eliminando ogni dipendenza parziale:</p>
<p><strong>📋 Tabella STUDENTI</strong></p>
<table>
<tr><th>ID_Studente (PK)</th><th>Nome_Studente</th><tr>
<tr><td style="text-align: center">1</td><td>Marco</td></tr>
<tr><td style="text-align: center">2</td><td>Laura</td></tr>
</table>
<p><strong>📋 Tabella CORSI</strong></p>
<table>
<tr><th>ID_Corso (PK)</th><th>Nome_Corso</th></tr>
<tr><td style="text-align: center">101</td><td>Matematica</td></tr>
<tr><td style="text-align: center">102</td><td>Fisica</td></tr>
</table>
<p><strong>📋 Tabella ISCRIZIONI (tabella ponte)</strong></p>
<table>
<tr><th>ID_Studente (FK)</th><th>ID_Corso (FK)</th><th>Data_Iscrizione</th></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">101</td><td>2025-01-10</td></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">102</td><td>2025-01-12</td></tr>
<tr><td style="text-align: center">2</td><td style="text-align: center">101</td><td>2025-01-11</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora ogni attributo non chiave dipende dall'intera chiave primaria della propria tabella. Nessuna ridondanza.
</div>
<!-- Immagine 2: Diagramma 2NF -->
<div class="image-container">
<img src="immagine2.jpg" alt="Diagramma 2NF - eliminazione dipendenze parziali" onerror="this.style.display='none'">
<div class="caption">Figura 2: Scomposizione per eliminare le dipendenze parziali dalla chiave composta</div>
</div>
<!-- ============================================= -->
<!-- TERZA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔹 3. Terza Forma Normale (3NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 3NF:</strong>
<ul>
<li>La tabella deve essere già in 2NF.</li>
<li><strong>Nessuna dipendenza transitiva</strong>: un attributo non chiave non può dipendere da un altro attributo non chiave.</li>
</ul>
</div>
<h3>❌ Esempio che VIOLA la 3NF</h3>
<p>Tabella "Impiegati" in 2NF ma con dipendenza transitiva.</p>
<table>
<tr><th>ID_Impiegato</th><th>Nome</th><th>ID_Ufficio</th><th>Città_Ufficio</th></tr>
<tr><td style="text-align: center">10</td><td>Anna</td><td>U1</td><td>Roma</td></tr>
<tr><td style="text-align: center">11</td><td>Luigi</td><td>U2</td><td>Milano</td></tr>
<tr><td style="text-align: center">12</td><td>Sofia</td><td>U1</td><td>Roma</td></tr>
</table>
<p><strong>⚠️ Problema:</strong> "Città_Ufficio" dipende da "ID_Ufficio" (attributo non chiave), non direttamente da ID_Impiegato. Esiste una <strong>dipendenza transitiva</strong>:<br>
<code>ID_Impiegato → ID_Ufficio → Città_Ufficio</code>.<br>
Ridondanza: "Roma" ripetuta per ogni impiegato dello stesso ufficio.</p>
<p><strong>Anomalie:</strong> se un ufficio cambia città, bisogna aggiornare tutte le righe degli impiegati (rischio inconsistenza).</p>
<h3>✅ Soluzione: scomposizione in 3NF</h3>
<p>Separare la dipendenza transitiva in una tabella dedicata agli uffici.</p>
<p><strong>📋 Tabella IMPIEGATI (3NF)</strong></p>
<table>
<tr><th>ID_Impiegato (PK)</th><th>Nome</th><th>ID_Ufficio (FK)</th></tr>
<tr><td style="text-align: center">10</td><td>Anna</td><td>U1</td></tr>
<tr><td style="text-align: center">11</td><td>Luigi</td><td>U2</td></tr>
<tr><td style="text-align: center">12</td><td>Sofia</td><td>U1</td></tr>
</table>
<p><strong>📋 Tabella UFFICI</strong></p>
<table>
<tr><th>ID_Ufficio (PK)</th><th>Città_Ufficio</th></tr>
<tr><td style="text-align: center">U1</td><td>Roma</td></tr>
<tr><td style="text-align: center">U2</td><td>Milano</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora non esistono dipendenze transitive: la città dell'ufficio si trova solo nella tabella Uffici. Se un ufficio cambia città, si modifica un solo record.
</div>
<!-- Immagine 3: Diagramma 3NF -->
<div class="image-container">
<img src="immagine3.jpg" alt="Diagramma 3NF - eliminazione dipendenze transitive" onerror="this.style.display='none'">
<div class="caption">Figura 3: Eliminazione della dipendenza transitiva separando la tabella Uffici</div>
</div>
<!-- Immagine 4: Diagramma riepilogativo -->
<div class="image-container">
<img src="immagine4.jpg" alt="Diagramma riepilogativo delle 3 forme normali" onerror="this.style.display='none'">
<div class="caption">Figura 4: Riepilogo visivo dei tre passaggi di normalizzazione</div>
</div>
<!-- ============================================= -->
<!-- RIEPILOGO FINALE -->
<!-- ============================================= -->
<h2>📊 Riepilogo comparativo</h2>
<table class="summary-table">
<tr><th>Forma normale</th><th>Regola chiave</th><th>Problema risolto</th><th>Quando applicare</th></tr>
<tr><td style="text-align: center"><strong>1NF</strong></td><td>Attributi atomici + chiave univoca</td><td>Dati multivalore, gruppi ripetuti</td><td>Sempre</td></tr>
<tr><td style="text-align: center"><strong>2NF</strong></td><td>Nessuna dipendenza parziale</td><td>Ridondanza in chiave composta</td><td>Con chiavi primarie composte</td></tr>
<tr><td style="text-align: center"><strong>3NF</strong></td><td>Nessuna dipendenza transitiva</td><td>Ridondanza tra attributi non chiave</td><td>Quasi sempre (fino a 3NF è standard)</td></tr>
</table>
<h2>🎯 Conclusione:</h2>
<ul>
<li>La normalizzazione fino alla <strong>3NF</strong> è sufficiente per la maggior parte dei database relazionali.</li>
<li>Riduce la ridondanza, migliora l'integrità dei dati e semplifica la manutenzione.</li>
<li>Forme superiori (BCNF, 4NF, 5NF) esistono ma sono usate raramente nella pratica quotidiana.</li>
</ul>
<hr>
<!-- ============================================= -->
<!-- ESERCIZI DI NORMALIZZAZIONE -->
<!-- ============================================= -->
<h2>📝 ESERCIZI: Normalizza tu stesso!</h2>
<p>Di seguito trovi 4 esercizi di difficoltà crescente. Prova a normalizzare i dati fino alla 3NF, poi confronta con la soluzione.</p>
<hr>
<!-- ESERCIZIO 1 -->
<h3>✏️ Esercizio 1 - Raggiungi la 1NF</h3>
<p><strong>Consegna:</strong> La tabella "Libri" memorizza informazioni sui libri e i loro autori. Normalizza in 1NF.</p>
<h4>Tabella di partenza (viola 1NF):</h4>
<table>
<tr><th>ID_Libro</th><th>Titolo</th><th>Autori</th><th>Anno</th></tr>
<tr><td style="text-align: center">1</td><td>Database Facile</td><td>Rossi, Bianchi</td><td style="text-align: center">2020</td></tr>
<tr><td style="text-align: center">2</td><td>SQL Avanzato</td><td>Verdi</td><td style="text-align: center">2021</td></tr>
<tr><td style="text-align: center">3</td><td>NoSQL Guida</td><td>Neri, Rossi, Gialli</td><td style="text-align: center">2022</td></tr>
</table>
<details>
<summary><strong>🔍 Mostra soluzione Esercizio 1 (1NF)</strong></summary>
<div class="correct" style="margin-top: 15px;">
<p><strong>Soluzione:</strong> Scomporre gli autori su righe separate. Chiave primaria composta (ID_Libro, Autore).</p>
<table>
<tr><th>ID_Libro</th><th>Titolo</th><th>Autore</th><th>Anno</th></tr>
<tr><td style="text-align: center">1</td><td>Database Facile</td><td>Rossi</td><td style="text-align: center">2020</td></tr>
<tr><td style="text-align: center">1</td><td>Database Facile</td><td>Bianchi</td><td style="text-align: center">2020</td></tr>
<tr><td style="text-align: center">2</td><td>SQL Avanzato</td><td>Verdi</td><td style="text-align: center">2021</td></tr>
<tr><td style="text-align: center">3</td><td>NoSQL Guida</td><td>Neri</td><td style="text-align: center">2022</td></tr>
<tr><td style="text-align: center">3</td><td>NoSQL Guida</td><td>Rossi</td><td style="text-align: center">2022</td></tr>
<tr><td style="text-align: center">3</td><td>NoSQL Guida</td><td>Gialli</td><td style="text-align: center">2022</td></tr>
</table>
<p>✅ Ora ogni cella contiene un valore atomico.</p>
</div>
</details>
<hr>
<!-- ESERCIZIO 2 -->
<h3>✏️ Esercizio 2 - Raggiungi la 2NF</h3>
<p><strong>Consegna:</strong> La tabella "OrdiniClienti" ha chiave primaria composta (ID_Ordine, ID_Prodotto). Normalizza in 2NF.</p>
<h4>Tabella di partenza (in 1NF ma viola 2NF):</h4>
<table>
<tr><th>ID_Ordine</th><th>ID_Prodotto</th><th>Data_Ordine</th><th>Nome_Cliente</th><th>Prodotto_Nome</th><th>Quantità</th></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P1</td><td>2025-01-10</td><td>Marco</td><td>Mouse</td><td style="text-align: center">2</td></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P2</td><td>2025-01-10</td><td>Marco</td><td>Tastiera</td><td style="text-align: center">1</td></tr>
<tr><td style="text-align: center">102</td><td style="text-align: center">P1</td><td>2025-01-11</td><td>Laura</td><td>Mouse</td><td style="text-align: center">3</td></tr>
</table>
<details>
<summary><strong>🔍 Mostra soluzione Esercizio 2 (2NF)</strong></summary>
<div class="correct" style="margin-top: 15px;">
<p><strong>Soluzione:</strong> Identificare le dipendenze parziali: Data_Ordine e Nome_Cliente dipendono solo da ID_Ordine. Prodotto_Nome dipende solo da ID_Prodotto. Creare 3 tabelle.</p>
<p><strong>Tabella ORDINI:</strong></p>
<table>
<tr><th>ID_Ordine (PK)</th><th>Data_Ordine</th><th>Nome_Cliente</th></tr>
<tr><td style="text-align: center">101</td><td>2025-01-10</td><td>Marco</td></tr>
<tr><td style="text-align: center">102</td><td>2025-01-11</td><td>Laura</td></tr>
</table>
<p><strong>Tabella PRODOTTI:</strong></p>
<table>
<tr><th>ID_Prodotto (PK)</th><th>Prodotto_Nome</th></tr>
<tr><td style="text-align: center">P1</td><td>Mouse</td></tr>
<tr><td style="text-align: center">P2</td><td>Tastiera</td></tr>
</table>
<p><strong>Tabella DETTAGLI_ORDINE (tabella ponte):</strong></p>
<table>
<tr><th>ID_Ordine (FK)</th><th>ID_Prodotto (FK)</th><th>Quantità</th></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P1</td><td style="text-align: center">2</td></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P2</td><td style="text-align: center">1</td></tr>
<tr><td style="text-align: center">102</td><td style="text-align: center">P1</td><td style="text-align: center">3</td></tr>
</table>
<p>✅ Eliminate tutte le dipendenze parziali.</p>
</div>
</details>
<hr>
<!-- ESERCIZIO 3 -->
<h3>✏️ Esercizio 3 - Raggiungi la 3NF</h3>
<p><strong>Consegna:</strong> La tabella "ProgettiDipendenti" è già in 2NF, ma ha una dipendenza transitiva. Normalizza in 3NF.</p>
<h4>Tabella di partenza (in 2NF, viola 3NF):</h4>
<table>
<tr><th>ID_Dipendente</th><th>Nome_Dipendente</th><th>ID_Progetto</th><th>Nome_Progetto</th><th>Reparto</th><th>Edificio_Reparto</th></tr>
<tr><td style="text-align: center">D1</td><td>Anna</td><td style="text-align: center">PRJ1</td><td>AI</td><td>R&D</td><td>Edificio A</td></tr>
<tr><td style="text-align: center">D2</td><td>Luigi</td><td style="text-align: center">PRJ1</td><td>AI</td><td>R&D</td><td>Edificio A</td></tr>
<tr><td style="text-align: center">D3</td><td>Sofia</td><td style="text-align: center">PRJ2</td><td>Cloud</td><td>Infrastrutture</td><td>Edificio B</td></tr>
</table>
<p><strong>Suggerimento:</strong> Individua la dipendenza transitiva: ID_Dipendente → ? → ?</p>
<details>
<summary><strong>🔍 Mostra soluzione Esercizio 3 (3NF)</strong></summary>
<div class="correct" style="margin-top: 15px;">
<p><strong>Soluzione:</strong> Dipendenza transitiva: ID_Dipendente → Reparto → Edificio_Reparto. Inoltre Nome_Progetto dipende da ID_Progetto (altro attributo non chiave).</p>
<p><strong>Tabella DIPENDENTI_PROGETTI (relazione pura):</strong></p>
<table>
<tr><th>ID_Dipendente</th><th>ID_Progetto</th></tr>
<tr><td style="text-align: center">D1</td><td style="text-align: center">PRJ1</td></tr>
<tr><td style="text-align: center">D2</td><td style="text-align: center">PRJ1</td></tr>
<tr><td style="text-align: center">D3</td><td style="text-align: center">PRJ2</td></tr>
</table>
<p><strong>Tabella DIPENDENTI:</strong></p>
<table>
<tr><th>ID_Dipendente (PK)</th><th>Nome_Dipendente</th><th>Reparto</th></tr>
<tr><td style="text-align: center">D1</td><td>Anna</td><td>R&D</td></tr>
<tr><td style="text-align: center">D2</td><td>Luigi</td><td>R&D</td></tr>
<tr><td style="text-align: center">D3</td><td>Sofia</td><td>Infrastrutture</td></tr>
</table>
<p><strong>Tabella REPARTI:</strong></p>
<table>
<tr><th>Reparto (PK)</th><th>Edificio_Reparto</th></tr>
<tr><td>R&D</td><td>Edificio A</td></tr>
<tr><td>Infrastrutture</td><td>Edificio B</td></tr>
</table>
<p><strong>Tabella PROGETTI:</strong></p>
<table>
<tr><th>ID_Progetto (PK)</th><th>Nome_Progetto</th></tr>
<tr><td style="text-align: center">PRJ1</td><td>AI</td></tr>
<tr><td style="text-align: center">PRJ2</td><td>Cloud</td></tr>
</table>
<p>✅ Eliminate tutte le dipendenze transitive.</p>
</div>
</details>
<hr>
<!-- ESERCIZIO 4 - COMPLETO -->
<h3>✏️ Esercizio 4 - Sfida completa (1NF → 2NF → 3NF)</h3>
<p><strong>Consegna:</strong> La tabella "CorsiStudentiDocenti" riassume corsi, studenti e docenti. Normalizza completamente fino alla 3NF.</p>
<h4>Tabella di partenza (non normalizzata):</h4>
<table>
<tr><th>ID_Corso</th><th>Nome_Corso</th><th>Studenti (lista)</th><th>ID_Docente</th><th>Nome_Docente</th><th>Specializzazione_Docente</th></tr>
<tr><td style="text-align: center">CS101</td><td>Database</td><td>Marco, Laura</td><td style="text-align: center">D10</td><td>Rossi</td><td>SQL, NoSQL</td></tr>
<tr><td style="text-align: center">CS102</td><td>Python</td><td>Marco, Sofia, Luigi</td><td style="text-align: center">D20</td><td>Bianchi</td><td>Python, Django</td></tr>
<tr><td style="text-align: center">CS101</td><td>Database</td><td>Sofia</td><td style="text-align: center">D10</td><td>Rossi</td><td>SQL, NoSQL</td></tr>
</table>
<details>
<summary><strong>🔍 Mostra soluzione Esercizio 4 (3NF completa)</strong></summary>
<div class="correct" style="margin-top: 15px;">
<p><strong>Soluzione passo passo:</strong></p>
<ol>
<li><strong>1NF:</strong> Scomporre studenti e specializzazioni in righe atomiche.</li>
<li><strong>2NF:</strong> Identificare dipendenze parziali (Nome_Corso dipende solo da ID_Corso).</li>
<li><strong>3NF:</strong> Eliminare dipendenze transitive (Specializzazione_Docente dipende da ID_Docente).</li>
</ol>
<p><strong>Tabella CORSI:</strong></p>
<table>
<tr><th>ID_Corso (PK)</th><th>Nome_Corso</th></tr>
<tr><td style="text-align: center">CS101</td><td>Database</td></tr>
<tr><td style="text-align: center">CS102</td><td>Python</td></tr>
</table>
<p><strong>Tabella DOCENTI:</strong></p>
<table>
<tr><th>ID_Docente (PK)</th><th>Nome_Docente</th></tr>
<tr><td style="text-align: center">D10</td><td>Rossi</td></tr>
<tr><td style="text-align: center">D20</td><td>Bianchi</td></tr>
</table>
<p><strong>Tabella SPECIALIZZAZIONI_DOCENTE (1NF per le specializzazioni):</strong></p>
<table>
<tr><th>ID_Docente (FK)</th><th>Specializzazione</th></tr>
<tr><td style="text-align: center">D10</td><td>SQL</td></tr>
<tr><td style="text-align: center">D10</td><td>NoSQL</td></tr>
<tr><td style="text-align: center">D20</td><td>Python</td></tr>
<tr><td style="text-align: center">D20</td><td>Django</td></tr>
</table>
<p><strong>Tabella STUDENTI (dall'estrazione degli studenti unici):</strong></p>
<table>
<tr><th>ID_Studente (generato)</th><th>Nome_Studente</th></tr>
<tr><td style="text-align: center">S1</td><td>Marco</td></tr>
<tr><td style="text-align: center">S2</td><td>Laura</td></tr>
<tr><td style="text-align: center">S3</td><td>Sofia</td></tr>
<tr><td style="text-align: center">S4</td><td>Luigi</td></tr>
</table>
<p><strong>Tabella ISCRIZIONI_CORSI (relazione studenti-corsi):</strong></p>
<table>
<tr><th>ID_Studente (FK)</th><th>ID_Corso (FK)</th></tr>
<tr><td style="text-align: center">S1</td><td style="text-align: center">CS101</td></tr>
<tr><td style="text-align: center">S2</td><td style="text-align: center">CS101</td></tr>
<tr><td style="text-align: center">S1</td><td style="text-align: center">CS102</td></tr>
<tr><td style="text-align: center">S3</td><td style="text-align: center">CS102</td></tr>
<tr><td style="text-align: center">S4</td><td style="text-align: center">CS102</td></tr>
<tr><td style="text-align: center">S3</td><td style="text-align: center">CS101</td></tr>
</table>
<p><strong>Tabella ASSEGNAZIONE_DOCENTI (un corso può avere un docente):</strong></p>
<table>
<tr><th>ID_Corso (FK)</th><th>ID_Docente (FK)</th></tr>
<tr><td style="text-align: center">CS101</td><td style="text-align: center">D10</td></tr>
<tr><td style="text-align: center">CS102</td><td style="text-align: center">D20</td></tr>
</table>
<p>✅ Database completamente normalizzato in 3NF, senza ridondanze né anomalie.</p>
</div>
</details>
<hr>
<!-- RIEPILOGO ESERCIZI -->
<h3>📌 Autovalutazione</h3>
<p>Dopo aver completato gli esercizi, verifica di aver compreso:</p>
<ul>
<li>✅ Riconoscere valori non atomici (violazione 1NF)</li>
<li>✅ Identificare dipendenze parziali in chiavi composte (violazione 2NF)</li>
<li>✅ Scovare dipendenze transitive tra attributi non chiave (violazione 3NF)</li>
<li>✅ Applicare la scomposizione in sottotabelle senza perdita di informazioni</li>
</ul>
<div class="rule-box">
<strong>💡 Suggerimento finale:</strong> Per verificare se hai normalizzato correttamente, controlla che:<br>
- Ogni tabella rappresenti un <strong>unico concetto</strong> (entità).<br>
- Tutti gli attributi non chiave descrivano <strong>completamente</strong> la chiave primaria (e solo quella).<br>
- Non ci siano <strong>catene di dipendenze</strong> tra attributi non chiave.
</div>
<hr>
<p><em>📚 Esercizi tratti da casi reali - Prova a inventare nuovi esempi dalla tua esperienza per allenarti ulteriormente!</em></p>
</body>
</html>
///(Fine file: TutorialFormeNormali2026-CON-SOLUZIONE-ESERCIZI.html)
///File: TutorialFormeNormali2026.html
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Tutorial Normalizzazione Database - 1NF, 2NF, 3NF - F. Sacco - Maggio 2026</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 2cm;
line-height: 1.4;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
}
h1 { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 5px; }
h2 { color: #2980b9; margin-top: 35px; border-left: 5px solid #3498db; padding-left: 15px; }
h3 { color: #16a085; margin-top: 25px; }
table {
border-collapse: collapse;
width: 100%;
margin: 20px 0;
background: #f9f9f9;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
th, td {
border: 1px solid #aaa;
padding: 10px;
text-align: left;
vertical-align: top;
}
th { background: #ecf0f1; font-weight: bold; }
.wrong {
border-left: 5px solid #e74c3c;
padding-left: 15px;
background: #fceaea;
margin: 15px 0;
}
.correct {
border-left: 5px solid #2ecc71;
padding-left: 15px;
background: #e8f8f5;
margin: 15px 0;
}
.image-container {
text-align: center;
margin: 25px 0;
background: #fef9e7;
padding: 15px;
border-radius: 8px;
border: 1px solid #f39c12;
}
.image-container img {
max-width: 100%;
height: auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.image-container .caption {
font-style: italic;
margin-top: 10px;
color: #7f8c8d;
font-size: 0.9em;
}
.rule-box {
background: #e8f8f5;
padding: 15px;
border-radius: 8px;
margin: 20px 0;
border-left: 5px solid #1abc9c;
}
.summary-table {
background: #ecf0f1;
}
.salto-pagina {
page-break-before: always;
}
hr {
margin: 40px 0;
border: 1px solid #bdc3c7;
}
</style>
</head>
<body>
<h1>📘 Tutorial completo: Normalizzazione nei database</h1>
<p>La normalizzazione elimina ridondanze e anomalie di inserimento, cancellazione e aggiornamento. Vediamo le <strong>tre forme normali (1NF, 2NF, 3NF)</strong> con esempi reali e diagrammi illustrativi.</p>
<!-- ============================================= -->
<!-- PRIMA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔹 1. Prima Forma Normale (1NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 1NF:</strong>
<ul>
<li>Ogni colonna deve contenere valori <strong>atomici</strong> (indivisibili).</li>
<li>Non sono ammesse ripetizioni di gruppi di colonne (es. Telefono1, Telefono2).</li>
<li>Ogni riga deve essere univocamente identificabile (chiave primaria).</li>
</ul>
</div>
<h3>❌ Esempio che VIOLA la 1NF</h3>
<p>Tabella "Studenti" con numeri di telefono multipli nella stessa cella e attributi ripetuti.</p>
<table>
<tr><th>ID Studente</th><th>Nome</th><th>Telefoni</th><th>Telefono2</th></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331123456, 331654321</td><td>NULL</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392111222</td><td>392333444</td></tr>
</table>
<p><strong>⚠️ Problemi:</strong> I telefoni non sono atomici (nel primo caso ci sono due numeri separati da virgola). Colonne Telefono1/Telefono2 creano ridondanza e difficoltà di ricerca.</p>
<h3>✅ Esempio CORRETTO in 1NF</h3>
<p>Suddivido i telefoni su righe distinte e creo una chiave primaria composta (ID_Studente, Telefono).</p>
<table>
<tr><th>ID Studente</th><th>Nome</th><th>Telefono</th></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331123456</td></tr>
<tr><td style="text-align: center">1</td><td>Marco Rossi</td><td>331654321</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392111222</td></tr>
<tr><td style="text-align: center">2</td><td>Laura Bianchi</td><td>392333444</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora ogni attributo è atomico e non esistono gruppi ripetuti. Ogni riga è univoca grazie alla coppia (ID_Studente, Telefono).
</div>
<!-- Immagine 1: Diagramma 1NF -->
<div class="image-container">
<img src="immagine1.jpg" alt="Diagramma 1NF - da valori multipli ad atomici" onerror="this.style.display='none'">
<div class="caption">Figura 1: Trasformazione dalla violazione della 1NF alla corretta 1NF</div>
</div>
<!-- ============================================= -->
<!-- SECONDA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔸 2. Seconda Forma Normale (2NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 2NF:</strong>
<ul>
<li>La tabella deve essere già in 1NF.</li>
<li><strong>Nessuna dipendenza parziale</strong> dalla chiave primaria: ogni colonna non chiave deve dipendere dall'<em>intera</em> chiave primaria (non solo da una parte).</li>
</ul>
<em>Nota: la 2NF ha senso solo con chiavi primarie composte.</em>
</div>
<h3>❌ Esempio che VIOLA la 2NF</h3>
<p>Tabella "IscrizioniCorsi" con chiave primaria composta (ID_Studente, ID_Corso).</p>
<table>
<tr><th>ID_Studente</th><th>ID_Corso</th><th>Nome_Studente</th><th>Nome_Corso</th><th>Data_Iscrizione</th></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">101</td><td>Marco</td><td>Matematica</td><td>2025-01-10</td></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">102</td><td>Marco</td><td>Fisica</td><td>2025-01-12</td></tr>
<tr><td style="text-align: center">2</td><td style="text-align: center">101</td><td>Laura</td><td>Matematica</td><td>2025-01-11</td></tr>
</table>
<p><strong>⚠️ Problema:</strong> "Nome_Studente" dipende solo da ID_Studente (non da ID_Corso), e "Nome_Corso" dipende solo da ID_Corso. Sono <strong>dipendenze parziali</strong> → violazione 2NF. Ridondanza: "Marco" e "Matematica" vengono ripetuti più volte.</p>
<h3>✅ Soluzione: scomposizione in 2NF</h3>
<p>Creo tre tabelle separate, eliminando ogni dipendenza parziale:</p>
<p><strong>📋 Tabella STUDENTI</strong></p>
<table>
<tr><th>ID_Studente (PK)</th><th>Nome_Studente</th><tr>
<tr><td style="text-align: center">1</td><td>Marco</td></tr>
<tr><td style="text-align: center">2</td><td>Laura</td></tr>
</table>
<p><strong>📋 Tabella CORSI</strong></p>
<table>
<tr><th>ID_Corso (PK)</th><th>Nome_Corso</th></tr>
<tr><td style="text-align: center">101</td><td>Matematica</td></tr>
<tr><td style="text-align: center">102</td><td>Fisica</td></tr>
</table>
<p><strong>📋 Tabella ISCRIZIONI (tabella ponte)</strong></p>
<table>
<tr><th>ID_Studente (FK)</th><th>ID_Corso (FK)</th><th>Data_Iscrizione</th></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">101</td><td>2025-01-10</td></tr>
<tr><td style="text-align: center">1</td><td style="text-align: center">102</td><td>2025-01-12</td></tr>
<tr><td style="text-align: center">2</td><td style="text-align: center">101</td><td>2025-01-11</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora ogni attributo non chiave dipende dall'intera chiave primaria della propria tabella. Nessuna ridondanza.
</div>
<!-- Immagine 2: Diagramma 2NF -->
<div class="image-container">
<img src="immagine2.jpg" alt="Diagramma 2NF - eliminazione dipendenze parziali" onerror="this.style.display='none'">
<div class="caption">Figura 2: Scomposizione per eliminare le dipendenze parziali dalla chiave composta</div>
</div>
<!-- ============================================= -->
<!-- TERZA FORMA NORMALE -->
<!-- ============================================= -->
<h2>🔹 3. Terza Forma Normale (3NF)</h2>
<div class="rule-box">
<strong>📌 Regole della 3NF:</strong>
<ul>
<li>La tabella deve essere già in 2NF.</li>
<li><strong>Nessuna dipendenza transitiva</strong>: un attributo non chiave non può dipendere da un altro attributo non chiave.</li>
</ul>
</div>
<h3>❌ Esempio che VIOLA la 3NF</h3>
<p>Tabella "Impiegati" in 2NF ma con dipendenza transitiva.</p>
<table>
<tr><th>ID_Impiegato</th><th>Nome</th><th>ID_Ufficio</th><th>Città_Ufficio</th></tr>
<tr><td style="text-align: center">10</td><td>Anna</td><td>U1</td><td>Roma</td></tr>
<tr><td style="text-align: center">11</td><td>Luigi</td><td>U2</td><td>Milano</td></tr>
<tr><td style="text-align: center">12</td><td>Sofia</td><td>U1</td><td>Roma</td></tr>
</table>
<p><strong>⚠️ Problema:</strong> "Città_Ufficio" dipende da "ID_Ufficio" (attributo non chiave), non direttamente da ID_Impiegato. Esiste una <strong>dipendenza transitiva</strong>:<br>
<code>ID_Impiegato → ID_Ufficio → Città_Ufficio</code>.<br>
Ridondanza: "Roma" ripetuta per ogni impiegato dello stesso ufficio.</p>
<p><strong>Anomalie:</strong> se un ufficio cambia città, bisogna aggiornare tutte le righe degli impiegati (rischio inconsistenza).</p>
<h3>✅ Soluzione: scomposizione in 3NF</h3>
<p>Separare la dipendenza transitiva in una tabella dedicata agli uffici.</p>
<p><strong>📋 Tabella IMPIEGATI (3NF)</strong></p>
<table>
<tr><th>ID_Impiegato (PK)</th><th>Nome</th><th>ID_Ufficio (FK)</th></tr>
<tr><td style="text-align: center">10</td><td>Anna</td><td>U1</td></tr>
<tr><td style="text-align: center">11</td><td>Luigi</td><td>U2</td></tr>
<tr><td style="text-align: center">12</td><td>Sofia</td><td>U1</td></tr>
</table>
<p><strong>📋 Tabella UFFICI</strong></p>
<table>
<tr><th>ID_Ufficio (PK)</th><th>Città_Ufficio</th></tr>
<tr><td style="text-align: center">U1</td><td>Roma</td></tr>
<tr><td style="text-align: center">U2</td><td>Milano</td></tr>
</table>
<div class="correct">
<strong>✅ Risultato:</strong> Ora non esistono dipendenze transitive: la città dell'ufficio si trova solo nella tabella Uffici. Se un ufficio cambia città, si modifica un solo record.
</div>
<!-- Immagine 3: Diagramma 3NF -->
<div class="image-container">
<img src="immagine3.jpg" alt="Diagramma 3NF - eliminazione dipendenze transitive" onerror="this.style.display='none'">
<div class="caption">Figura 3: Eliminazione della dipendenza transitiva separando la tabella Uffici</div>
</div>
<!-- Immagine 4: Diagramma riepilogativo -->
<div class="image-container">
<img src="immagine4.jpg" alt="Diagramma riepilogativo delle 3 forme normali" onerror="this.style.display='none'">
<div class="caption">Figura 4: Riepilogo visivo dei tre passaggi di normalizzazione</div>
</div>
<!-- ============================================= -->
<!-- RIEPILOGO FINALE -->
<!-- ============================================= -->
<h2>📊 Riepilogo comparativo</h2>
<table class="summary-table">
<tr><th>Forma normale</th><th>Regola chiave</th><th>Problema risolto</th><th>Quando applicare</th></tr>
<tr><td style="text-align: center"><strong>1NF</strong></td><td>Attributi atomici + chiave univoca</td><td>Dati multivalore, gruppi ripetuti</td><td>Sempre</td></tr>
<tr><td style="text-align: center"><strong>2NF</strong></td><td>Nessuna dipendenza parziale</td><td>Ridondanza in chiave composta</td><td>Con chiavi primarie composte</td></tr>
<tr><td style="text-align: center"><strong>3NF</strong></td><td>Nessuna dipendenza transitiva</td><td>Ridondanza tra attributi non chiave</td><td>Quasi sempre (fino a 3NF è standard)</td></tr>
</table>
<h2>🎯 Conclusione:</h2>
<ul>
<li>La normalizzazione fino alla <strong>3NF</strong> è sufficiente per la maggior parte dei database relazionali.</li>
<li>Riduce la ridondanza, migliora l'integrità dei dati e semplifica la manutenzione.</li>
<li>Forme superiori (BCNF, 4NF, 5NF) esistono ma sono usate raramente nella pratica quotidiana.</li>
</ul>
<!-- ============================================= -->
<!-- ESERCIZI DI NORMALIZZAZIONE -->
<!-- ============================================= -->
<h2>📝 ESERCIZI: Normalizza tu stesso!</h2>
<p>Di seguito trovi 4 esercizi di difficoltà crescente. Normalizza i dati fino alla 3NF su un foglio a parte. Le soluzioni possono essere fornite dal docente o verificate successivamente.</p>
<hr>
<!-- ESERCIZIO 1 -->
<h3>✏️ Esercizio 1 - Raggiungi la 1NF</h3>
<p><strong>Consegna:</strong> La tabella "Libri" memorizza informazioni sui libri e i loro autori. Normalizza in 1NF.</p>
<h4>Tabella di partenza (viola 1NF):</h4>
<table>
<tr><th>ID_Libro</th><th>Titolo</th><th>Autori</th><th>Anno</th></tr>
<tr><td style="text-align: center">1</td><td>Database Facile</td><td>Rossi, Bianchi</td><td style="text-align: center">2020</td></tr>
<tr><td style="text-align: center">2</td><td>SQL Avanzato</td><td>Verdi</td><td style="text-align: center">2021</td></tr>
<tr><td style="text-align: center">3</td><td>NoSQL Guida</td><td>Neri, Rossi, Gialli</td><td style="text-align: center">2022</td></tr>
</table>
<hr>
<!-- ESERCIZIO 2 -->
<h3>✏️ Esercizio 2 - Raggiungi la 2NF</h3>
<p><strong>Consegna:</strong> La tabella "OrdiniClienti" ha chiave primaria composta (ID_Ordine, ID_Prodotto). Normalizza in 2NF.</p>
<h4>Tabella di partenza (in 1NF ma viola 2NF):</h4>
<table>
<tr><th>ID_Ordine</th><th>ID_Prodotto</th><th>Data_Ordine</th><th>Nome_Cliente</th><th>Prodotto_Nome</th><th>Quantità</th></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P1</td><td>2025-01-10</td><td>Marco</td><td>Mouse</td><td style="text-align: center">2</td></tr>
<tr><td style="text-align: center">101</td><td style="text-align: center">P2</td><td>2025-01-10</td><td>Marco</td><td>Tastiera</td><td style="text-align: center">1</td></tr>
<tr><td style="text-align: center">102</td><td style="text-align: center">P1</td><td>2025-01-11</td><td>Laura</td><td>Mouse</td><td style="text-align: center">3</td></tr>
</table>
<hr>
<!-- ESERCIZIO 3 -->
<h3>✏️ Esercizio 3 - Raggiungi la 3NF</h3>
<p><strong>Consegna:</strong> La tabella "ProgettiDipendenti" è già in 2NF, ma ha una dipendenza transitiva. Normalizza in 3NF.</p>
<h4>Tabella di partenza (in 2NF, viola 3NF):</h4>
<table>
<tr><th>ID_Dipendente</th><th>Nome_Dipendente</th><th>ID_Progetto</th><th>Nome_Progetto</th><th>Reparto</th><th>Edificio_Reparto</th></tr>
<tr><td style="text-align: center">D1</td><td>Anna</td><td style="text-align: center">PRJ1</td><td>AI</td><td>R&D</td><td>Edificio A</td></tr>
<tr><td style="text-align: center">D2</td><td>Luigi</td><td style="text-align: center">PRJ1</td><td>AI</td><td>R&D</td><td>Edificio A</td></tr>
<tr><td style="text-align: center">D3</td><td>Sofia</td><td style="text-align: center">PRJ2</td><td>Cloud</td><td>Infrastrutture</td><td>Edificio B</td></tr>
</table>
<p><strong>Suggerimento:</strong> Individua la dipendenza transitiva: ID_Dipendente → ? → ?</p>
<hr>
<!-- ESERCIZIO 4 - COMPLETO -->
<h3>✏️ Esercizio 4 - Sfida completa (1NF → 2NF → 3NF)</h3>
<p><strong>Consegna:</strong> La tabella "CorsiStudentiDocenti" riassume corsi, studenti e docenti. Normalizza completamente fino alla 3NF.</p>
<h4>Tabella di partenza (non normalizzata):</h4>
<table>
<tr><th>ID_Corso</th><th>Nome_Corso</th><th>Studenti (lista)</th><th>ID_Docente</th><th>Nome_Docente</th><th>Specializzazione_Docente</th></tr>
<tr><td style="text-align: center">CS101</td><td>Database</td><td>Marco, Laura</td><td style="text-align: center">D10</td><td>Rossi</td><td>SQL, NoSQL</td></tr>
<tr><td style="text-align: center">CS102</td><td>Python</td><td>Marco, Sofia, Luigi</td><td style="text-align: center">D20</td><td>Bianchi</td><td>Python, Django</td></tr>
<tr><td style="text-align: center">CS101</td><td>Database</td><td>Sofia</td><td style="text-align: center">D10</td><td>Rossi</td><td>SQL, NoSQL</td></tr>
</table>
<hr>
<!-- RIEPILOGO ESERCIZI -->
<h3>📌 Autovalutazione</h3>
<p>Dopo aver completato gli esercizi, verifica di aver compreso:</p>
<ul>
<li>✅ Riconoscere valori non atomici (violazione 1NF)</li>
<li>✅ Identificare dipendenze parziali in chiavi composte (violazione 2NF)</li>
<li>✅ Scovare dipendenze transitive tra attributi non chiave (violazione 3NF)</li>
<li>✅ Applicare la scomposizione in sottotabelle senza perdita di informazioni</li>
</ul>
<div class="rule-box">
<strong>💡 Suggerimento finale:</strong> Per verificare se hai normalizzato correttamente, controlla che:<br>
- Ogni tabella rappresenti un <strong>unico concetto</strong> (entità).<br>
- Tutti gli attributi non chiave descrivano <strong>completamente</strong> la chiave primaria (e solo quella).<br>
- Non ci siano <strong>catene di dipendenze</strong> tra attributi non chiave.
</div>
<hr>
<p><em>📚 Esercizi tratti da casi reali - Prova a inventare nuovi esempi dalla tua esperienza per allenarti ulteriormente.</em></p>
</body>
</html>
///(Fine file: TutorialFormeNormali2026.html)