2009-02-09 16 views
9

¿Es cierto que MS SQL restringe las restricciones de autorreferencia con la opción ON DELETE CASCADE? Tengo una tabla con relación padre-hijo, la columna PARENT_ID es clave externa para ID. Creación con opción ON CASCADE DELETE causa de errorRestricción autorreferencial en MS SQL

Presentación de restricción FOREIGN KEY puede causar ciclos o múltiples en cascada caminos. Especifique en DELETE NO ACTION o ON UPDATE NO ACTION, o modificar otros restricciones FOREIGN KEY". "

No puedo creer que tenga que eliminar esta jerarquía en modo recursivo. ¿Hay algún problema, excepto los factores desencadenantes?

Respuesta

9

Es el caso que no se puede configurar ON DELETE CASCADE en una tabla con restricciones autorreferenciales. Existe un potencial de problemas de lógica cíclica, por lo tanto, no lo permitirá.

Hay un buen artículo here - aunque es para la versión 8 en lugar de 9 de SQL - aunque se aplican las mismas reglas.

+0

PostgreSQL lo soporta. Ahora, si otra entrada que no se va a eliminar hace referencia a una subinserción que se va a eliminar, emitirá un error y la operación de eliminación se revertirá. De lo contrario, funcionará perfectamente. El verdadero problema es si su relación padre-hijo es un gráfico dirigido no cíclico o no. Debido a que la mayoría de las autorreferencias implementan jerarquías, y las jerarquías deben dirigirse a gráficos no cíclicos, el curso de acción de PostgreSQL seguramente será más sensato en la mayoría de los casos. En todos los demás casos, puede implementar esa funcionalidad de forma manual, para que no se pierda nada. –

0
CREATE TRIGGER MyTable_OnDelete ON MyTable 
INSTEAD OF DELETE 
AS 
BEGIN 

    SET NOCOUNT ON; 

    DELETE FROM mt 
    FROM deleted AS D 
    JOIN MyTable AS mt 
    ON  d.Id = mt.ParentId 

    DELETE FROM mt 
    FROM deleted AS D 
    JOIN MyTable AS mt 
    ON  d.Id = mt.Id 

END 
+0

Lo sentimos pero en un caso si 'MyTable' está en relación con otra tabla (teniendo' ON DELETE CASCADE ...') no puede definir un disparador 'INSTEAD OF DELETE' ... – Bellash

4

acabo respondió another question donde esta pregunta estaba obligado como duplicado. Creo que también vale la pena colocar mi respuesta aquí:

Esto no es posible. Puede resolver esto con un INSTEAD OF TRIGGER

create table locations 
(
    id int identity(1, 1), 
    name varchar(255) not null, 
    parent_id int, 

    constraint pk__locations 
     primary key clustered (id) 

) 
GO 

INSERT INTO locations(name,parent_id) VALUES 
('world',null) 
,('Europe',1) 
,('Asia',1) 
,('France',2) 
,('Paris',4) 
,('Lyon',4); 
GO 

--Este gatillo utilizará un CTE recursiva para obtener todos los ID siguientes todos los identificadores que está eliminando. Estas identificaciones se eliminan.

CREATE TRIGGER dbo.DeleteCascadeLocations ON locations 
INSTEAD OF DELETE 
AS 
BEGIN 
    WITH recCTE AS 
    (
     SELECT id,parent_id 
     FROM deleted 

     UNION ALL 

     SELECT nxt.id,nxt.parent_id 
     FROM recCTE AS prv 
     INNER JOIN locations AS nxt ON nxt.parent_id=prv.id 
    ) 
    DELETE FROM locations WHERE id IN(SELECT id FROM recCTE); 
END 
GO 

- Pruébalo aquí, prueba con diferentes ID. Usted puede tratar de WHERE id IN(4,3) también ...

SELECT * FROM locations; 

DELETE FROM locations WHERE id=4; 

SELECT * FROM locations 
GO 

--clean-Up (Carefull con datos reales!)

if exists(select 1 from INFORMATION_SCHEMA.TABLES where TABLE_NAME='locations') 
---DROP TABLE locations; 
+0

Tengo una tabla que se refiere a sí misma hasta tres niveles de profundidad, hizo extensas pruebas con esto y funciona perfectamente. Muchas gracias! – vaindil