🧚 Ascolta! Beekeeper Studio è una GUI per database veloce, moderna e open source Scarica
13 gennaio 2026 Di Matthew Rathbone

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 STRICT dopo la parentesi di chiusura per attivare il controllo (una tabella strict accetta solo i tipi INT, INTEGER, REAL, TEXT, BLOB e ANY).
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 KEY a parte, non come REFERENCES dentro la definizione della colonna: MySQL 8 accetta quella forma abbreviata e poi la ignora. SQLite applica le foreign key solo dopo PRAGMA foreign_keys = ON;, da eseguire su ogni connessione.
  • CREATE TABLE fallisce se la tabella esiste già. Scrivi CREATE TABLE IF NOT EXISTS per saltarla.
  • In MySQL, una colonna TEXT non può avere DEFAULT o UNIQUE. Usa VARCHAR(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.

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.

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:

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.

La versione Linux di Beekeeper è completa al 100%, senza tagli e senza compromessi sulle funzionalità.

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."
— Alex K., Database Developer
★★★★★
"Ho provato molte GUI per database, ma Beekeeper trova il perfetto equilibrio tra funzionalità e semplicità. Funziona e basta."
— Sarah M., Full Stack Engineer

Pronto a migliorare il tuo workflow SQL?

download Scarica gratis