Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Was tun, wenn ich Datenbankeinschränkungen verwenden, aber nur als gelöscht markieren möchte, anstatt zu löschen?

Sie könnten den ID-Wert am Ende des Namens hinzufügen, wenn ein Datensatz gelöscht wird. Wenn also jemand die ID 3 löscht, wird der Name zu Thingy3_3, und wenn er dann die ID 100 löscht, wird der Name zu Thingy3_100. Dies würde es Ihnen ermöglichen, einen eindeutigen zusammengesetzten Index für den Namen und die gelöschten Felder zu erstellen, aber Sie müssen dann die Namensspalte jedes Mal filtern, wenn Sie sie anzeigen, und die ID am Ende des Namens entfernen.

Vielleicht wäre es eine bessere Lösung, Ihre gelöschte Spalte durch eine "deleted_at"-Spalte vom Typ DATETIME zu ersetzen. Sie könnten dann einen eindeutigen Index für „name“ und „delete at“ verwalten, wobei ein nicht gelöschter Datensatz einen Nullwert im Feld „deleted_at“ hat. Dies würde die Erstellung mehrerer Namen in einem aktiven Zustand verhindern, aber es Ihnen ermöglichen, denselben Namen mehrmals zu löschen.

Sie müssen natürlich einen Test durchführen, wenn Sie einen Datensatz wiederherstellen, um sicherzustellen, dass es keine Zeile mit demselben Namen und einem leeren Feld "delete_at" gibt, bevor Sie die Wiederherstellung zulassen.

Sie könnten diese gesamte Logik tatsächlich in der Datenbank implementieren, indem Sie einen INSTEAD-OF-Trigger für das Löschen verwenden. Dieser Trigger würde keine Datensätze löschen, sondern stattdessen die Spalte „deleted_at“ aktualisieren, wenn Sie einen Datensatz löschen.

Der folgende Beispielcode demonstriert dies

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  

Die Auswahl aus dieser Abfrage gibt Folgendes zurück

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

In Ihrem Code können Sie also Datensätze mit einem normalen Löschvorgang löschen und den Trigger die Details erledigen lassen. Das einzig mögliche Problem (das ich sehen konnte) war, dass das Löschen bereits gelöschter Datensätze zu doppelten Zeilen führen konnte, daher die Bedingung im Trigger, das Feld "deleted_at" in einer bereits gelöschten Zeile nicht zu aktualisieren.