CREATE TABLE adiciona uma nova tabela a um banco de dados. Você dá um nome à tabela e lista suas colunas, cada uma com um tipo de dado e as regras (constraints) que seus valores precisam seguir. Os exemplos funcionam em PostgreSQL, MySQL, SQLite e SQL Server.
Como usar CREATE TABLE
Dê um nome à tabela e depois liste suas colunas entre parênteses, separadas por vírgulas. Cada coluna recebe um nome, um tipo de dado e, opcionalmente, constraints como PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT ou 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
A nova tabela fica vazia até você inserir linhas nela. Este insert omitiu country, então a linha recebeu o valor padrão, US.
Regras importantes
-
O SQLite não valida tipos nem tamanhos. Onde outros bancos rejeitam um valor que não cabe na coluna, o SQLite o armazena mesmo assim. Adicione
STRICTdepois do parêntese de fechamento para ativar a verificação (uma tabela strict aceita apenas os tiposINT,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
-
Declare a chave estrangeira em uma linha
FOREIGN KEYprópria, e não comoREFERENCESdentro da definição da coluna: o MySQL 8 aceita essa forma abreviada e depois a ignora. O SQLite só aplica chaves estrangeiras depois dePRAGMA foreign_keys = ON;, que você executa em cada conexão. -
CREATE TABLE falha se a tabela já existir. Escreva
CREATE TABLE IF NOT EXISTSpara pular a criação nesse caso. -
No MySQL, uma coluna
TEXTnão pode terDEFAULTnemUNIQUE. UseVARCHAR(n), como nos exemplos aqui.
Sintaxe alternativa
IDs numerados automaticamente são escritos de forma diferente em cada banco:
| Banco de dados | Coluna de ID autonumerada |
|---|---|
| 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 |
Omita o id em um insert e o banco preenche o próximo número.
O SQL Server também tem nomes próprios para colunas de verdadeiro/falso e de data e hora, e não tem IF NOT EXISTS. Use BIT (com 1 e 0) em vez de BOOLEAN, DATETIME2 para data e hora (o TIMESTAMP dele é um número de versão da linha, não uma data) e verifique OBJECT_ID antes de criar a tabela:
-- 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 usar CREATE TABLE?
Toda tabela começa com CREATE TABLE, mas as colunas e constraints que você escolhe resolvem problemas diferentes.
Armazenar um novo tipo de dado
Cada tipo de coisa que sua aplicação acompanha, como clientes, livros ou faturas, ganha sua própria tabela, com uma coluna para cada informação sobre ela e um tipo adequado aos valores.
Dar a cada linha um ID único
Uma PRIMARY KEY impede que duas linhas compartilhem o mesmo identificador, para que você sempre consiga encontrar, atualizar ou referenciar exatamente uma linha. Deixe o banco numerar as linhas (veja “Sintaxe alternativa” acima) ou combine duas colunas quando for preciso um par de valores para identificar uma linha.
Bloquear dados inválidos ou ausentes
Constraints rejeitam linhas que violam suas regras: NOT NULL para colunas obrigatórias, UNIQUE para valores como endereços de email e CHECK para intervalos permitidos. DEFAULT preenche uma coluna que o insert omite.
Relacionar tabelas
Uma FOREIGN KEY faz uma coluna apontar para uma linha em outra tabela, para que um pedido não possa citar um cliente que não existe. Adicione ON DELETE CASCADE e, ao excluir a linha pai, as linhas que apontam para ela também são excluídas.
Salvar resultados de consulta como tabela
CREATE TABLE ... AS SELECT cria uma tabela e a preenche a partir de uma consulta em um único comando. Use para snapshots, tabelas de relatório ou um backup de linhas que você está prestes a alterar.
Exemplos reais de CREATE TABLE
As mensagens de erro são do PostgreSQL. Outros bancos rejeitam as mesmas linhas com mensagens próprias.
Uma tabela de ligação com chave de duas colunas
Alunos fazem vários cursos, e cursos têm vários alunos. A tabela enrollments liga os dois, e sua chave primária é o par de ids, então um aluno pode entrar em vários cursos, mas não no mesmo curso duas vezes:
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
Cadastros que seguem as regras
Toda conta precisa de um endereço de email que nenhuma outra conta use e de pelo menos uma vaga. Novas contas começam no plano gratuito com uma vaga:
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
Pedidos que precisam pertencer a um cliente
Cada pedido aponta para um cliente. A chave estrangeira rejeita um pedido para um cliente que não existe, e ON DELETE CASCADE remove os pedidos de um cliente quando ele é excluído. No SQLite, execute PRAGMA foreign_keys = ON; antes.
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
Um snapshot de clientes ativos
Copie os clientes que fizeram pedidos este ano para uma tabela própria, criando uma lista de campanha que não muda conforme novos pedidos chegam:
-- 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
A nova tabela recebe as colunas, seus tipos e as linhas, mas não a chave primária nem outras constraints. Adicione-as com ALTER TABLE se precisar.
Leituras complementares sobre CREATE TABLE
Neste blog:
- Guia de tabelas temporárias em SQL: tabelas que só duram enquanto sua sessão estiver ativa
- SQL ALTER TABLE add column: alterando uma tabela depois de criá-la
- Chaves primárias compostas em SQL: chaves formadas por mais de uma coluna
- Como usar chaves estrangeiras no PostgreSQL: chaves estrangeiras e suas ações de exclusão em mais detalhes
- Guia de relacionamentos em bancos de dados: projetando tabelas que se relacionam
- Comando SQL INSERT: adicionando linhas a uma nova tabela
- Criador de tabelas SQL: monte um comando CREATE TABLE no navegador em vez de escrevê-lo à mão
Documentação oficial:
Beekeeper Studio é um cliente de banco de dados gratuito e open source
A melhor ferramenta de consultas e edição de SQL que já usei. Tem tudo o que preciso para gerenciar meu banco de dados. - ⭐⭐⭐⭐⭐ Mit
O Beekeeper Studio é rápido, intuitivo e fácil de usar. Ele suporta vários bancos de dados e funciona muito bem no Windows, Mac e Linux.
O que os usuários dizem sobre o Beekeeper Studio
"O Beekeeper Studio substituiu completamente meu antigo fluxo de trabalho com SQL. É rápido, intuitivo e torna o trabalho com bancos de dados agradável de novo."
"Já testei muitas GUIs de banco de dados, mas o Beekeeper encontra o equilíbrio perfeito entre recursos e simplicidade. Simplesmente funciona."