Tipi di Dati e Vincoli

Bentornato.
Nella lezione precedente hai imparato le azioni SQL di base:
SELECT;INSERT;UPDATE;DELETE.
Hai imparato a leggere dati.
Aggiungere dati.
Modificare dati.
Eliminare dati.
Molto potente.
Anche leggermente pericoloso.
Oggi impariamo come rendere le tabelle più sicure.
Perché un database non dovrebbe accettare tutto.
Se una colonna è per l’età, non dovrebbe accettare:
banana
Se un’email deve essere unica, PostgreSQL dovrebbe impedire a due utenti di avere la stessa email.
Se un nome è obbligatorio, PostgreSQL non dovrebbe permettere a persone misteriose e vuote di entrare nella tabella.
Qui entrano in gioco tipi di dati e vincoli.
I tipi di dati definiscono che tipo di dato può salvare una colonna.
I vincoli definiscono regole che i dati devono rispettare.
Insieme rendono il database più forte.
Come una guardia molto seria.
Ma con i punti e virgola.
Cosa Imparerai
In questa lezione imparerai:
- che cosa sono i tipi di dati;
- perché i tipi di dati contano;
- come usare
INTEGER; - come usare
VARCHAR; - come usare
TEXT; - come usare
BOOLEAN; - come usare
DATE; - come usare
NUMERIC; - che cosa sono i vincoli;
- come usare
NOT NULL; - come usare
UNIQUE; - come usare
DEFAULT; - come usare
CHECK; - come creare tabelle più sicure;
- come PostgreSQL protegge i tuoi dati dal caos.
Alla fine di questa lezione capirai come progettare tabelle che non accettano assurdità.
Questo è importante.
Perché i dati sbagliati sono come glitter.
Una volta entrati nel sistema, appaiono ovunque.
Per sempre.
Che Cosa Sono i Tipi di Dati?
Un tipo di dato dice a PostgreSQL che tipo di valore può salvare una colonna.
Esempio:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INTEGER
);
Qui:
name VARCHAR(100)
significa che la colonna name salva testo.
E:
age INTEGER
significa che la colonna age salva numeri interi.
Quindi PostgreSQL capisce:
name = testo
age = numero
Questo è utile perché PostgreSQL può rifiutare dati sbagliati.
Se provi a mettere testo in una colonna INTEGER, PostgreSQL si lamenterà.
Bene.
I database devono lamentarsi quando arriva assurdità.
Il silenzio è pericoloso.
Soprattutto nei database.
E nelle cucine.
Perché i Tipi di Dati Contano
Immagina questa tabella:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age TEXT
);
Tecnicamente qui age è testo.
Quindi PostgreSQL potrebbe permettere:
INSERT INTO users (name, age)
VALUES ('Anna', 'twenty two');
O persino:
INSERT INTO users (name, age)
VALUES ('Marco', 'banana');
Questo è male.
L’età dovrebbe essere un numero.
Meglio:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age INTEGER
);
Ora PostgreSQL si aspetta un numero per age.
Questo protegge i dati.
Una buona struttura impedisce ai dati stupidi di entrare nella tabella.
PostgreSQL sta praticamente dicendo:
Niente età banana oggi.
Eccellente.
Tipi di Dati Comuni in PostgreSQL
PostgreSQL ha molti tipi di dati.
Oggi impareremo quelli più utili per iniziare:
INTEGER;VARCHAR;TEXT;BOOLEAN;DATE;NUMERIC;SERIAL.
Sono abbastanza per molti progetti da principiante.
Più avanti potrai esplorare tipi più avanzati.
PostgreSQL ne ha tanti.
Perché PostgreSQL ha guardato i dati e ha detto:
Sì, posso organizzare tutto questo.
Molto ambizioso.
Molto utile.
INTEGER
INTEGER salva numeri interi.
Esempio:
age INTEGER
Valori buoni:
18
25
100
Valori cattivi:
hello
25.5
banana
Tabella di esempio:
CREATE TABLE players (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
score INTEGER
);
Inserisci dati:
INSERT INTO players (name, score)
VALUES ('Anna', 100);
Questo funziona.
Ma questo no:
INSERT INTO players (name, score)
VALUES ('Marco', 'very good');
Perché score si aspetta un numero.
PostgreSQL rifiuta.
Come dovrebbe.
Un database senza standard è solo un foglio Excel con ambizione.
VARCHAR
VARCHAR salva testo con una lunghezza massima.
Esempio:
name VARCHAR(100)
Questo significa:
Il nome può contenere fino a 100 caratteri.
Esempio:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category VARCHAR(50)
);
Va bene per campi testuali dove vuoi un limite ragionevole.
Per esempio:
- nomi;
- titoli;
- email;
- categorie;
- etichette brevi.
Se provi a inserire testo più lungo del limite, PostgreSQL lo rifiuterà.
Bene.
A volte i limiti sono sani.
Soprattutto per le colonne del database.
E forse per le porzioni di pizza.
TEXT
TEXT salva testo lungo.
Esempio:
description TEXT
Usa TEXT quando non hai bisogno di un limite rigido di caratteri.
Va bene per:
- descrizioni;
- contenuto di articoli;
- commenti;
- note;
- messaggi lunghi.
Esempio:
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
content TEXT
);
Qui:
title VARCHAR(150)
è limitato.
Ma:
content TEXT
può essere lungo.
Ha senso.
Un titolo non dovrebbe essere un romanzo.
Un campo contenuto può esserlo.
PostgreSQL è pratico.
Più o meno.
BOOLEAN
BOOLEAN salva valori true o false.
Esempio:
available BOOLEAN
Valori buoni:
true
false
Tabella di esempio:
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
completed BOOLEAN
);
Inserisci dati:
INSERT INTO tasks (title, completed)
VALUES ('Learn PostgreSQL', false);
Più tardi puoi aggiornarlo:
UPDATE tasks
SET completed = true
WHERE title = 'Learn PostgreSQL';
BOOLEAN è perfetto per valori sì/no:
- active;
- completed;
- available;
- published;
- verified.
Non salvarli come testo:
yes
no
maybe
sort of
Quella strada porta al caos.
Usa BOOLEAN.
Lascia che il database ti aiuti.
DATE
DATE salva date del calendario.
Esempio:
birth_date DATE
Inserisci una data così:
'1992-10-23'
PostgreSQL preferisce il formato:
YYYY-MM-DD
Tabella di esempio:
CREATE TABLE events (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
event_date DATE
);
Inserisci dati:
INSERT INTO events (title, event_date)
VALUES ('PostgreSQL Practice', '2026-05-03');
Le date dovrebbero essere date.
Non testo.
Non stringhe casuali.
Non “venerdì prossimo forse”.
PostgreSQL può lavorare bene con le date solo se le salvi come date.
Sorprendente.
Ma vero.
NUMERIC
NUMERIC salva numeri decimali esatti.
È utile per il denaro.
Esempio:
price NUMERIC(10, 2)
Questo significa:
Fino a 10 cifre totali, con 2 cifre dopo la virgola.
Valori di esempio:
49.99
100.00
1250.50
Tabella di esempio:
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
price NUMERIC(10, 2)
);
Inserisci dati:
INSERT INTO courses (title, price)
VALUES ('PostgreSQL Basics', 49.99);
Per i prezzi, NUMERIC di solito è meglio di INTEGER.
A meno che tu non salvi i centesimi come interi.
Anche quello è un approccio valido.
Ma per principianti, NUMERIC(10, 2) è facile da capire.
Il denaro merita precisione.
Soprattutto quando esce dal tuo conto.
SERIAL
SERIAL crea un intero auto-incrementale.
Esempio:
id SERIAL PRIMARY KEY
Questo significa che PostgreSQL genera automaticamente gli ID.
Esempio:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
Inserisci dati senza id:
INSERT INTO students (name)
VALUES ('Anna');
PostgreSQL dà automaticamente un ID ad Anna.
Poi un’altra riga riceve l’ID successivo.
E così via.
Molto utile.
Non gestire manualmente gli ID se PostgreSQL può farlo per te.
La vita è già complicata.
Lascia contare il database.
Che Cosa Sono i Vincoli?
I vincoli sono regole per i dati della tabella.
Dicono a PostgreSQL:
Questo valore è obbligatorio.
Questo valore deve essere unico.
Questo valore deve rispettare una condizione.
Questo valore ha un default.
Vincoli comuni:
PRIMARY KEY;NOT NULL;UNIQUE;DEFAULT;CHECK.
I vincoli rendono le tabelle più sicure.
Fermano i dati sbagliati prima che entrino nella tabella.
Pensa ai vincoli come regole della tabella.
Tipo:
Niente nomi vuoti.
Niente email duplicate.
Niente prezzi negativi.
Niente età impossibili.
Molto ragionevole.
PostgreSQL è severo.
Ma in questo caso, severo è buono.
NOT NULL
NOT NULL significa che una colonna è obbligatoria.
Esempio:
name VARCHAR(100) NOT NULL
Questo significa che ogni riga deve avere un nome.
Tabella di esempio:
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150)
);
Questo funziona:
INSERT INTO customers (name, email)
VALUES ('Anna', 'anna@example.com');
Questo non funziona:
INSERT INTO customers (email)
VALUES ('no-name@example.com');
Perché name è obbligatorio.
Bene.
Niente clienti misteriosi senza nome.
Questo non è un database di spie.
Probabilmente.
UNIQUE
UNIQUE significa che i valori in una colonna non possono ripetersi.
Molto utile per le email.
Esempio:
email VARCHAR(150) UNIQUE
Tabella:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE
);
Inserisci il primo utente:
INSERT INTO users (name, email)
VALUES ('Anna', 'anna@example.com');
Questo funziona.
Prova a inserire un altro utente con la stessa email:
INSERT INTO users (name, email)
VALUES ('Another Anna', 'anna@example.com');
PostgreSQL lo rifiuta.
Perché l’email deve essere unica.
Questo protegge i dati.
Senza UNIQUE, email duplicate possono creare problemi di login, account e mal di testa.
Il mal di testa da database non è divertente.
Porta stivali pesanti.
DEFAULT
DEFAULT dà a una colonna un valore quando nessun valore viene fornito.
Esempio:
active BOOLEAN DEFAULT true
Tabella:
CREATE TABLE subscribers (
id SERIAL PRIMARY KEY,
email VARCHAR(150) UNIQUE NOT NULL,
active BOOLEAN DEFAULT true
);
Inserisci senza active:
INSERT INTO subscribers (email)
VALUES ('reader@example.com');
Ora controlla:
SELECT * FROM subscribers;
La colonna active dovrebbe essere true.
PostgreSQL ha usato il valore di default.
I default sono utili quando la maggior parte delle righe dovrebbe iniziare con lo stesso valore.
Per esempio:
active DEFAULT true;completed DEFAULT false;published DEFAULT false;created_at DEFAULT CURRENT_DATE.
I buoni default riducono codice ripetitivo.
E il codice ripetitivo è dove piccoli bug costruiscono nidi.
CHECK
CHECK crea una regola che i valori devono rispettare.
Esempio:
price NUMERIC(10, 2) CHECK (price >= 0)
Questo significa che il prezzo non può essere negativo.
Tabella:
CREATE TABLE store_products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(10, 2) CHECK (price >= 0)
);
Questo funziona:
INSERT INTO store_products (name, price)
VALUES ('Mouse', 25.00);
Questo no:
INSERT INTO store_products (name, price)
VALUES ('Magic Refund Product', -10.00);
PostgreSQL lo rifiuta.
Bene.
I prezzi negativi possono esistere in contabilità.
Ma non in questa tabella.
Il database protegge la regola.
Molto serio.
Molto utile.
CHECK con Age
Altro esempio:
age INTEGER CHECK (age >= 0)
Questo significa che l’età non può essere negativa.
Tabella:
CREATE TABLE people (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INTEGER CHECK (age >= 0)
);
Questo funziona:
INSERT INTO people (name, age)
VALUES ('Anna', 22);
Questo no:
INSERT INTO people (name, age)
VALUES ('Time Traveler', -5);
PostgreSQL rifiuta.
Bene.
Se ti servono viaggiatori nel tempo, crea una tabella separata.
Forse.
Combinare Vincoli
Puoi combinare diversi vincoli in una tabella.
Esempio:
CREATE TABLE app_users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
active BOOLEAN DEFAULT true,
age INTEGER CHECK (age >= 0)
);
Questa tabella ha molte regole:
idè la primary key;nameè obbligatorio;emailè obbligatoria;emaildeve essere unica;activeparte datrue;agenon può essere negativa.
È molto più sicura di una tabella senza regole.
Una tabella senza vincoli accetta troppo.
È troppo educata.
I database non dovrebbero essere troppo educati.
Dovrebbero proteggere i dati.
Come un buttafuori serio al club delle informazioni.
Creare una Tabella Products più Sicura
Creiamo una tabella products migliore.
Prima rimuovi la vecchia se serve:
DROP TABLE IF EXISTS safe_products;
Ora crea:
CREATE TABLE safe_products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category VARCHAR(100) DEFAULT 'General',
price NUMERIC(10, 2) CHECK (price >= 0),
available BOOLEAN DEFAULT true
);
Questa tabella ha regole migliori:
nameè obbligatorio;categoryha un default;pricenon può essere negativo;availableparte datrue.
Inserisci dati:
INSERT INTO safe_products (name, price)
VALUES ('Laptop', 900.00);
Controlla:
SELECT * FROM safe_products;
Dovresti vedere:
category = General
available = true
PostgreSQL ha riempito i default.
Bello.
Il database sta aiutando.
Finalmente.
Testare le Regole
Prova a inserire un prodotto senza nome:
INSERT INTO safe_products (price)
VALUES (10.00);
PostgreSQL dovrebbe rifiutare perché name è NOT NULL.
Prova a inserire un prezzo negativo:
INSERT INTO safe_products (name, price)
VALUES ('Broken Product', -5.00);
PostgreSQL dovrebbe rifiutare per via del CHECK.
Questo è buono.
La tabella si difende.
Una tabella che si difende è molto più sicura di una tabella che accetta tutto.
Come una porta con una serratura.
Non perfetta.
Ma meglio di una tenda.
Ispezionare la Tabella
Esegui:
\d safe_products
Dovresti vedere colonne, tipi, default e vincoli.
Questo comando è utile.
Usalo spesso.
Quando dimentichi com’è fatta la tabella, chiedi a PostgreSQL.
Lui ricorda.
Ricorda sempre.
Molto database.
Leggermente inquietante.
Errori Comuni
Usare TEXT per Tutto
Male:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age TEXT,
active TEXT
);
Meglio:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INTEGER,
active BOOLEAN
);
Usa il tipo corretto.
Text non è una soluzione universale.
È uno strumento utile.
Non un sacco dell’immondizia per lo storage.
Dimenticare NOT NULL
Male:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(150)
);
Questo permette utenti senza nome o email.
Forse non è quello che vuoi.
Meglio:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL
);
Se un valore è obbligatorio, dillo.
PostgreSQL lo farà rispettare.
Dimenticare UNIQUE sull'Email
Male:
email VARCHAR(150)
Meglio:
email VARCHAR(150) UNIQUE
Se le email identificano gli utenti, di solito devono essere uniche.
Email duplicate sono come due persone con lo stesso passaporto.
Possibile in un sistema brutto.
Pessima idea.
Permettere Prezzi Negativi
Male:
price NUMERIC(10, 2)
Meglio:
price NUMERIC(10, 2) CHECK (price >= 0)
Se i prezzi negativi non hanno senso, bloccali.
Non fidarti del codice futuro perché si comporti sempre bene.
Il codice futuro è scritto da umani futuri.
Pericoloso.
Pratica
Crea una tabella chiamata employees.
Deve avere:
id;name;email;salary;active;hired_at.
Usa queste regole:
nameè obbligatorio;emailè obbligatoria e unica;salarynon può essere negativo;activeparte datrue;hired_atè una data.
Esempio:
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
salary NUMERIC(10, 2) CHECK (salary >= 0),
active BOOLEAN DEFAULT true,
hired_at DATE
);
Inserisci employees:
INSERT INTO employees (name, email, salary, hired_at)
VALUES ('Anna', 'anna@example.com', 2500.00, '2026-05-03');
INSERT INTO employees (name, email, salary, active, hired_at)
VALUES ('Marco', 'marco@example.com', 3000.00, false, '2026-05-04');
Leggi dati:
SELECT * FROM employees;
Poi testa i vincoli.
Prova email duplicata.
Prova stipendio negativo.
Prova nome mancante.
Lascia che PostgreSQL ti fermi.
Questo è il punto.
Mini Challenge
Crea una tabella chiamata courses.
Deve avere:
id;title;description;price;published;created_at.
Regole:
titleè obbligatorio;pricenon può essere negativo;publishedparte dafalse;created_atparte dalla data corrente.
Suggerimento:
created_at DATE DEFAULT CURRENT_DATE
Inserisci almeno tre corsi.
Poi esegui:
SELECT * FROM courses;
Prova a inserire un corso senza titolo.
Prova a inserire un corso con prezzo negativo.
PostgreSQL dovrebbe rifiutare dati sbagliati.
Questo non è PostgreSQL che fa il fastidioso.
È PostgreSQL che è utile.
C’è differenza.
A volte.
Riepilogo
Oggi hai imparato:
- i tipi di dati definiscono che tipo di dato salva una colonna;
INTEGERsalva numeri interi;VARCHARsalva testo limitato;TEXTsalva testo lungo;BOOLEANsalvatrueofalse;DATEsalva date;NUMERICsalva valori decimali precisi;SERIALcrea ID auto-incrementali;- i vincoli creano regole per i dati;
NOT NULLrende una colonna obbligatoria;UNIQUEimpedisce valori duplicati;DEFAULTfornisce automaticamente un valore;CHECKvalida valori con una condizione;- un buon design delle tabelle protegge il database.
Questo è un grande passo.
Non stai più solo creando tabelle.
Stai creando tabelle più sicure.
Un database non dovrebbe accettare assurdità.
Dovrebbe proteggere la struttura.
Dovrebbe rifiutare dati sbagliati.
Dovrebbe fermare età banana, email duplicate, prezzi negativi e utenti misteriosi senza nome.
PostgreSQL può farlo.
Se gli dai le regole.
Prossima Lezione
Nella prossima lezione impareremo a filtrare e ordinare dati.
Andremo più a fondo in:
WHERE;- operatori di confronto;
AND;OR;LIKE;ORDER BY;LIMIT.
Perché una volta che hai dati, devi trovare i dati giusti.
Non tutti i dati.
I dati giusti.
È lì che le query diventano interessanti.
E leggermente pericolose.