Lezione 5 — CREATE TABLE e i Vincoli Base in MySQL: Progettare Database Solidi

Impara a creare tabelle in MySQL utilizzando l'istruzione CREATE TABLE e scopri come utilizzare i vincoli (constraints) per garantire l'integrità dei tuoi dati.

Introduzione alla creazione delle tabelle

Benvenuti alla quinta lezione del nostro corso "Impara MySQL in 45 lezioni". Dopo aver imparato a creare e gestire i database a livello strutturale, è arrivato il momento di scendere nel dettaglio e definire dove i dati verranno effettivamente memorizzati: le tabelle.

In un database relazionale come MySQL, una tabella è una collezione di dati organizzata in righe (record) e colonne (campi). Immaginate la tabella come un foglio di calcolo di Excel, ma con una differenza fondamentale: mentre in Excel potete scrivere qualsiasi cosa in qualsiasi cella, in MySQL ogni colonna deve avere un tipo di dato predefinito e deve rispettare determinate regole. Questa rigidità è ciò che rende i database relazionali così potenti, sicuri e veloci nel recupero delle informazioni.

In questa lezione esploreremo l'istruzione CREATE TABLE, analizzeremo i tipi di dato più comuni e approfondiremo i cosiddetti vincoli (constraints), ovvero le regole che impediscono l'inserimento di dati errati o incoerenti.

L'istruzione CREATE TABLE: Sintassi e Logica

L'istruzione CREATE TABLE è il comando DDL (Data Definition Language) utilizzato per creare una nuova tabella all'interno di un database. La sintassi di base richiede il nome della tabella e una lista di definizioni per ogni colonna.

La struttura fondamentale

Ogni colonna definita all'interno di CREATE TABLE deve includere almeno tre elementi:

  1. Il nome della colonna: un identificativo univoco (es. id, nome_utente, email).
  2. Il tipo di dato: definisce che genere di informazione può essere salvata (es. INT per numeri interi, VARCHAR per testo).
  3. Le opzioni/vincoli: definiscono se il campo può essere vuoto, se deve essere unico o se è la chiave primaria.

Vediamo un esempio concreto. Supponiamo di voler creare una tabella per gestire gli utenti di un sito web.

CREATE TABLE utenti (
    id INT NOT NULL AUTO_INCREMENT,
    nome VARCHAR(50) NOT NULL,
    cognome VARCHAR(50),
    email VARCHAR(100) NOT NULL,
    data_registrazione DATETIME DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id)
);

Spiegazione del codice

Analizziamo cosa succede in questo blocco di codice:

  • id INT NOT NULL AUTO_INCREMENT: Creiamo una colonna chiamata id di tipo intero. NOT NULL significa che non può essere lasciata vuota. AUTO_INCREMENT è una funzionalità di MySQL che assegna automaticamente un numero progressivo (1, 2, 3...) a ogni nuovo record, eliminando la necessità di gestirlo manualmente.
  • nome VARCHAR(50) NOT NULL: Il tipo VARCHAR è usato per stringhe di lunghezza variabile. Il numero 50 indica la lunghezza massima consentita. In questo caso, il nome è obbligatorio.
  • cognome VARCHAR(50): Qui non abbiamo specificato NOT NULL, quindi il cognome è opzionale (può contenere un valore NULL).
  • email VARCHAR(100) NOT NULL: L'email è obbligatoria e ha un limite di 100 caratteri.
  • data_registrazione DATETIME DEFAULT CURRENT_TIMESTAMP: Usiamo DATETIME per salvare data e ora. L'opzione DEFAULT CURRENT_TIMESTAMP dice a MySQL: "se non inserisco una data, usa l'ora esatta di adesso".
  • PRIMARY KEY (id): Definiamo l'id come chiave primaria, l'identificatore unico della tabella.

I Tipi di Dato Fondamentali

Prima di procedere con i vincoli, è essenziale capire quale tipo di dato scegliere. Scegliere il tipo sbagliato può portare a sprechi di memoria o a errori di overflow.

Tipi Numerici

  • INT: Il più comune per i numeri interi. Ideale per ID, conteggi e quantità.
  • DECIMAL(p, s): Fondamentale per i prezzi e i dati finanziari. A differenza dei numeri a virgola mobile, il DECIMAL è esatto. p è la precisione totale (cifre totali) e s è la scala (cifre dopo la virgola). Esempio: DECIMAL(10, 2) può memorizzare fino a 99.999.999,99.

Tipi di Testo

  • VARCHAR(n): Testo di lunghezza variabile. È il più efficiente per nomi, indirizzi o email.
  • TEXT: Usato per contenuti molto lunghi, come il corpo di un articolo di un blog o una descrizione prodotto. Non richiede una lunghezza specifica.
  • CHAR(n): Testo di lunghezza fissa. Se definisci CHAR(2) per una sigla di stato (es. 'IT', 'US'), MySQL occuperà sempre lo spazio di 2 caratteri.

Tipi di Data e Ora

  • DATE: Formato YYYY-MM-DD.
  • DATETIME: Formato YYYY-MM-DD HH:MM:SS.
  • TIMESTAMP: Simile a DATETIME, ma viene utilizzato spesso per tracciare quando un record è stato creato o modificato, poiché è legato al fuso orario del server.

I Vincoli (Constraints): Garantire l'Integrità dei Dati

I vincoli sono regole applicate alle colonne per assicurare che i dati inseriti siano validi. Senza vincoli, il database diventerebbe rapidamente un "deposito di spazzatura" con dati duplicati o incompleti.

1. NOT NULL

