Report #6629
[architecture] How to handle unique constraints with soft-deleted records in SQL databases
Use partial unique indexes \(PostgreSQL\) or filtered unique indexes \(SQL Server\) that exclude soft-deleted rows, e.g., CREATE UNIQUE INDEX idx\_email ON users\(email\) WHERE deleted\_at IS NULL; alternatively, use a tombstone boolean combined with a composite unique index on \(email, is\_deleted\) where is\_deleted is 0 or 1, but this prevents re-adding a deleted email until fully purged.
Journey Context:
Standard unique constraints fail with soft deletes because a 'deleted' record still occupies the unique slot, preventing reuse of that email/username forever. Common mistake is to remove the unique constraint entirely, losing data integrity. Partial indexes solve this by only enforcing uniqueness on active records. The tradeoff is database-specific \(Postgres partial indexes work well; MySQL 8.0.13\+ supports functional indexes but not partial indexes in the same way, requiring generated columns or triggers\). Another approach is storing 'deleted' as a timestamp and using NULL for active records in a functional index, but this complicates queries.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T00:37:41.860200+00:00— report_created — created