Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🔒 CAPÍTULO 12: RESTRIÇÕES DE INTEGRIDADE E CONSTRAINTS

As restrições (Constraints) são as muralhas do seu banco de dados. Elas garantem que os dados inseridos no banco sigam as regras de negócio rigorosas e mantenham a consistência da informação, impedindo que a aplicação salve um preço negativo ou um cliente sem CPF. 🛡️🧩


🎯 Objetivo Curricular

Dominar as restrições de integridade (NOT NULL, UNIQUE, DEFAULT, CHECK) e as Ações Referenciais em Chaves Estrangeiras (CASCADE, RESTRICT) para blindar o banco de dados contra lixo digital.


🏢 O Cenário Prático (Seu Desafio)

A equipe de auditoria da TecProExpress encontrou anomalias gravíssimas na base de testes: existiam produtos cadastrados com peso negativo, motoristas cadastrados com a mesma placa de CNH e registros vazios.

"Seu desafio é reescrever a DDL do sistema de transportes adicionando Constraints (Restrições) diretas no motor SQL. Se um programador tentar inserir um pacote com peso de -5 kg, o SGBD deve cuspir um erro de volta na cara da aplicação antes mesmo do dado chegar no disco!"


🧠 Fundamentos: O Arsenal de Defesa (Constraints)

Você já usou a restrição máxima (PRIMARY KEY), mas o DDL nos fornece ferramentas mais granulares:

ConstraintFunção de DefesaExemplo Prático
NOT NULLO campo é obrigatório.Nenhum usuário sem Nome.
DEFAULTValor automático se ninguém enviar nada.Cliente novo entra com status Ativo por padrão.
UNIQUEImpede valor repetido (mas aceita NULL).O E-mail da conta de acesso.
CHECKValidações matemáticas e lógicas.O frete deve ser sempre >= 0.

📖 Exemplo Guiado: O DDL Blindado (Regras de Negócio)

Vamos criar a tabela de "Frete" da TecProExpress com uma armadura pesada de validações.

🛠️ Código do Exemplo

-- PASSO 1: DDL (Criando a Tabela Blindada)
CREATE TABLE frete_blindado (
    id INT PRIMARY KEY,
    codigo_rastreio CHAR(10) UNIQUE NOT NULL, -- Obrigatório e Exclusivo
    peso_kg DECIMAL(5,2) CHECK (peso_kg > 0), -- A regra de ouro da auditoria
    data_registro DATE DEFAULT CURRENT_DATE,  -- Se omitido, pega o dia de hoje
    status VARCHAR(20) DEFAULT 'PENDENTE'
);

-- PASSO 2: DML (Carga de Sucesso)
-- Omitimos a data e o status para ver o DEFAULT agir!
INSERT INTO frete_blindado (id, codigo_rastreio, peso_kg) 
VALUES (1, 'AB12345678', 15.50);

-- PASSO 3: DML (A Carga que VAI FALHAR - Teste o CHECK)
-- Descomente e rode. O banco VAI recusar a inserção por causa do peso negativo.
-- INSERT INTO frete_blindado (id, codigo_rastreio, peso_kg) VALUES (2, 'XY99999999', -2.00);

🔍 Detalhamento do Código:

  • DEFAULT CURRENT_DATE: Uma função nativa. Se a aplicação de frontend esquecer de mandar a data, o próprio banco preenche.
  • CHECK (peso_kg > 0): A parede intransponível. A aplicação Node.js ou Python vai receber um erro "Constraint Violation" caso tente registrar peso negativo. O banco de dados nunca confia no Frontend!

🔗 Ações Referenciais em Chaves Estrangeiras (FK)

A Chave Estrangeira não serve apenas para "vincular". Ela define o que acontece quando alguém apaga o dado PAI.

  • RESTRICT (Padrão): O SGBD proíbe a deleção do Cliente se ele tiver Pacotes no sistema.
  • CASCADE: Se você deletar o Cliente, o SGBD deleta todos os Pacotes dele junto. (Use com extrema sabedoria).
  • SET NULL: Deleta o Cliente e deixa os Pacotes órfãos (com ID NULL). Útil se você não quer apagar o histórico de transporte, mas o cliente cancelou a conta.

📊 Fluxo da Chave Estrangeira

flowchart TD
    DEL["❌ Ação: DELETE FROM Cliente WHERE id=10"] --> SGBD{"⚙️ Motor de FK"}
    SGBD -- "RESTRICT" --> B1["⛔ ERRO: Ação Bloqueada"]
    SGBD -- "CASCADE" --> B2["🔥 Deleção em Massa (Cliente e Pacotes)"]
    SGBD -- "SET NULL" --> B3["🧹 Apaga o Cliente. Atualiza Pacotes para NULL"]

🛠️ Prática Obrigatória: Nomeando as Muralhas

Cenário: Facilitando o debug do desenvolvedor. Se você não der um nome para o seu CHECK, o banco cria um nome feio (ex: SYS_C0015). Veja como nomear sua restrição para o log de erro ficar legível.

  1. Crie a tabela de funcionario com um CHECK de salário nomeado como chk_salario_minimo.

🚀 Script de Seed (Gabarito de Nomenclatura)

-- DDL
CREATE TABLE funcionario (
    id INT PRIMARY KEY,
    nome VARCHAR(100),
    salario DECIMAL(10,2),
    
    -- O 'CONSTRAINT' antes da regra permite batizá-la!
    CONSTRAINT chk_salario_minimo CHECK (salario >= 1412.00)
);

-- DML (Essa linha falha e o erro vai explicitar o nome 'chk_salario_minimo')
-- INSERT INTO funcionario VALUES (1, 'João', 1000.00);

📤 Instruções de Entrega (Microsoft Teams)

Após validar seus códigos práticos e de estudo:

Use o operador e para critérios rigorosos e ou para critérios flexíveis. Salve os arquivos com a extensão .sql (Ex: Atividade_XX_SeuNome.sql ou Atividade_XX_SeuNome.png ou Atividade_XX_SeuNome.drawio


💡 Checkpoint de Lógica

[!TIP] Dica do Especialista: Uma arquitetura de dados sênior deve sempre possuir uma "Defesa em Profundidade" (Defense in Depth). Não é porque a linguagem de programação no frontend tem um "IF" bloqueando pesos negativos que o banco de dados deve aceitar qualquer coisa. A Constraint é o goleiro do seu time: se a defesa do código falhar, o goleiro do banco espalma a bola! 🚀🛡️