Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Sur la cascade de suppression pour la table d'auto-référence

En supposant que vous conserviez votre FOREIGN KEY contrainte en place, vous ne pouvez pas résoudre le problème dans un FOR DELETE gâchette. FOR déclencheurs (également appelés AFTER déclencheurs) se déclenchent après l'activité a eu lieu. Et une clé étrangère empêchera une ligne d'être supprimée si elle contient des références. Les vérifications de clé étrangère ont lieu avant suppression.

Ce dont vous avez besoin est un INSTEAD OF gâchette. Vous devez également garder à l'esprit que votre déclencheur actuel n'a essayé de traiter qu'un "niveau" de référencement. (Donc, si la ligne 3 fait référence à la ligne 2 et que la ligne 2 fait référence à la ligne 1, et que vous supprimez la ligne 1, votre déclencheur n'a essayé de supprimer que la ligne 2)

Donc, quelque chose comme :

CREATE TRIGGER [dbo].[T_comment_Trigger]
    ON [dbo].[Comments]
    INSTEAD OF DELETE
AS
    ;WITH IDs as (
       select id from deleted
       union all
       select c.id
       from Comments c
              inner join
            IDs i
              on
                 c.ParentID = i.id
    )
    DELETE FROM Comments
    WHERE id in (select id from IDs);

S'il existe d'autres contraintes de clé étrangère en cascade (non auto-référencées), elles doivent toutes être remplacées par des actions dans ce déclencheur. Dans un tel cas, je recommanderais d'introduire une variable de table pour contenir la liste de tous les identifiants qui seront éventuellement supprimés des Comments tableau :

CREATE TRIGGER [dbo].[T_comment_Trigger]
    ON [dbo].[Comments]
    INSTEAD OF DELETE
AS
    declare @deletions table (ID varchar(7) not null);
    ;WITH IDs as (
       select id from deleted
       union all
       select c.id
       from Comments c
              inner join
            IDs i
              on
                 c.ParentID = i.id
    )
    insert into @deletions(ID)
    select ID from IDs

    DELETE FROM OtherTable
    WHERE CommentID in (select ID from @deletions)

    --This delete comes last
    DELETE FROM Comments
    WHERE id in (select ID from @deletions);