1001Ferramentas
🗃️Geradores

Gerador de CREATE TABLE SQL

Gera DDL CREATE TABLE a partir de uma lista de campos com tipos. Adiciona id PK auto-increment automaticamente.


  

CREATE TABLE SQL em profundidade: dialetos, constraints e design de esquema

O comando CREATE TABLE é a pedra fundamental da DDL (Data Definition Language) — o subconjunto do SQL que define o formato dos dados em vez de consultar ou alterar linhas. De um SQLite rodando num celular até um Aurora cluster com milhares de transações por segundo, toda base relacional começa com as mesmas poucas linhas declarativas descrevendo colunas, tipos, valores default e constraints. Acertar o esquema no momento da criação é uma das decisões de maior alavancagem em todo o ciclo de vida de um projeto: tipos, chaves primárias e chaves estrangeiras ficam notoriamente caros de alterar quando a tabela já tem milhões de registros.

Este gerador emite DDL portável para começar; abaixo está uma referência mais aprofundada cobrindo as diferenças entre dialetos (PostgreSQL, MySQL, SQLite, SQL Server), famílias de constraints, colunas geradas, particionamento e ferramentas de migration que todo desenvolvedor backend acaba precisando.

Sintaxe básica

A forma mínima lista um nome de tabela e uma lista de colunas entre parênteses. Cada declaração é nome tipo [constraints]:

CREATE TABLE usuarios (
  id         INTEGER PRIMARY KEY,
  nome       VARCHAR(100) NOT NULL,
  email      VARCHAR(255) UNIQUE NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Adicione IF NOT EXISTS para migrations idempotentes e CREATE TEMPORARY TABLE para tabelas com escopo de sessão usadas em ETL ou relatórios.

Tipos por dialeto

  • PostgreSQL: SERIAL/BIGSERIAL ou o moderno GENERATED ALWAYS AS IDENTITY, JSONB (JSON indexável), UUID, TIMESTAMPTZ (com fuso), NUMERIC(p,s), tipos ARRAY nativos e ENUM via CREATE TYPE.
  • MySQL / MariaDB: INT AUTO_INCREMENT, JSON (desde 5.7), ENUM('a','b') inline, DATETIME vs TIMESTAMP (este último ocupa 4 bytes e armazena em UTC, mas é limitado a 2038), DECIMAL(p,s) e particularidades por engine (InnoDB vs MyISAM).
  • SQLite: apenas cinco storage classes (INTEGER, TEXT, REAL, BLOB, NUMERIC) mais type affinity. A combinação INTEGER PRIMARY KEY faz alias do ROWID interno e é a chave mais rápida possível.
  • SQL Server: INT IDENTITY(1,1), NVARCHAR(n) para Unicode, DATETIME2 (preferível ao antigo DATETIME), UNIQUEIDENTIFIER e colunas calculadas via AS.

Constraints: PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK, NOT NULL, DEFAULT

Constraints são como o banco garante invariantes que o código da aplicação pode esquecer. Toda tabela deve ter uma única PRIMARY KEY (implicitamente NOT NULL UNIQUE); chaves compostas são legais mas mais difíceis de referenciar por tabelas filhas. Declarações FOREIGN KEY ligam a uma linha pai e aceitam ações referenciais:

CREATE TABLE pedidos (
  id         BIGSERIAL PRIMARY KEY,
  usuario_id INTEGER NOT NULL REFERENCES usuarios(id)
             ON DELETE CASCADE ON UPDATE NO ACTION,
  total      NUMERIC(10,2) NOT NULL CHECK (total >= 0),
  status     VARCHAR(20) NOT NULL DEFAULT 'pendente',
  CONSTRAINT chk_status CHECK (status IN ('pendente','pago','enviado'))
);

Opções ON DELETE: CASCADE apaga os filhos automaticamente, SET NULL zera a FK, SET DEFAULT usa o default da coluna, RESTRICT bloqueia o delete do pai imediatamente, e NO ACTION adia a checagem para o fim da transação.

Colunas geradas, índices e particionamento

Colunas geradas (computed) derivam o valor de uma expressão e evitam duplicação entre caminhos de insert:

qtd   INTEGER NOT NULL,
preco NUMERIC(10,2) NOT NULL,
total NUMERIC(12,2) GENERATED ALWAYS AS (qtd * preco) STORED

Alguns dialetos (MySQL, SQL Server) permitem UNIQUE INDEX (col) inline dentro do CREATE TABLE; a maioria dos projetos mantém índices em comandos CREATE INDEX separados, para poder adicioná-los concurrently em produção sem reescrever a tabela. O particionamento divide uma tabela lógica em pedaços físicos por range, list ou hash — PARTITION BY RANGE (created_at) declarativo existe no PostgreSQL desde a 10 e no MySQL desde a 5.1, e melhora drasticamente o tempo de prune em workloads de séries temporais.

Nomenclatura e boas práticas de design

  • Use snake_case e nomes de tabela no plural (usuarios, itens_pedido) — combinam naturalmente com chaves estrangeiras (usuario_id).
  • Escolha uma estratégia de PK e mantenha: BIGINT IDENTITY surrogado para OLTP, UUID v7 quando IDs vazam para clientes ou são gerados offline.
  • Adicione created_at + updated_at em toda tabela; o custo são duas colunas e o valor durante debug é enorme.
  • Considere soft delete (deleted_at TIMESTAMP NULL) em entidades expostas ao usuário, para que remoções acidentais sejam reversíveis.
  • Colunas de auditoria (created_by_id, updated_by_id) tornam compliance e forense triviais.

Ferramentas de migration

Em produção raramente se roda CREATE TABLE à mão; em vez disso, um framework de migration versiona cada mudança e a aplica de forma determinística em todos os ambientes. Opções populares: Flyway e Liquibase (JVM), Alembic (Python/SQLAlchemy), Rails migrations (Ruby), Knex.js e Prisma Migrate (Node.js), golang-migrate (Go) e EF Core Migrations (.NET). Todas registram as versões aplicadas em uma tabela de metadados e suportam rollback de alguma forma.

FAQ

Uma tabela pode ter zero colunas? Não — o padrão SQL exige pelo menos uma coluna. O PostgreSQL tecnicamente aceita uma tabela só com colunas geradas internas, mas é curiosidade, não padrão.

Como mudar a chave primária depois? Use ALTER TABLE ... DROP CONSTRAINT seguido de ADD CONSTRAINT. Algumas engines exigem recriar a tabela; ferramentas como pt-online-schema-change (MySQL) ou pg_repack (PostgreSQL) fazem isso sem locks longos.

Os tipos são portáveis entre dialetos? Nem tanto. VARCHAR, INT e TIMESTAMP são compatíveis na maioria dos casos, mas tudo mais rico (JSONB, UUID, ENUM, arrays, sintaxe de identity) diverge. Use um ORM ou camada de abstração SQL se precisar de portabilidade real.

Devo usar VARCHAR(255) como default? Não. Escolha um tamanho que reflita o domínio (e-mails 255, nomes 100, slugs 80). No PostgreSQL, TEXT não tem limite e tem a mesma performance de VARCHAR.

CREATE TABLE é transacional? No PostgreSQL e no SQL Server, sim — envolva em BEGIN ... COMMIT com os ALTERs relacionados. No MySQL, DDL faz commit implícito, então planeje rollback de outro jeito (DDL atômico desde a 8.0 ajuda).

Ferramentas Relacionadas