Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Co zrobić, gdy chcę użyć ograniczeń bazy danych, ale tylko oznaczyć jako usunięte, a nie usuwać?

Możesz dodać wartość id na końcu nazwy, gdy rekord jest usuwany, więc gdy ktoś usunie id 3, nazwa staje się Thingy3_3, a gdy usunie id 100, imię staje się Thingy3_100. Umożliwiłoby to utworzenie unikalnego indeksu złożonego dla nazwy i usuniętych pól, ale wtedy musisz filtrować kolumnę nazwy za każdym razem, gdy ją wyświetlasz i usuwając identyfikator z końca nazwy.

Być może lepszym rozwiązaniem byłoby zastąpienie usuniętej kolumny kolumną delete_at typu DATETIME. Można wtedy zachować unikalny indeks nazwy i usunąć o, z nieusuniętym rekordem mającym wartość null w polu usunięty_at. Uniemożliwiłoby to tworzenie wielu nazw w stanie aktywnym, ale umożliwiłoby wielokrotne usuwanie tej samej nazwy.

Oczywiście musisz przeprowadzić test podczas przywracania rekordu, aby upewnić się, że nie ma wiersza o tej samej nazwie i pustego pola delete_at przed zezwoleniem na cofnięcie usunięcia.

W rzeczywistości można zaimplementować całą tę logikę w bazie danych, używając wyzwalacza INSTEAD-OF do usuwania. Ten wyzwalacz nie usunie rekordów, ale zamiast tego zaktualizuje kolumnę delete_at po usunięciu rekordu.

Poniższy przykładowy kod demonstruje to

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  

Wybór z tego zapytania zwraca następujące

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

Tak więc w swoim kodzie możesz usuwać rekordy przy użyciu normalnego usuwania i pozwolić wyzwalaczowi zająć się szczegółami. Jedynym możliwym problemem (który mogłem zobaczyć) było to, że usunięcie już usuniętych rekordów może spowodować zduplikowanie wierszy, stąd warunek w regule, aby nie aktualizować pola delete_at w już usuniętym wierszu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. T-SQL MERGE - sprawdzanie, jakie działanie wykonało

  2. Usuń profil poczty bazy danych w programie SQL Server (T-SQL)

  3. Sql binary to c# - Jak uzyskać binarny odpowiednik kodu binarnego SQL w c#

  4. Wybierz tę samą nazwę kolumny na serwerze microsoft sql z wielu tabel

  5. Unikanie zakleszczenia za pomocą podpowiedzi NOLOCK