Carregando exercício...
Objetivos do Exercício:
Estado Atual do Banco (Schema & Dados Mockados)
tabela: clientes| Coluna | Tipo | Restrições (Constraints) |
|---|
Reforma de Banco de Dados em Produção no Supabase
SQL DDL – Alterações, Restrições Avançadas e Performance em SGBD Real
Objetivos do Aprendizado
🏢 A Situação-Problema (Cenário Real em Produção)
"Nosso banco de dados de cadastro de clientes no Supabase já está em produção com usuários cadastrados ativamente. Porém, hoje pela manhã o cliente solicitou mudanças críticas:
1. Precisamos registrar as empresas às quais os clientes pertencem.
2. Devemos incluir a idade dos clientes, bloqueando qualquer cadastro de menores de 18 anos.
3. Precisamos incluir o CPF obrigatório (NOT NULL) para aumentar a segurança do cadastro.
E agora? Não podemos apagar a tabela e nem reiniciar o banco, pois perderíamos os dados reais ativos. Faremos essa reforma com os moradores dentro do prédio!"
Passo 1: Preparando a Base (Simulando Produção)
Antes de começar a reforma, crie a tabela inicial de clientes com registros pré-existentes simulando a nossa produção ativa.
-- 1. Criar a tabela inicial de clientes
CREATE TABLE clientes (
id SERIAL PRIMARY KEY,
nome VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE
);
-- 2. Inserir dados de clientes existentes (Simulação de Produção)
INSERT INTO clientes (nome, email) VALUES
('João Silva', 'joao.silva@email.com'),
('Maria Oliveira', 'maria.oliveira@email.com'),
('Pedro Souza', 'pedro.souza@email.com');
Passo 2: A Armadilha do NOT NULL (Diagnóstico & Protocolo)
O cliente exige que a coluna cpf seja obrigatória. Se você tentar aplicar diretamente em uma tabela populada, o banco retornará erro:
ALTER TABLE clientes ADD COLUMN cpf VARCHAR(11) NOT NULL;
🚨 Por que falha? O PostgreSQL recusa o comando pois os 3 clientes antigos ficariam com o CPF nulo, violando a restrição de obrigatoriedade instantaneamente.
Solução Padrão de Mercado (Protocolo em 3 Etapas):
-- Etapa A: Adicionar a coluna permitindo NULL temporariamente
ALTER TABLE clientes
ADD COLUMN cpf VARCHAR(11);
-- Etapa B: Preencher os registros legados antigos
UPDATE clientes
SET cpf = '00000000000'
WHERE cpf IS NULL;
-- Etapa C: Aplicar a trava de obrigatoriedade NOT NULL
ALTER TABLE clientes
ALTER COLUMN cpf SET NOT NULL;
Passo 3: Blindagem com Restrições Avançadas (CHECK e CASCADE)
1. Restrição de Maioridade (CHECK)
Impede no próprio banco o cadastro de menores de 18 anos.
ALTER TABLE clientes ADD COLUMN idade INT;
ALTER TABLE clientes
ADD CONSTRAINT chk_maioridade
CHECK (idade >= 18);
INSERT INTO clientes (nome, email, cpf, idade) VALUES ('Guilherme', 'g@e.com', '12345678901', 16);❌ O SGBD rejeita e exibe erro de Check Constraint.
2. Integridade Referencial em Cascata
Associa o cliente à empresa. Se a empresa for removida, limpa os clientes vinculados automaticamente.
CREATE TABLE empresas (
id SERIAL PRIMARY KEY,
nome_fantasia VARCHAR(255) NOT NULL
);
ALTER TABLE clientes
ADD COLUMN empresa_id INT,
ADD CONSTRAINT fk_empresa
FOREIGN KEY (empresa_id)
REFERENCES empresas(id)
ON DELETE CASCADE;
DELETE FROM empresas WHERE id = 1;✔ Todos os clientes dessa empresa são deletados automaticamente sem orfanhar dados.
Passo 4: Acelerando o Banco com Índices B-Tree (CREATE INDEX)
Em tabelas com milhões de registros, realizar um SELECT * FROM clientes WHERE nome = '...' resulta em varredura sequencial (Table Scan) de alto custo. A criação de um índice reduz o tempo de busca de $O(N)$ para $O(\log N)$.
-- Criando um índice B-Tree acelerador para buscas pelo nome
CREATE INDEX idx_clientes_nome ON clientes(nome);
Passo 5: Os Botões de Pânico (TRUNCATE vs DROP)
Laboratório controlado para comparar na prática o esvaziamento instantâneo mantendo a estrutura (TRUNCATE) vs a exclusão total da tabela (DROP).
-- 1. Criar tabela temporária de testes
CREATE TABLE temp_logs (
id SERIAL PRIMARY KEY,
mensagem TEXT
);
INSERT INTO temp_logs (mensagem) VALUES ('Erro de login de teste');
-- 2. Testar TRUNCATE (Apaga todos os registros em alta velocidade, mas MANTÉM a tabela)
TRUNCATE TABLE temp_logs;
SELECT * FROM temp_logs; -- Retorna 0 linhas (a tabela ainda existe!)
-- 3. Testar DROP (Destrói os dados AND a estrutura da tabela)
DROP TABLE temp_logs;
SELECT * FROM temp_logs; -- Retorna Erro: relation "temp_logs" does not exist
Questões de Fixação e Avaliação Teórico-Prática
Responda às questões no seu caderno ou utilize os campos expansíveis para conferir a justificativa técnica de cada caso.
1. Por que o comando ALTER TABLE original para adicionar o CPF como NOT NULL falhou? Qual o comportamento interno do SGBD?
Ver explicação técnica
O SGBD recusa a operação porque a tabela já possuía registros. Ao adicionar uma nova coluna NOT NULL sem informar um valor padrão (DEFAULT), o motor do PostgreSQL tentaria preencher as linhas existentes com valor NULL, gerando uma violação instantânea de integridade. Para proteger os dados, o banco aborta a transação.
2. Explique a diferença crucial entre rodar um comando TRUNCATE e um comando DROP TABLE.
Ver explicação técnica
O TRUNCATE remove instantaneamente todos os registros da tabela liberando espaço em disco, mas preserva as colunas, tipos e restrições para novas inserções. O DROP TABLE destrói tanto os registros quanto a própria estrutura e dependências da tabela do dicionário de dados.
3. O que acontece se tentarmos cadastrar um cliente com 17 anos após aplicar a restrição CHECK (idade >= 18)?
Ver explicação técnica
O PostgreSQL interrompe o comando INSERT e retorna o erro violates check constraint "chk_maioridade". Nenhuma linha é inserida na tabela e a transação é cancelada para garantir a regra de negócio.
4. Se tivéssemos definido a Foreign Key com ON DELETE RESTRICT em vez de ON DELETE CASCADE, o que aconteceria ao tentar deletar uma empresa que possui clientes?
Ver explicação técnica
O SGBD bloquearia a exclusão da empresa e retornaria erro de violação de chave estrangeira, pois existem registros filhos (clientes) apontando para aquele registro pai. O administrador teria que remover ou reatribuir todos os clientes manualmente antes de conseguir deletar a empresa.
5. Qual é a desvantagem em aplicar Índices (CREATE INDEX) em todas as colunas de uma tabela sem critérios prévios?
Ver explicação técnica
Embora acelere consultas de leitura (SELECT), cada índice exige espaço adicional em disco e reduz a performance de operações de escrita (INSERT, UPDATE, DELETE), pois a estrutura de árvore B-Tree de cada índice precisa ser recalculada a cada alteração.
Terminal SQL Livre (Supabase Playground)
Use este espaço para praticar livremente comandos DDL (`CREATE TABLE`, `ALTER TABLE`, `DROP TABLE`, `TRUNCATE`, `CREATE INDEX`).
Snippets de Exemplo (Clique para carregar):
A Matriz da Destruição
No Supabase (PostgreSQL), remover dados ou tabelas inteiras exige o entendimento exato da diferença de impacto, velocidade e capacidade de rollback entre os três comandos de exclusão.
| Comando | Apaga Dados? | Apaga Estrutura? | Velocidade | Gera Log (Linha a Linha)? | Caso de Uso Recomendado |
|---|---|---|---|---|---|
| DELETE FROM | Sim (Filtro WHERE) | Não (Mantém gaveta) | Lenta (Linha por linha) | Sim (Seguro/Rollback) | Remover registros específicos com base em uma condição (`WHERE status = 'inativo'`). |
| TRUNCATE TABLE | Sim (TODOS os dados) | Não (Mantém colunas) | Ultra-Rápida (Reset) | Não (Limpa bloco inteiro) | Esvaziar uma tabela gigante instantaneamente mantendo as colunas para receber novos dados. "Botão de Pânico Otimizado". |
| DROP TABLE | Sim (Tudo) | Sim (Destrói a tabela) | Rápida | Não | Eliminar por completo a tabela e suas restrições do banco de dados (destruição total da gaveta). |
É como usar uma borracha para apagar item por item de uma folha de papel. Leva tempo, mas você escolhe exatamente o que apagar.
É como pegar uma folha cheia de texto e passar um corretivo cobrindo tudo instantaneamente: a folha continua existindo, mas fica limpa.
É como tacar fogo no papel e no arquivo. A folha e a pasta desaparecem do mapa.
Guia Rápido de DDL & Constraints em PostgreSQL / Supabase
Sintaxes essenciais ministradas na Aula 06 para consultar e utilizar nos exercícios.
Comandos ALTER TABLE
-- 1. Adicionar nova coluna ALTER TABLE clientes ADD COLUMN data_nascimento DATE; -- 2. Alterar tipo de dado da coluna ALTER TABLE clientes ALTER COLUMN cpf TYPE VARCHAR(14); -- 3. Remover coluna existente ALTER TABLE clientes DROP COLUMN apelido; -- 4. Definir valor padrão (DEFAULT) ALTER TABLE clientes ALTER COLUMN ativo SET DEFAULT true;
Restrições (CHECK & FK)
-- Restrição CHECK de Validação de Dados ALTER TABLE clientes ADD CONSTRAINT chk_maioridade CHECK (data_nascimento <= '2008-01-01'); -- Restrição Foreign Key com ON DELETE CASCADE ALTER TABLE pedidos ADD CONSTRAINT fk_cliente FOREIGN KEY (cliente_id) REFERENCES clientes(id) ON DELETE CASCADE;
Índices de Performance (CREATE INDEX)
-- Otimiza busca em tabelas com milhões de linhas CREATE INDEX idx_clientes_cpf ON clientes(cpf); -- Índice composto para múltiplas colunas CREATE INDEX idx_pedidos_cliente_data ON pedidos(cliente_id, data_pedido);
Solução da Armadilha NOT NULL
Ao tentar adicionar uma coluna NOT NULL em uma tabela que já possui dados cadastrados, o Supabase retornará erro pois as linhas antigas ficariam nulas.
Passos corretos de resolução:
- Adicionar a coluna sem NOT NULL, mas com um
DEFAULT 'valor'. - Ou atualizar os registros antigos com
UPDATE. - Aplicar o
ALTER COLUMN ... SET NOT NULLpor último.
Banco de Temas Práticos (32 Alunos)
Cada aluno deve selecionar (ou sortear) o seu número de chamada e resolver o cenário DDL correspondente no Supabase.