Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Какво да направя, когато искам да използвам ограничения на базата данни, но само да маркирам като изтрит, вместо да изтрия?

Можете да добавите стойността на id в края на името, когато се изтрие запис, така че когато някой изтрие id 3, името става Thingy3_3 и след това, когато изтрие id 100, името става Thingy3_100. Това ще ви позволи да създадете уникален съставен индекс на името и изтритите полета, но след това трябва да филтрирате колоната с име всеки път, когато я показвате и да премахнете идентификатора от края на името.

Може би по-добро решение би било да замените вашата изтрита колона с deleted_at колона от тип DATETIME. След това можете да поддържате уникален индекс на name и deleted at, като неизтрит запис има нулева стойност в полето deleted_at. Това ще предотврати създаването на множество имена в активно състояние, но ще ви позволи да изтриете едно и също име няколко пъти.

Очевидно трябва да направите тест, когато възстановявате изтриване на запис, за да се уверите, че няма ред със същото име и нулево поле deleted_at, преди да разрешите премахването на изтриването.

Всъщност можете да приложите цялата тази логика в базата данни, като използвате тригер INSTEAD-OF за изтриването. Този тригер няма да изтрие записи, а вместо това ще актуализира колоната deleted_at, когато изтриете запис.

Следният примерен код демонстрира това

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  

Изборът от тази заявка връща следното

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

Така че във вашия код можете да изтривате записи, като използвате нормално изтриване и оставяте тригера да се погрижи за подробностите. Единственият възможен проблем (който можех да видя) беше, че изтриването на вече изтрити записи може да доведе до дублиращи се редове, следователно условието в тригера да не се актуализира полето deleted_at на вече изтрит ред.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да изпълня 32-битов SSIS пакет в 64-битов пакет?

  2. Как да запазя резултатите от заявката за избор във временна таблица?

  3. Актуализиране на колоната за брой от данни в друга таблица

  4. Използване на Like на параметърна променлива?

  5. Групиране по колона и множество редове в един ред множество колони