I am working in a project where database items are not deleted, but only marked as deleted. Something like this:
id name deleted
--- ------- --------
The type of constraint you require is a table-level CHECK constraint i.e. a CHECK constraint consisting of a subquery which tests NOT EXISTS (or equivalent) for the table e.g.
CREATE TABLE Test
(
ID INTEGER NOT NULL UNIQUE,
name VARCHAR(30) NOT NULL,
deleted INTEGER NOT NULL,
CHECK (deleted IN (0, 1))
);
ALTER TABLE Test ADD
CONSTRAINT test1__unique_non_deleted
CHECK
(
NOT EXISTS
(
SELECT T1.name
FROM Test AS T1
WHERE T1.deleted = 0
GROUP
BY T1.Name
HAVING COUNT(*) > 1
)
);
INSERT INTO Test (ID, name, deleted) VALUES (1, 'Thingy1', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (2, 'Thingy2', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (3, 'Thingy3', 1)
;
INSERT INTO Test (ID, name, deleted) VALUES (4, 'Thingy3', 1)
;
INSERT INTO Test (ID, name, deleted) VALUES (5, 'Thingy3', 0)
;
INSERT INTO Test (ID, name, deleted) VALUES (6, 'Thingy3', 0)
;
The last INSERT (ID = 6) will cause the constraint to bite and the INSERT will fail. Q.E.D.
...ooh, nearly forgot to mention: SQL Server doesn't yet support CHECK constraints with that contain a subquery (I tested the above on ACE/JET, a.k.a. ). While you could use a FUNCTION I've read this is unsafe due to SQL Server testing constraints on a row-by-row basis (see David Portas' Blog). Until this full SQL-92 feature is supported in SQL Server, my preferred workaround is to use the same logic in a trigger.