Buena explicación del comportamiento en cascada (EN ELIMINAR / ACTUALIZAR)

98

No diseño esquemas todos los días, pero cuando lo hago, trato de configurar las actualizaciones / eliminaciones en cascada correctamente para facilitar la administración. Entiendo cómo funcionan las cascadas, pero nunca puedo recordar qué tabla es cuál.

Por ejemplo, si tengo dos tablas - Parenty Child- con una clave foránea en Childesas referencias Parenty has ON DELETE CASCADE, ¿qué registros desencadenan una cascada y qué registros son eliminados por la cascada? Mi primera suposición sería que los Childregistros se eliminan cuando Parentse eliminan, ya que los Childregistros dependen de los Parentregistros, pero ON DELETEes ambiguo; podría significar eliminar el Parentregistro cuando Childse elimine el registro, o podría significar eliminar el Childregistro cuando Parentse elimine. Entonces, ¿cuál es?

Desearía que la sintaxis fuera ON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADEo algo similar para eliminar la ambigüedad. ¿Alguien tiene alguna mnemotecnia para recordar esto?

Johntron
fuente

Respuestas:

138

Si te gusta las Parenty los Childtérminos y sientes que son fáciles de recordar, que le gustará la traducción de ON DELETE CASCADEaLeave No Orphans!

Lo que significa que cuando Parentse elimina (elimina) una fila, ninguna fila huérfana debe permanecer viva en la Childtabla. Todos los elementos secundarios de la fila principal también se eliminan (eliminan). Si alguno de estos hijos tiene nietos (en otra tabla a través de otra clave externa) y está ON DELETE CASCADEdefinido, estos también deberían ser eliminados (y todos los descendientes, siempre que haya un efecto de cascada definido).

La FOREIGN KEYrestricción en sí misma también podría describirse como Allow No Orphans!(en primer lugar). Nunca se Childdebe permitir (escribir) en la tabla secundaria si no tiene una Parent(una fila en la tabla primaria).

Por coherencia, ON DELETE RESTRICTse puede traducir al (menos agresivo). You Can't Kill Parents!Solo se pueden eliminar (eliminar) las filas sin hijos.

ypercubeᵀᴹ
fuente
3
Siento que todavía falta algo en la analogía. ¿No puede un niño tener más de un padre? En este caso, ¿matar a uno de los padres hará que el niño quede huérfano?
Jus12
77
@ Jus12 No, las restricciones de clave externa funcionan solo con 1 padre. No es una buena analogía con respecto a este aspecto.
ypercubeᵀᴹ
1
@ypercube: ¿No está permitido? Order(custID, itemID, orderID)donde se custIDrefiere a una clave primaria en la Customerstabla y se itemIDrefiere a una clave primaria en la Itemstabla. ¿No Ordertendrá dos padres?
Jus12
44
@ Jus12 Eso está permitido, por supuesto, pero serían 2 restricciones de clave externa. Entonces cada hijo (pedido) tendría un padre (cliente) y un padre (artículo). Sin embargo, los comportamientos de las 2 FK pueden diferir. (Entonces, por ejemplo, podría ser que matar clientes mataría a todos sus (pedidos) hijos, pero matar artículos no mataría sus órdenes.)
ypercubeᵀᴹ
1
La analogía principal todavía puede funcionar si no decimos "huérfano". Si hay dos referencias a dos padres separados en la entrada de un niño, todavía se puede ver como un hijo de una pareja divorciada. Restringir: "No dejaré que mates a mi mamá" Cascada: "Si matas a mi papá, también moriré"
Christopher McGowan
31

Por ejemplo, si tengo dos tablas, Principal y Secundario, donde los registros secundarios son propiedad de los registros principales, ¿qué tabla necesita la CASCADA ELIMINAR?

ON DELETE CASCADE es una cláusula opcional en una declaración de clave foránea. Entonces va con la declaración de clave extranjera. (Es decir, en la tabla "hijo").

... podría significar eliminar el registro principal cuando se elimina el registro secundario, o podría significar eliminar el registro secundario cuando se elimina el principal. Entonces cual es?

Una forma de interpretar una declaración de clave externa es: "Todos los valores válidos para esta columna provienen de 'that_column' en 'that_table'". Cuando elimina una fila en la tabla "secundaria", a nadie le importa. No afecta la integridad de los datos.

Cuando elimina una fila de la tabla "primaria" - de "esa_tabla" - elimina un valor válido de los posibles valores para la tabla "secundaria". Para mantener la integridad de los datos, debe hacer algo en la tabla "secundaria". La eliminación en cascada es una cosa que puede hacer.

Mike Sherrill 'Retiro del gato'
fuente
2

SQL: 2011 Spec

Hay cinco opciones para ON DELETE, y ON UPDATEeso puede aplicarse a FOREIGN KEY. Estos se llaman <referential actions>, directamente desde la especificación SQL: 2011

  • ON DELETE CASCADE: si se elimina una fila de la tabla referenciada, se eliminan todas las filas coincidentes en la tabla de referencia.
  • ON DELETE SET NULL: si se elimina una fila de la tabla referenciada, todas las columnas de referencia en todas las filas coincidentes de la tabla de referencia se establecerán como nulas.
  • ON DELETE SET DEFAULT: si se elimina una fila de la tabla referenciada, todas las columnas de referencia en todas las filas coincidentes de la tabla de referencia se establecerán en el valor predeterminado de la columna.
  • ON DELETE RESTRICT: está prohibido eliminar una fila de la tabla referenciada si esa fila tiene filas coincidentes en la tabla de referencia.
  • ON DELETE NO ACTION (el valor predeterminado) : no hay acción de eliminación referencial; la restricción referencial solo especifica una verificación de restricción.

