Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

O que fazer quando quero usar restrições de banco de dados, mas apenas marcar como excluído em vez de excluir?


Você pode adicionar o valor do id ao final do nome quando um registro é excluído, então quando alguém exclui o id 3, o nome se torna Thingy3_3 e, quando ele exclui o id 100, o nome se torna Thingy3_100. Isso permitiria que você criasse um índice composto exclusivo no nome e nos campos excluídos, mas você teria que filtrar a coluna de nome sempre que exibi-la e remover o id do final do nome.

Talvez uma solução melhor seja substituir sua coluna excluída por uma coluna delete_at do tipo DATETIME. Você pode manter um índice exclusivo em nome e excluído em, com um registro não excluído com um valor nulo no campo delete_at. Isso impediria a criação de vários nomes em um estado ativo, mas permitiria excluir o mesmo nome várias vezes.

Obviamente, você precisa fazer um teste ao recuperar um registro para garantir que não haja nenhuma linha com o mesmo nome e um campo null delete_at antes de permitir o un-delete.

Você pode realmente implementar toda essa lógica no banco de dados usando um gatilho INSTEAD-OF para a exclusão. Esse acionador não exclui registros, mas atualiza a coluna delete_at quando você exclui um registro.

O código de exemplo a seguir demonstra isso
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  

A seleção desta consulta retorna o seguinte
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

Portanto, dentro do seu código, você pode excluir registros usando uma exclusão normal e deixar o gatilho cuidar dos detalhes. O único problema possível (que eu pude ver) era que a exclusão de registros já excluídos poderia resultar em linhas duplicadas, daí a condição no gatilho para não atualizar o campo delete_at em uma linha já excluída.