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

Que faire lorsque je souhaite utiliser des contraintes de base de données mais uniquement marquer comme supprimé au lieu de supprimer ?

Vous pouvez ajouter la valeur de l'identifiant à la fin du nom lorsqu'un enregistrement est supprimé. Ainsi, lorsque quelqu'un supprime l'identifiant 3, le nom devient Thingy3_3, puis lorsqu'il supprime l'identifiant 100, le nom devient Thingy3_100. Cela vous permettrait de créer un index composite unique sur le nom et les champs supprimés, mais vous devez ensuite filtrer la colonne du nom chaque fois que vous l'affichez et supprimer l'identifiant à la fin du nom.

Une meilleure solution serait peut-être de remplacer votre colonne supprimée par une colonne delete_at de type DATETIME. Vous pouvez alors maintenir un index unique sur le nom et supprimé à, avec un enregistrement non supprimé ayant une valeur nulle dans le champ delete_at. Cela empêcherait la création de plusieurs noms dans un état actif mais vous permettrait de supprimer le même nom plusieurs fois.

Vous devez évidemment faire un test lors de la restauration d'un enregistrement pour vous assurer qu'il n'y a pas de ligne avec le même nom et un champ null delete_at avant d'autoriser la restauration.

Vous pouvez en fait implémenter toute cette logique dans la base de données en utilisant un déclencheur INSTEAD-OF pour la suppression. Ce déclencheur ne supprimerait pas les enregistrements mais mettrait à jour la colonne delete_at lorsque vous supprimeriez un enregistrement.

L'exemple de code suivant le démontre

CREATE TABLE swtest (  
    id          INT IDENTITY,  
    name        NVARCHAR(20),  
    deleted_at  DATETIME  
)  
GO  
CREATE TRIGGER tr_swtest_delete ON swtest  
INSTEAD OF DELETE  
AS  
BEGIN  
    UPDATE swtest SET deleted_at = getDate()  
    WHERE id IN (SELECT deleted.id FROM deleted)
    AND deleted_at IS NULL      -- Required to prevent duplicates when deleting already deleted records  
END  
GO  

CREATE UNIQUE INDEX ix_swtest1 ON swtest(name, deleted_at)  

INSERT INTO swtest (name) VALUES ('Thingy1')  
INSERT INTO swtest (name) VALUES ('Thingy2')  
DELETE FROM swtest WHERE id = SCOPE_IDENTITY()  
INSERT INTO swtest (name) VALUES ('Thingy2')  
DELETE FROM swtest WHERE id = SCOPE_IDENTITY()  
INSERT INTO swtest (name) VALUES ('Thingy2')  

SELECT * FROM swtest  
DROP TABLE swtest  

La sélection de cette requête renvoie ce qui suit

id      name       deleted_at
1       Thingy1    NULL
2       Thingy2    2009-04-21 08:55:38.180
3       Thingy2    2009-04-21 08:55:38.307
4       Thingy2    NULL

Ainsi, dans votre code, vous pouvez supprimer des enregistrements à l'aide d'une suppression normale et laisser le déclencheur s'occuper des détails. Le seul problème possible (que j'ai pu voir) était que la suppression d'enregistrements déjà supprimés pouvait entraîner des lignes en double, d'où la condition dans le déclencheur de ne pas mettre à jour le champ delete_at sur une ligne déjà supprimée.