CREATE TABLE aggiunge una nuova tabella a un database. Dai un nome alla tabella ed elenchi le sue colonne, ognuna con un tipo di dato e le eventuali regole (vincoli) che i suoi valori devono rispettare. Gli esempi funzionano in PostgreSQL, MySQL, SQLite e SQL Server.
Come usare CREATE TABLE
Dai un nome alla tabella, poi elenca le sue colonne tra parentesi, separate da virgole. Ogni colonna ha un nome, un tipo di dato e, facoltativamente, vincoli come PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT o CHECK:
CREATE TABLE table_name (
column_name data_type constraints,
another_column data_type constraints
);
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
country CHAR(2) DEFAULT 'US',
signed_up DATE
);
INSERT INTO customers (id, name, email, signed_up)
VALUES (1, 'Ana Lima', 'ana@example.com', '2026-03-02');
SELECT * FROM customers;
-- Output:
-- id | name | email | country | signed_up
-- ---+----------+-----------------+---------+-----------
-- 1 | Ana Lima | ana@example.com | US | 2026-03-02
La nuova tabella resta vuota finché non ci inserisci delle righe. Questo insert ha omesso country, quindi la riga ha ricevuto il valore predefinito, US.
Regole da conoscere
-
SQLite non impone tipi né lunghezze. Dove altri database rifiutano un valore che non è adatto alla colonna, SQLite lo salva comunque. Aggiungi
STRICTdopo la parentesi di chiusura per attivare il controllo (una tabella strict accetta solo i tipiINT,INTEGER,REAL,TEXT,BLOBeANY).
CREATE TABLE products (
sku VARCHAR(5),
quantity INTEGER
);
-- SQLite stores this row; other databases reject it with an error
INSERT INTO products VALUES ('LAMP-001', 'twelve');
SELECT sku, quantity FROM products;
-- Output (SQLite):
-- sku | quantity
-- ---------+---------
-- LAMP-001 | twelve
-
Dichiara una foreign key su una riga
FOREIGN KEYa parte, non comeREFERENCESdentro la definizione della colonna: MySQL 8 accetta quella forma abbreviata e poi la ignora. SQLite applica le foreign key solo dopoPRAGMA foreign_keys = ON;, da eseguire su ogni connessione. -
CREATE TABLE fallisce se la tabella esiste già. Scrivi
CREATE TABLE IF NOT EXISTSper saltarla. -
In MySQL, una colonna
TEXTnon può avereDEFAULToUNIQUE. UsaVARCHAR(n), come negli esempi qui.
Sintassi alternativa
Gli id a numerazione automatica si scrivono in modo diverso in ogni database:
| Database | Colonna id a numerazione automatica |
|---|---|
| PostgreSQL | id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY |
| MySQL | id INT AUTO_INCREMENT PRIMARY KEY |
| SQLite | id INTEGER PRIMARY KEY |
| SQL Server | id INT IDENTITY(1,1) PRIMARY KEY |
Ometti l'id in un insert e il database inserisce il numero successivo.
SQL Server ha anche nomi propri per le colonne vero/falso e data-ora, e non ha IF NOT EXISTS. Usa BIT (con 1 e 0) al posto di BOOLEAN, DATETIME2 per data e ora (il suo TIMESTAMP è un numero di versione della riga, non una data) e controlla OBJECT_ID prima di creare la tabella:
-- SQL Server
IF OBJECT_ID('users', 'U') IS NULL
CREATE TABLE users (
id INT IDENTITY(1,1) PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
is_active BIT NOT NULL DEFAULT 1,
created_at DATETIME2 NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Quando usare CREATE TABLE?
Ogni tabella nasce con CREATE TABLE, ma le colonne e i vincoli che scegli risolvono problemi diversi.
Salvare un nuovo tipo di dato
Ogni tipo di entità che la tua applicazione gestisce, come clienti, libri o fatture, ha la sua tabella, con una colonna per ogni informazione e un tipo adatto ai valori.
Dare a ogni riga un ID univoco
Una PRIMARY KEY impedisce che due righe condividano lo stesso identificatore, così puoi sempre trovare, aggiornare o collegare esattamente una riga. Lascia che sia il database a numerare le righe (vedi “Sintassi alternativa” sopra), oppure combina due colonne quando serve una coppia di valori per identificare una riga.
Tenere fuori dati errati o mancanti
I vincoli rifiutano le righe che violano le tue regole: NOT NULL per le colonne obbligatorie, UNIQUE per valori come gli indirizzi email e CHECK per gli intervalli consentiti. DEFAULT riempie una colonna che un insert omette.
Collegare tabelle correlate
Una FOREIGN KEY fa puntare una colonna a una riga di un'altra tabella, così un ordine non può riferirsi a un cliente che non esiste. Aggiungi ON DELETE CASCADE ed eliminando la riga padre verranno eliminate anche le righe che puntano a essa.
Salvare i risultati di una query come tabella
CREATE TABLE ... AS SELECT crea una tabella e la riempie da una query in un'unica istruzione. Usalo per snapshot, tabelle di report o un backup delle righe che stai per modificare.
Esempi reali di CREATE TABLE
I messaggi di errore sono quelli di PostgreSQL. Altri database rifiutano le stesse righe con parole proprie.
Una tabella di collegamento con chiave a due colonne
Gli studenti seguono molti corsi e i corsi hanno molti studenti. La tabella enrollments li collega e la sua chiave primaria è la coppia di id, così uno studente può iscriversi a molti corsi ma non due volte allo stesso:
CREATE TABLE enrollments (
student_id INTEGER NOT NULL,
course_id INTEGER NOT NULL,
enrolled_on DATE,
PRIMARY KEY (student_id, course_id)
);
INSERT INTO enrollments VALUES (1, 101, '2026-09-01');
INSERT INTO enrollments VALUES (1, 102, '2026-09-01');
INSERT INTO enrollments VALUES (1, 101, '2026-09-08');
-- ERROR: duplicate key value violates unique constraint "enrollments_pkey"
-- DETAIL: Key (student_id, course_id)=(1, 101) already exists.
SELECT * FROM enrollments;
-- Output:
-- student_id | course_id | enrolled_on
-- -----------+-----------+------------
-- 1 | 101 | 2026-09-01
-- 1 | 102 | 2026-09-01
Iscrizioni che rispettano le regole
Ogni account ha bisogno di un indirizzo email non usato da altri account e di almeno un posto. I nuovi account partono dal piano gratuito con un posto:
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
tier VARCHAR(20) NOT NULL DEFAULT 'free',
seats INTEGER NOT NULL DEFAULT 1 CHECK (seats > 0)
);
INSERT INTO accounts (id, email) VALUES (1, 'sam@example.com');
SELECT * FROM accounts;
-- Output:
-- id | email | tier | seats
-- ---+-----------------+------+------
-- 1 | sam@example.com | free | 1
INSERT INTO accounts (id, email) VALUES (2, 'sam@example.com');
-- ERROR: duplicate key value violates unique constraint "accounts_email_key"
INSERT INTO accounts (id, email, seats) VALUES (3, 'kim@example.com', 0);
-- ERROR: new row ... violates check constraint "accounts_seats_check"
INSERT INTO accounts (id) VALUES (4);
-- ERROR: null value in column "email" ... violates not-null constraint
Ordini che devono appartenere a un cliente
Ogni ordine punta a un cliente. La foreign key rifiuta un ordine per un cliente che non esiste e ON DELETE CASCADE rimuove gli ordini di un cliente quando il cliente viene eliminato. In SQLite, esegui prima PRAGMA foreign_keys = ON;.
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL,
total DECIMAL(10,2),
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE
);
-- Input: customers
-- id | name
-- ---+-----------
-- 1 | Ana Lima
-- 2 | Ben Okafor
-- Input: orders
-- id | customer_id | total
-- ---+-------------+------
-- 10 | 1 | 25.00
-- 11 | 1 | 60.00
-- 12 | 2 | 42.50
INSERT INTO orders VALUES (13, 99, 15.00);
-- ERROR: ... violates foreign key constraint "orders_customer_id_fkey"
-- DETAIL: Key (customer_id)=(99) is not present in table "customers".
DELETE FROM customers WHERE id = 1;
-- Output (orders after the DELETE):
-- id | customer_id | total
-- ---+-------------+------
-- 12 | 2 | 42.50
Uno snapshot dei clienti attivi
Copia i clienti che hanno ordinato quest'anno in una tabella a parte, per una lista di campagna che non deve cambiare all'arrivo di nuovi ordini:
-- Input: customers
-- customer_id | name | email | last_order_date
-- ------------+------------+-------------------+----------------
-- 1 | Ana Lima | ana@example.com | 2026-03-18
-- 2 | Ben Okafor | ben@example.com | 2025-11-02
-- 3 | Chloe Park | chloe@example.com | 2026-06-30
-- 4 | Dev Shah | dev@example.com | NULL
CREATE TABLE active_customers AS
SELECT customer_id, name, email
FROM customers
WHERE last_order_date >= '2026-01-01';
-- SQL Server has no CREATE TABLE ... AS. Use SELECT ... INTO:
SELECT customer_id, name, email
INTO active_customers
FROM customers
WHERE last_order_date >= '2026-01-01';
-- Output (active_customers):
-- customer_id | name | email
-- ------------+------------+------------------
-- 1 | Ana Lima | ana@example.com
-- 3 | Chloe Park | chloe@example.com
La nuova tabella riceve le colonne, i loro tipi e le righe, ma non la chiave primaria né altri vincoli. Aggiungili con ALTER TABLE se ti servono.
Approfondimenti su CREATE TABLE
Su questo blog:
- Guida alle tabelle temporanee SQL: tabelle che durano solo quanto la tua sessione
- SQL ALTER TABLE add column: modificare una tabella dopo averla creata
- Chiavi primarie composte in SQL: chiavi formate da più colonne
- Come usare le foreign key in PostgreSQL: foreign key e azioni di eliminazione più nel dettaglio
- Guida alle relazioni tra database: progettare tabelle collegate tra loro
- Istruzione SQL INSERT: aggiungere righe a una nuova tabella
- Generatore di tabelle SQL: crea un'istruzione CREATE TABLE nel browser invece di scriverla a mano
Documentazione ufficiale:
Beekeeper Studio è una GUI per database gratuita & open source
Il miglior strumento per query & editor SQL che abbia mai usato. Offre tutto ciò che mi serve per gestire il mio database. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio è veloce, intuitivo e facile da usare. Beekeeper supporta tantissimi database e funziona alla grande su Windows, Mac e Linux.
Cosa dicono gli utenti di Beekeeper Studio
"Beekeeper Studio ha sostituito completamente il mio vecchio workflow SQL. È veloce, intuitivo e rende di nuovo piacevole lavorare con i database."
"Ho provato molte GUI per database, ma Beekeeper trova il perfetto equilibrio tra funzionalità e semplicità. Funziona e basta."