2010-07-19 13 views
5

Quiero eliminar filas de dos tablas que dependen una de la otra a través de un conjunto de restricciones diferibles. Para simplificar esta publicación, me he burlado de un simple esquema DB.PostgreSQL 'Deferrable Delete' aún golpea la restricción en Delete

Espero eliminar las entradas de alguna tabla, 'delete_from_me', dentro de una transacción SQL/Parche DB. El truco es, quiero eliminar basado en una selección de una segunda tabla 'constraining_table' antes de perder el enlace.

He aquí una descripción de las dos tablas:

tab-quarantine=> \d delete_from_me 
     Table "public.delete_from_me" 
    Column |  Type  | Modifiers 
-----------+-------------------+----------- 
id  | character varying | not null 
extension | character varying | not null 
Indexes: 
    "delete_from_me_pkey" PRIMARY KEY, btree (id) 

tab-quarantine=> \d constraining_table 
    Table "public.constraining_table" 
Column |  Type  | Modifiers 
--------+-------------------+----------- 
image | character varying | not null 
type | character varying | not null 
Foreign-key constraints: 
    "constraining_table_image_fkey" FOREIGN KEY (image) REFERENCES delete_from_me(id) 
     ON UPDATE CASCADE 
     ON DELETE RESTRICT DEFERRABLE 

He aquí algunos datos de ejemplo que acabo de blatted allí:

tab-quarantine=> SELECT * FROM delete_from_me; 
    id  | extension 
------------+----------- 
12345abcde | png 
(1 row) 

tab-quarantine=> SELECT * FROM constraining_table; 
    image | type 
------------+---------- 
12345abcde | select_me 
(1 row) 

Y aquí va mi transacción:

BEGIN; 
\set ON_ERROR_STOP 1 
SET CONSTRAINTS ALL DEFERRED; 
DELETE FROM delete_from_me WHERE id IN (
    SELECT image FROM constraining_table WHERE type = 'select_me' 
); 
DELETE FROM constraining_table WHERE type = 'select_me'; 
COMMIT; 

Este la transacción falla Cuando me paso a través y hacerlo de forma manual, me presentan con el siguiente mensaje de error:

ERROR: update or delete on table "delete_from_me" violates foreign key constraint "constraining_table_image_fkey" on table "constraining_table" 
DETAIL: Key (id)=(12345abcde) is still referenced from table "constraining_table". 

Este parece ser un buen candidato para una tabla temporal, sin embargo, me gustaría saber por qué es que No puedo eliminar en este orden dado que las restricciones no deberían ser efectivas hasta el final de la transacción.

Respuesta

6

Use ON DELETE NO ACTION DEFERRABLE en lugar de ON DELETE RESTRICT DEFERRABLE. El uso de RESTRICT en lugar de NO ACTION fuerza a la restricción a no ser diferible, independientemente de si aplica el modificador DEFERRABLE.

Esto está en la letra pequeña de la manual page for CREATE TABLE:

acciones referenciales que no sea el NO cheque acción no puede ser diferida, incluso si la restricción se declara diferible.

Obviamente, la advertencia anterior incluye RESTRICT.

que sigue poco después de esta frase son las definiciones de NO ACTION y RESTRICT:

NO ACTION

producir un error que indica que la supresión o actualización crearían una violación de restricción de clave externa. Si se difiere la restricción, este error se producirá en el tiempo de comprobación de restricciones si todavía existen filas de referencia. Esta es la acción por defecto.

RESTRICT

producir un error que indica que la supresión o actualización crearían una violación de restricción de clave externa. Esto es lo mismo que NO HAY ACCIÓN, excepto que el cheque no es diferible.

Como se puede ver, NO ACTION se comportará de forma idéntica a RESTRICT, excepto NO ACTION es prorrogable. Es por eso que lo recomendé, creo que es justo lo que estás pidiendo.