La clave foránea establece la relación dependiente. El <referential action>determina lo que sucede cuando la relación se disuelve.

Ejemplo / Metáfora / Explicación

Para este ejemplo, aceptaremos el modelo común de sociedad y economía: donde cada businessuna es una compañía que mantiene una relación a bourgeoisietravés de 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');

Si todos los businesses afectados directamente por bourgeoisieellos fatcat_owner, ¿qué haces después de la revolución obrera cuando purgas el fatcat_owners y tienes una sociedad sin clases?

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

Tienes algunas opciones aquí,

  • Paren la revolución. En el lenguaje SQL, RESTRICT. Algunas personas creen que este es el mal menor, pero generalmente están equivocados.
  • Permitir que continúe. Si es así cuando sucede la revolución, SQL te da cuatro opciones,

    • SET NULL-- dejalo en blanco. Quién sabe, tal vez se restablezca el capitalismo bourgeoisiey surjan los oligarcas fatcat_owners. Nota importante, la columna debe ser NULLABLE(no NOT NULL) o esto nunca puede suceder.
    • SET DEFAULT- tal vez tuviste un DEFAULTque manejó esto? A DEFAULTpuede llamar a una función. Quizás tu esquema ya esté listo para la revolución.
    • CASCADE- No hay control de daños. Si el bourgeoisieva, también lo hace el business. Si una empresa debe tener un fatcat_pig, entonces a veces tiene más sentido perder los datos en lugar de tener una no empresa en una businesstabla.
    • NO ACTION- esto es esencialmente un método para retrasar la verificación, en MySQL no es diferente RESTRICT, pero en PostgreSQL, podría hacer

      -- 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;
      

      En dicho sistema, la restricción se valida solo antes de que se confirme la transacción. Esto puede resultar en detener la revolución, pero puede recuperarse en la transacción, hasta cierto punto de "recuperación".

Evan Carroll
fuente
¿ referencedTabla significa tabla primaria y referencingtabla significa tabla secundaria?
sg552
@ sg552 Sí, lo entendiste correctamente.
informatik01
0

Una simple mnemónica sería

AL ELIMINAR la CASCADA principal [al eliminar] aquí

Eso le indica qué eliminaciones (eliminaciones del padre) se ponen en cascada, dónde va la instrucción ON DELETE CASCADE (en el hijo) y qué se elimina (el hijo).

msouth
fuente
-3

bueno, quizás podamos racionalizar la sintaxis. Tomemos un ejemplo 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)

lo que dice esta línea es on_delete del Parent (que se menciona accidentalmente en la declaración), por favor, elimine en cascada al niño. Es por eso que la declaración CASCADE se define en el nivel secundario, marca aquellos elementos secundarios que deben eliminarse

Por ejemplo si tuvieras otra clase

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

esta estructura mostraría claramente cuáles de los niños necesitan ser eliminados (Niño) y cuáles deben permanecer (GrownUpChild) aunque huérfanos

[Editar: dado el contexto de la discusión, específicamente en casos de on_delete = models.CASCADE, etc.,] de hecho, a menudo es un comportamiento deseado dejar a los hijos de un padre eliminado, debido a razones de auditoría e informes, así como a la recuperación accidental eliminaciones [por supuesto, el software de nivel empresarial se creará en torno a dicho comportamiento y marcará los registros eliminados como eliminados = 1 en lugar de eliminarlos realmente y tampoco los incluirá en ninguna consulta para el front-end, menos algunos informes especialmente diseñados. Además, tendrá la función de purgar los registros eliminados == 1 de la base de datos, que generalmente será ejecutado por el administrador de la interfaz de usuario, a menudo evitando cualquier participación del lado del administrador de la base de datos.]

George Mogilevsky
fuente
1
"De hecho, a menudo es un comportamiento deseado dejar a los hijos de un padre eliminado, debido a razones de auditoría e informes, así como recuperar eliminaciones accidentales" , eso sería desastroso en una base de datos (sana).
dezso
@dezso gracias por tu aporte. Sin embargo, varios sistemas CRM de nivel empresarial hacen exactamente eso.
George Mogilevsky
TBH que no lo hace más sensible. Una vez recibí una asignación para arreglar la mierda resultante de tal enfoque, sin alegría, excepto el cheque de pago.
dezso
suenas como un administrador de base de datos inteligente :) Puedo escuchar totalmente tu punto. El software que mencioné anteriormente que lo hace, en realidad tiene una función para eliminar los eliminados = 1 manualmente, por lo que corresponde al administrador de la aplicación hacer esta llamada. Normalmente, el administrador de la base de datos ni siquiera participa en el mantenimiento de este aspecto. Y además, toda la clase de base de datos del software se basa en el concepto, por lo que siempre verifica si hay una marca eliminada en las operaciones de crud
George Mogilevsky
Sí, ese es un patrón conocido y sensato, pero posiblemente debas cambiar la redacción anterior para reflejar esto.
dezso