Boa explicação do comportamento em cascata (ON DELETE / UPDATE)


98

Não desenho esquemas todos os dias, mas quando o faço, tento configurar as atualizações / exclusões em cascata corretamente para facilitar a administração. Entendo como as cascatas funcionam, mas nunca consigo me lembrar de qual tabela é qual.

Por exemplo, se eu tiver duas tabelas - Parente Child- com uma chave estrangeira nessas Childreferências Parente tiver ON DELETE CASCADE, quais registros acionam uma cascata e quais são excluídos pela cascata? Meu primeiro palpite seria que os Childregistros sejam excluídos quando os Parentregistros forem excluídos, pois os Childregistros dependem dos Parentregistros, mas isso ON DELETEé ambíguo; isso pode significar excluir o Parentregistro quando o Childregistro for excluído ou pode excluir o Childregistro quando ele Parentfor excluído. Então qual é?

Eu gostaria que a sintaxe fosse ON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADEou algo semelhante, para remover a ambiguidade. Alguém tem alguma mnemônica para lembrar disso?

Respostas:


138

Se você gosta de Parente Childtermos e você sente que eles são fáceis de ser lembrado, você pode gostar da tradução ON DELETE CASCADEdaLeave No Orphans!

O que significa que, quando uma Parentlinha é excluída (eliminada), nenhuma linha órfã deve permanecer viva na Childtabela. Todos os filhos da linha pai também são mortos (excluídos). Se algum desses filhos tiver netos (em outra tabela através de outra chave estrangeira) e houver alguma ON DELETE CASCADEdefinição, eles também deverão ser mortos (e todos os descendentes, desde que haja um efeito em cascata definido).

A FOREIGN KEYrestrição em si também pode ser descrita como Allow No Orphans!(em primeiro lugar). Nunca Childdeve ser permitido (escrito) na tabela filho, se não houver um Parent(uma linha na tabela pai).

Por consistência, o ON DELETE RESTRICTpode ser convertido para o (menos agressivo) You Can't Kill Parents!Somente as linhas sem filhos podem ser eliminadas (excluídas.)


3
Sinto que ainda falta alguma analogia. Uma criança não pode ter mais de um pai ou mãe? Nesse caso, matar um dos pais tornará a criança órfã?
Jus12

7
@ Jus12 Não, as restrições de chave estrangeira funcionam apenas com 1 pai. Não é uma boa analogia sobre esse aspecto.
ypercubeᵀᴹ

1
@ ypercube: isso não é permitido? Order(custID, itemID, orderID)onde custIDrefere-se a uma chave primária na Customerstabela e itemIDrefere-se a uma chave primária na Itemstabela. Não vai Orderter dois pais?
Jus12

4
@ Jus12 Isso é permitido, é claro, mas seriam duas restrições de chave estrangeira. Então todo filho (pedido) teria um pai (cliente) e um pai (item). Os comportamentos dos 2 FKs podem diferir. (Assim, por exemplo, pode ser que os clientes matando mataria todos os seus (ordens) crianças, mas itens matando não mataria seus pedidos.)
ypercubeᵀᴹ

1
A analogia dos pais ainda pode funcionar se não dissermos "órfão". Se houver duas referências a dois pais separados em uma entrada de filhos, isso ainda poderá ser visto como filho de um casal divorciado. Restringir: "Eu não vou deixar você matar minha mãe" Cascade: "Se você matar meu pai, eu também vou morrer"
Christopher McGowan

31

Por exemplo, se eu tiver duas tabelas - pai e filho - em que os registros filhos pertencem aos registros pai, qual tabela precisa do ON DELETE CASCADE?

ON DELETE CASCADE é uma cláusula opcional em uma declaração de chave estrangeira. O mesmo acontece com a declaração de chave estrangeira. (Significado, na tabela "filho").

... pode significar excluir o registro pai quando o registro filho for excluído ou pode significar excluir o registro filho quando o pai for excluído. Então qual é?

Uma maneira de interpretar uma declaração de chave estrangeira é: "Todos os valores válidos para esta coluna vêm de 'that_column' em 'that_table'." Quando você exclui uma linha da tabela "filho", ninguém se importa. Não afeta a integridade dos dados.

Quando você exclui uma linha da tabela "pai" - de "essa tabela" - você remove um valor válido dos valores possíveis para a tabela "filho". Para manter a integridade dos dados, você deve fazer algo na tabela "filho". Exclusões em cascata é uma coisa que você pode fazer.


2

SQL: 2011 Especificações

Existem cinco opções para ON DELETE, e ON UPDATEque podem ser aplicadas ao FOREIGN KEY. Eles são chamados <referential actions>diretamente da especificação SQL: 2011

  • ON DELETE CASCADE: se uma linha da tabela referenciada for excluída, todas as linhas correspondentes na tabela de referência serão excluídas.
  • ON DELETE SET NULL: se uma linha da tabela referenciada for excluída, todas as colunas de referência em todas as linhas correspondentes da tabela de referência serão definidas como nulas.
  • ON DELETE SET DEFAULT: se uma linha da tabela referenciada for excluída, todas as colunas de referência em todas as linhas correspondentes da tabela de referência serão definidas como o valor padrão da coluna.
  • ON DELETE RESTRICT: é proibido excluir uma linha da tabela referenciada se essa linha tiver alguma linha correspondente na tabela de referência.
  • ON DELETE NO ACTION (o padrão) : não há ação de exclusão referencial; a restrição referencial especifica apenas uma verificação de restrição.

A chave estrangeira estabelece o relacionamento dependente. O <referential action>determina o que acontece quando o relacionamento é dissolvido.

Exemplo / Metáfora / Explicação

