Imagina que você criou um banco de dados com uma tabela de clientes (customers) e outra de pedidos (orders) relacionada a ela. Só que aí bate a dúvida: o que fazer se um cliente for removido da tabela customers? Os pedidos desse cliente também devem ser apagados ou vão ficar "órfãos", apontando pra um cliente que nem existe mais? E se você quiser mudar o ID do cliente? É aí que entram as operações em cascata (CASCADE) e as restrições (RESTRICT) pra controlar o comportamento do banco.
ON DELETE CASCADE é um esquema que apaga automaticamente os registros relacionados quando você deleta um registro da tabela principal. Ou seja, se você deletar um cliente, todos os pedidos ligados a ele também vão embora.
Funciona assim: quando você coloca ON DELETE CASCADE na definição da foreign key, o banco "saca" que o registro relacionado tem que ser apagado junto.
Exemplo
Vamos supor que temos duas tabelas: customers e orders. Os clientes (customers) podem fazer vários pedidos (orders), ou seja, é uma relação ONE-TO-MANY. Queremos que, quando um cliente for deletado, todos os pedidos dele também sejam apagados.
-- Criando a tabela de clientes
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Criando a tabela de pedidos com foreign key apontando pra tabela de clientes
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE,
order_date DATE NOT NULL
);
Inserindo dados nas tabelas
-- Inserindo dados na tabela de clientes
INSERT INTO customers (name) VALUES ('Ivan'), ('Anna');
-- Inserindo dados na tabela de pedidos
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2023-10-01'),
(1, '2023-10-02'),
(2, '2023-10-03');
Tabela orders:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | 1 | 2023-10-01 |
| 2 | 1 | 2023-10-02 |
| 3 | 2 | 2023-10-03 |
Deletando um cliente e vendo o que rola
-- Deletando o cliente com ID 1
DELETE FROM customers WHERE customer_id = 1;
-- Conferindo o que sobrou na tabela de pedidos
SELECT * FROM orders;
| order_id | customer_id | order_date |
|---|---|---|
| 3 | 2 | 2023-10-03 |
Como dá pra ver, os pedidos ligados ao cliente deletado também foram apagados.
Restringindo alterações: ON UPDATE RESTRICT
ON UPDATE RESTRICT serve pra impedir que você altere um valor na tabela principal se tiver registro na tabela filha apontando pra ele. É tipo um "escudo" que barra mudanças que podem bagunçar a integridade dos dados.
Como funciona? Quando você coloca ON UPDATE RESTRICT, o banco não deixa atualizar a chave na tabela principal se ela estiver sendo usada na tabela filha.
Exemplo
Vamos usar as mesmas tabelas customers e orders, mas agora vamos colocar a restrição de update na foreign key.
-- Recriando a tabela de pedidos com restrição de update
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
Tentando atualizar o ID do cliente
-- Tentando mudar o ID do cliente de 2 pra 5
UPDATE customers
SET customer_id = 5
WHERE customer_id = 2;
Resultado:
ERROR: update or delete on table "customers" violates foreign key constraint
DETAIL: Key (customer_id)=(2) is still referenced from table "orders".
Como você viu, o banco deu erro porque mudar a chave ia quebrar a ligação entre as tabelas.
Mais detalhes sobre UPDATE e suas tretas eu conto no próximo nível :P
Juntando ON DELETE CASCADE e ON UPDATE RESTRICT
Claro que dá pra misturar operações em cascata (CASCADE) e restrições (RESTRICT). Por exemplo, você pode configurar pra apagar automaticamente os dados relacionados quando deletar o registro principal (ON DELETE CASCADE), mas bloquear a alteração do ID dele (ON UPDATE RESTRICT) pra evitar confusão.
Exemplo
Vamos criar de novo a tabela de pedidos, agora usando os dois esquemas:
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
Agora:
- Se você deletar um cliente, todos os pedidos dele vão ser apagados.
- Se tentar mudar o ID do cliente, vai tomar erro.
Por que isso é importante na vida real?
Usar CASCADE e RESTRICT é muito importante em sistemas grandes com várias tabelas relacionadas. Por exemplo:
Num e-commerce, o cliente pode ter pedidos. Se o cliente quiser deletar o perfil, você não vai querer deixar pedidos na base que não apontam pra ninguém. É aí que ON DELETE CASCADE salva o rolê.
Ao mesmo tempo, você pode querer evitar mudanças acidentais em chaves únicas pra não quebrar as relações entre as tabelas. Pra isso, ON UPDATE RESTRICT é perfeito.
GO TO FULL VERSION