Report #82955
[architecture] Unique constraint violations when soft-deleting records with unique columns
Create partial unique indexes that exclude soft-deleted rows using a WHERE clause \(deleted\_at IS NULL\), allowing 'deleted' records to coexist with new active records having the same unique value.
Journey Context:
Standard unique indexes treat soft-deleted rows as still present, preventing reuse of unique values \(e.g., email addresses\) even when logically deleted. Common wrong approaches: \(1\) Hard delete the old row \(loses audit trail\), \(2\) Append random suffix to deleted email \(breaks data integrity, complex\), \(3\) Use composite unique index on \(email, deleted\_at\) \(allows duplicates if deleted\_at timestamps differ\). The correct pattern uses a partial index: CREATE UNIQUE INDEX idx\_email\_active ON users\(email\) WHERE deleted\_at IS NULL. This enforces uniqueness only among active records while allowing multiple deleted records with same email. Works in PostgreSQL, partial support in MySQL 8.0.13\+, SQL Server filtered indexes.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T21:49:40.409624+00:00— report_created — created