Para este exemplo, aceitaremos o modelo comum de sociedade e economia: onde toda businessempresa é uma empresa que mantém um relacionamento com o bourgeoisiemeio a fatcat_owner.

CREATE TABLE bourgeoisie(
  fatcat_owner varchar(100) PRIMARY KEY
);
INSERT INTO bourgeoisie(fatcat_owner) VALUES
  ( 'Koch Brothers' );

CREATE TABLE business (
  name         varchar(100),
  fatcat_owner varchar(100) REFERENCES bourgeoisie
);
INSERT INTO business(name, fatcat_owner)
  VALUES ('Georgia-Pacific', 'Koch Brothers');

Se todas as businesses são diretamente afetadas pelas bourgeoisiesuas fatcat_ownerações, o que você faz após a revolução dos trabalhadores quando expurga fatcat_ownere tem uma sociedade sem classes?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;

Você tem algumas opções aqui,

  • Pare a revolução. Na linguagem SQL RESTRICT,. Algumas pessoas acreditam que este é o mal menor, mas geralmente estão erradas.
  • Permita que continue. Nesse caso, quando a revolução acontece, o SQL oferece quatro opções,

    • SET NULL-- deixe em branco. Quem sabe, talvez o capitalismo seja restaurado, o bourgeoisiesurgimento e os oligarcas enchem o papel do fatcat_owners. Nota importante, a coluna deve ser NULLABLE(não NOT NULL) ou isso nunca pode acontecer.
    • SET DEFAULT- talvez você tenha DEFAULTlidado com isso? A DEFAULTpode chamar uma função. Talvez seu esquema já esteja pronto para a revolução.
    • CASCADE- não há controle de danos. Se bourgeoisiefor, o mesmo acontece com o business. Se uma empresa precisa ter um fatcat_pig, às vezes faz mais sentido perder os dados do que ter uma empresa não em uma businesstabela.
    • NO ACTION- este é essencialmente um método de atrasar a verificação, no MySQL não é diferente RESTRICT, mas no PostgreSQL, você seria capaz de fazer

      -- Not a real revolution.
      -- requires constraint be DEFERRABLE INITIALLY DEFERRED
      BEGIN;
        SET CONSTRAINTS ALL DEFERRED;
        DELETE FROM bourgeoisie;
        INSERT INTO bourgeoisie VALUES ( 'Putin' );
        UPDATE business SET fatcat_pig = 'Putin';
      END;

      Nesse sistema, a restrição é validada apenas antes da transação ser confirmada. Isso pode resultar em parar a revolução, mas você pode se recuperar na transação - por algum grau de "recuperação".


Será que referencedas tabelas significa tabela pai e referencingmesa significa tabela filho?
SG552

@ sg552 Sim, você entendeu corretamente.
informatik01

1

Um simples mnemônico seria

ON DELETE do CASCADE pai [excluindo] aqui

Isso indica quais exclusões (exclusões do pai) são colocadas em cascata, para onde vai a instrução ON DELETE CASCADE (no filho) e o que é excluído (o filho).


-3

bem, talvez possamos racionalizar a sintaxe. Vamos dar um exemplo de Python:

class Parent(self):
    # define parent's fields

class Child(self):    
    # define child's fields
    parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.CASCADE)

o que esta linha diz ser on_delete do pai (que é acidentalmente mencionado na declaração), faça a cascata da exclusão no filho. É por isso que a instrução CASCADE é definida no nível filho, marca os filhos que precisam ser excluídos

Por exemplo, se você tivesse outra aula

class GrownUpChild(self):    
        # define grown up child's fields
        parent_pk_is_childs_foreign_key = models.ForeignKey(Parent, on_delete=models.DO_NOTHING)

essa estrutura mostraria claramente quais das crianças precisam ser removidas (Criança) e quais devem permanecer (GrownUpChild), embora órfãs

[Edit: Dado o contexto da discussão, especificamente nos casos de on_delete = models.CASCADE etc,] na verdade, geralmente é um comportamento desejado deixar os filhos de um pai excluído, devido a razões de auditoria e relatório, além de recuperar dados acidentais. exclusões. [é claro que o software em nível corporativo será construído em torno desse comportamento e sinalizará os registros excluídos como excluídos = 1, em vez de excluí-los, e também não os incluirá em nenhuma consulta para o front end, menos alguns relatórios especialmente projetados. Além disso, ele terá a função de remover os registros == 1 excluídos do banco de dados, que geralmente serão executados pelo administrador da interface do usuário, evitando frequentemente qualquer envolvimento por parte do administrador do banco de dados.]


1
“De fato, é geralmente um comportamento desejado deixar os filhos de um pai ou mãe excluído, devido a razões de auditoria e geração de relatórios, além de recuperar exclusões acidentais” - isso seria desastroso em um banco de dados (sadio).
Dez18

@dezso obrigado pela sua contribuição. No entanto, vários sistemas de CRM de nível empresarial fazem exatamente isso.
George Mogilevsky

TBH que não a torna mais sensata. Certa vez, recebi uma tarefa para consertar as merdas resultantes dessa abordagem - sem alegria, exceto o salário.
Dez24

você soa como um administrador de banco de dados experiente :) Eu posso ouvir totalmente o seu ponto. O software que mencionei acima, na verdade, possui uma função para remover manualmente os excluídos = 1, portanto, cabe ao administrador do aplicativo fazer essa chamada. Normalmente, o administrador do banco de dados nem mesmo está envolvido na manutenção desse aspecto. E, além disso, a classe de banco de dados de todo o software é construído em torno do conceito, por isso sempre verifica para Excluído bandeira em operações CRUD
George Mogilevsky

Sim, esse é um padrão conhecido e sensato - mas você deve alterar as palavras acima para refletir isso.
Dezso
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.