Il vincolo NOT NULL impedisce che una colonna accetti valori NULL. In SQL, NULL non significa zero o stringa vuota, ma "assenza di valore". Se un campo è critico per l'applicazione (come l'email di un utente), deve essere NOT NULL.

2. UNIQUE

Il vincolo UNIQUE assicura che tutti i valori in una colonna siano diversi tra loro. Ad esempio, due utenti non possono avere la stessa email.

CREATE TABLE prodotti (
    id INT AUTO_INCREMENT PRIMARY KEY,
    codice_sku VARCHAR(20) UNIQUE NOT NULL,
    nome_prodotto VARCHAR(100) NOT NULL,
    prezzo DECIMAL(10, 2)
);

In questo esempio, se provassimo a inserire due prodotti con lo stesso codice_sku, MySQL restituirebbe un errore, proteggendo l'integrità del catalogo.

3. PRIMARY KEY (Chiave Primaria)

La chiave primaria è il vincolo più importante. È una combinazione di NOT NULL e UNIQUE. Ogni tabella dovrebbe avere una chiave primaria perché permette di identificare univocamente ogni singola riga. Senza di essa, non potresti aggiornare o eliminare un record specifico senza rischiare di colpire altri record identici.

4. DEFAULT

Il vincolo DEFAULT assegna un valore predefinito se non ne viene fornito uno durante l'inserimento. È utilissimo per stati iniziali (es. stato_account VARCHAR(20) DEFAULT 'attivo').

5. CHECK (MySQL 8.0+)

Il vincolo CHECK permette di definire una condizione logica che il valore deve soddisfare per essere accettato.

CREATE TABLE ordini (
    id INT AUTO_INCREMENT PRIMARY KEY,
    quantita INT CHECK (quantita > 0),
    totale DECIMAL(10, 2) CHECK (totale >= 0)
);

Grazie al CHECK, è impossibile inserire un ordine con una quantità negativa, evitando errori logici gravi nel software di e-commerce.

Esempi Pratici: Progettare un Mini-Sistema

Per mettere in pratica quanto appreso, immaginiamo di dover progettare il database per un sistema di gestione di una biblioteca. Avremo bisogno di due tabelle: libri e autori.

Tabella Autori

L'autore è l'entità principale. Ogni autore ha un nome, un cognome e una data di nascita.

CREATE TABLE autori (
    autore_id INT AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(50) NOT NULL,
    cognome VARCHAR(50) NOT NULL,
    nazionalita VARCHAR(30) DEFAULT 'Sconosciuta'
);

Tabella Libri

Il libro deve avere un titolo, un anno di pubblicazione e un riferimento all'autore. In questa lezione non vedremo ancora le "Foreign Keys" (le vedremo nella prossima lezione!), ma definiremo comunque la struttura base.

CREATE TABLE libri (
    libro_id INT AUTO_INCREMENT PRIMARY KEY,
    titolo VARCHAR(255) NOT NULL,
    isbn VARCHAR(13) UNIQUE NOT NULL,
    anno_pubblicazione INT CHECK (anno_pubblicazione > 0 AND anno_pubblicazione <= 2025),
    prezzo DECIMAL(5, 2) NOT NULL
);

Analisi delle scelte progettuali

  • ISBN UNIQUE: L'ISBN è un codice internazionale univoco per ogni libro. Usare UNIQUE evita che lo stesso libro venga registrato due volte.
  • CHECK sull'anno: Abbiamo limitato l'anno di pubblicazione per evitare che un operatore inserisca per errore l'anno "20250" o un numero negativo.
  • DECIMAL(5, 2): Per il prezzo di un libro, 5 cifre totali (di cui 2 decimali) sono sufficienti (fino a 999.99).

Errori Comuni e FAQ

Perché non usare sempre VARCHAR(255)?

Molti principianti tendono a impostare tutte le colonne di testo a VARCHAR(255). Sebbene MySQL sia efficiente, definire lunghezze realistiche aiuta a documentare il database e a prevenire l'inserimento di dati anomali (es. un nome di 200 caratteri potrebbe essere un segno di un attacco o di un errore di input).

Differenza tra NULL e stringa vuota ('')

Questo è un punto cruciale. NULL significa "non sappiamo il valore". Una stringa vuota '' è un valore noto, ovvero una stringa che non contiene caratteri. Se un campo è NOT NULL, non puoi inserire NULL, ma puoi inserire una stringa vuota.

Posso cambiare i vincoli dopo aver creato la tabella?

Sì, utilizzando l'istruzione ALTER TABLE. Tuttavia, è molto più semplice e sicuro progettare bene la tabella all'inizio. Se provi a aggiungere un vincolo NOT NULL a una colonna che contiene già dei valori NULL, MySQL restituirà un errore.

Prossimi Passi

Ora che sai come creare tabelle e proteggere i tuoi dati con i vincoli base, hai gettato le fondamenta del tuo database. Tuttavia, le tabelle non vivono isolate: la vera potenza di SQL risiede nelle relazioni.

Nella prossima lezione parleremo delle Foreign Keys (Chiavi Esterne). Impareremo come collegare la tabella libri alla tabella autori, in modo che ogni libro sia associato a un autore esistente, evitando che nel sistema esistano "libri orfani".

Esercizio consigliato: Prova a creare una tabella chiamata prodotti_magazzino con le seguenti specifiche:

  • Un ID autoincrementale come chiave primaria.
  • Un nome prodotto obbligatorio.
  • Un prezzo che non può essere negativo.
  • Una quantità di scorta che deve essere almeno 0.
  • Una data di inserimento automatica.

Buono studio e ci vediamo alla Lezione 6!