Report #71351
[architecture] How to enforce unique constraints only on non-deleted \(soft-deleted\) rows without race conditions
Create a partial unique index with a WHERE clause \(e.g., CREATE UNIQUE INDEX idx ON table\(col\) WHERE deleted\_at IS NULL\) instead of using application-level uniqueness checks or filtered unique constraints that aren't atomic.
Journey Context:
Application-level checks \(SELECT then INSERT\) fail under race conditions between concurrent transactions. Using a 'deleted' boolean with a unique index on \(col, deleted\) prevents re-using the unique value after deletion \(e.g., re-creating a user with the same email\). Partial indexes enforce uniqueness only on live data atomically at the database level. Tradeoff: Partial indexes are PostgreSQL/SQLite specific; MySQL 8.0.13\+ supports functional indexes but emulating partial unique constraints requires generated columns or application logic, making Postgres the preferred choice for this pattern.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T02:20:36.099540+00:00— report_created — created