sql >> Databasteknik >  >> RDS >> Sqlserver

Vad ska jag göra när jag vill använda databasbegränsningar men bara markera som borttagen istället för att ta bort?

Du kan lägga till id-värdet i slutet av namnet när en post raderas, så när någon tar bort id 3 blir namnet Thingy3_3 och när de tar bort id 100 blir namnet Thingy3_100. Detta skulle tillåta dig att skapa ett unikt sammansatt index på namnet och borttagna fält, men du måste sedan filtrera namnkolumnen när du visar den och ta bort id:t från slutet av namnet.

En bättre lösning skulle kanske vara att ersätta din borttagna kolumn med en raderad_at kolumn av typen DATETIME. Du kan sedan upprätthålla ett unikt index på namn och raderade på, med en icke-raderad post som har ett nollvärde i deleted_at-fältet. Detta skulle förhindra skapandet av flera namn i ett aktivt tillstånd men skulle tillåta dig att radera samma namn flera gånger.

Du måste uppenbarligen göra ett test när du återställer en post för att säkerställa att det inte finns någon rad med samma namn och ett null deleted_at-fält innan du tillåter att du tar bort borttagningen.

Du kan faktiskt implementera all denna logik i databasen genom att använda en INSTEAD-OF-utlösare för borttagningen. Den här utlösaren skulle inte ta bort poster utan skulle istället uppdatera kolumnen deleted_at när du raderade en post.

Följande exempelkod visar detta

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  

Välj från denna fråga returnerar följande

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

Så inom din kod kan du radera poster med en normal radering och låta triggern ta hand om detaljerna. Det enda möjliga problemet (som jag kunde se) var att radering av redan raderade poster kunde resultera i dubbletter av rader, därav villkoret i utlösaren att inte uppdatera fältet deleted_at på en redan raderad rad.



  1. Hur räknar man rader från två tabeller i en fråga?

  2. HTTP-fel 404.0 hittades inte vid export från kristallrapport

  3. 3 sätt att hitta rader som innehåller versaler i SQLite

  4. Försöker få in egendom av icke-objekt