Constraints: PRIMARY KEY, NOT NULL, UNIQUE, DEFAULT
1. O que são Constraints e por que usá-las?
Constraints (restrições) são regras definidas no esquema de um banco de dados relacional para garantir a integridade e a consistência dos dados armazenados. Elas atuam como guardiões silenciosos que impedem a inserção, atualização ou exclusão de dados que violem regras de negócio previamente estabelecidas.
Sem constraints, um banco de dados pode rapidamente se tornar um repositório de dados inconsistentes, com registros duplicados, valores nulos indesejados ou chaves que não referenciam registros existentes. As constraints são a primeira linha de defesa contra dados corrompidos.
Existem dois tipos principais de constraints:
- Constraints de coluna: aplicadas a uma única coluna na definição da tabela
- Constraints de tabela: aplicadas a múltiplas colunas ou à tabela como um todo
As quatro constraints fundamentais que exploraremos neste artigo são: PRIMARY KEY, NOT NULL, UNIQUE e DEFAULT.
2. NOT NULL: Garantindo que campos não fiquem vazios
A constraint NOT NULL é a mais simples de todas. Ela garante que uma coluna nunca contenha valores nulos (NULL). Por padrão, a maioria das colunas permite NULL, a menos que explicitamente informado o contrário.
Sintaxe básica:
CREATE TABLE clientes (
id_cliente INT NOT NULL,
nome VARCHAR(100) NOT NULL,
email VARCHAR(200),
telefone VARCHAR(20)
);
Neste exemplo, id_cliente e nome são obrigatórios, enquanto email e telefone podem ser nulos.
Comportamento em INSERT e UPDATE:
-- Válido: todos os campos NOT NULL foram preenchidos
INSERT INTO clientes (id_cliente, nome, email)
VALUES (1, 'Maria Silva', 'maria@email.com');
-- Inválido: nome não pode ser NULL
INSERT INTO clientes (id_cliente, nome)
VALUES (2, NULL);
-- Inválido: id_cliente não pode ser NULL
INSERT INTO clientes (nome, email)
VALUES ('João', 'joao@email.com');
Cuidados importantes: NULL não é o mesmo que zero ou string vazia. Um campo VARCHAR(100) NOT NULL aceita uma string vazia (''), mas rejeita NULL. Da mesma forma, um INT NOT NULL aceita o valor 0, mas rejeita NULL.
3. UNIQUE: Evitando duplicatas em uma coluna
A constraint UNIQUE garante que todos os valores em uma coluna (ou combinação de colunas) sejam distintos entre si. Diferentemente da PRIMARY KEY, uma coluna UNIQUE pode conter um único valor NULL (em alguns bancos de dados, múltiplos NULLs são permitidos).
Declaração em uma coluna:
CREATE TABLE usuarios (
id_usuario INT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(200) UNIQUE NOT NULL
);
Diferença entre UNIQUE e PRIMARY KEY:
| Característica | PRIMARY KEY | UNIQUE |
|---|---|---|
| Permite NULL | Não | Sim (um valor) |
| Quantidade por tabela | Apenas uma | Múltiplas |
| Índice clusterizado | Geralmente sim | Não |
UNIQUE em múltiplas colunas (constraint composta):
CREATE TABLE matriculas (
id_aluno INT NOT NULL,
id_curso INT NOT NULL,
ano INT NOT NULL,
UNIQUE (id_aluno, id_curso, ano)
);
Esta constraint composta garante que um mesmo aluno não possa se matricular no mesmo curso no mesmo ano mais de uma vez.
4. PRIMARY KEY: A espinha dorsal de cada tabela
A PRIMARY KEY é a constraint mais importante em qualquer tabela relacional. Ela combina as características de NOT NULL e UNIQUE, garantindo que cada linha seja única e identificável de forma inequívoca.
Características fundamentais:
- Cada tabela deve ter uma (e apenas uma) PRIMARY KEY
- NOT NULL e UNIQUE são implícitos
- Um índice é automaticamente criado (geralmente clusterizado)
Sintaxe: chave primária simples vs. composta:
-- Chave primária simples (coluna única)
CREATE TABLE produtos (
id_produto INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
preco DECIMAL(10,2) NOT NULL
);
-- Chave primária composta (múltiplas colunas)
CREATE TABLE itens_pedido (
id_pedido INT NOT NULL,
id_produto INT NOT NULL,
quantidade INT NOT NULL,
PRIMARY KEY (id_pedido, id_produto)
);
Impacto na criação de índices:
Ao declarar uma PRIMARY KEY, o banco de dados automaticamente cria um índice único para acelerar buscas por essa chave. Em muitos SGBDs (como SQL Server e MySQL com InnoDB), esse índice é clusterizado, o que significa que os dados físicos são organizados de acordo com a ordem da chave primária.
5. DEFAULT: Valores padrão para colunas
A constraint DEFAULT define um valor automático para uma coluna quando nenhum valor é fornecido durante a inserção. Isso simplifica o código e garante consistência.
Sintaxe básica:
CREATE TABLE pedidos (
id_pedido INT PRIMARY KEY,
data_pedido DATE DEFAULT CURRENT_DATE,
status VARCHAR(20) DEFAULT 'Pendente',
total DECIMAL(10,2) DEFAULT 0.00,
ativo BOOLEAN DEFAULT TRUE
);
Exemplos práticos:
-- Datas e timestamps
data_criacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP
data_atualizacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-- Booleanos
ativo BOOLEAN DEFAULT TRUE
confirmado BOOLEAN DEFAULT FALSE
-- Strings
status VARCHAR(20) DEFAULT 'Ativo'
categoria VARCHAR(50) DEFAULT 'Geral'
-- Números
quantidade INT DEFAULT 1
desconto DECIMAL(5,2) DEFAULT 0.00
Interação com INSERT:
-- Omite a coluna com DEFAULT (usa o valor padrão)
INSERT INTO pedidos (id_pedido) VALUES (1);
-- Usa explicitamente a palavra-chave DEFAULT
INSERT INTO pedidos (id_pedido, data_pedido)
VALUES (2, DEFAULT);
-- Fornece um valor diferente do padrão
INSERT INTO pedidos (id_pedido, status)
VALUES (3, 'Cancelado');
6. Boas práticas e erros comuns
Escolhendo a chave primária: surrogate vs. natural
Chave surrogate (artificial):
CREATE TABLE clientes (
id_cliente INT AUTO_INCREMENT PRIMARY KEY,
cpf VARCHAR(11) UNIQUE NOT NULL,
nome VARCHAR(100) NOT NULL
);
Chave natural (baseada em dados reais):
CREATE TABLE paises (
codigo_iso CHAR(3) PRIMARY KEY,
nome VARCHAR(100) NOT NULL
);
Recomendação: Prefira chaves surrogate para a maioria dos casos. Elas são imutáveis, independentes de regras de negócio e mais eficientes em termos de desempenho.
Cuidados com UNIQUE em campos de texto longos
Campos de texto muito longos (como VARCHAR(500) ou TEXT) com constraint UNIQUE podem causar problemas de desempenho, pois o índice necessário para verificar a unicidade será grande e lento. Considere usar um hash do conteúdo ou limitar o tamanho do campo.
Quando evitar NOT NULL
Nem todos os campos precisam ser obrigatórios. Evite NOT NULL quando:
- O dado é genuinamente opcional (ex: telefone secundário)
- O valor ainda não está disponível no momento do cadastro
- NULL tem um significado semântico diferente de zero ou string vazia
-- Exemplo de uso adequado de NULL
CREATE TABLE funcionarios (
id_funcionario INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
data_demissao DATE, -- NULL significa "ainda empregado"
salario DECIMAL(10,2) NOT NULL
);
Conclusão
As constraints PRIMARY KEY, NOT NULL, UNIQUE e DEFAULT são ferramentas essenciais para qualquer profissional que trabalhe com bancos de dados relacionais. Elas garantem a integridade dos dados, previnem erros comuns e documentam as regras de negócio diretamente no esquema do banco.
Dominar essas constraints permite criar estruturas de dados robustas e confiáveis, reduzindo a necessidade de validações complexas na camada de aplicação. Invista tempo em projetar suas tabelas com as constraints adequadas desde o início – seu banco de dados (e seus usuários) agradecerão.
Referências
- Documentação PostgreSQL: Constraints — Documentação oficial sobre todos os tipos de constraints no PostgreSQL, com exemplos detalhados.
- MySQL 8.0 Reference Manual: PRIMARY KEY and UNIQUE Constraints — Explicação completa das constraints PRIMARY KEY e UNIQUE no MySQL.
- SQL Server Documentation: Constraints — Guia oficial da Microsoft sobre constraints no SQL Server, incluindo boas práticas.
- W3Schools SQL Constraints Tutorial — Tutorial interativo com exemplos práticos de NOT NULL, UNIQUE, PRIMARY KEY e DEFAULT.
- Oracle Database SQL Language Reference: Constraints — Documentação oficial da Oracle sobre a sintaxe e comportamento de constraints.