Report #46269
[architecture] Soft-deleted records block unique constraints on recycled values \(e.g., email reuse\)
Create a partial unique index \`WHERE deleted\_at IS NULL\` instead of a table-level constraint; for databases without partial indexes \(MySQL < 8.0\), use a computed \`is\_active\` boolean with a unique index on \`\(email, is\_active\)\` where \`is\_active\` is maintained by triggers.
Journey Context:
Developers often add a nullable \`deleted\_at\` timestamp then try to enforce \`UNIQUE\(email\)\`. This fails because SQL standards treat NULLs as distinct values in unique constraints, so \`\([email protected], NULL\)\` and \`\([email protected], '2024-01-01'\)\` are considered distinct rows. Partial indexes solve this by physically excluding soft-deleted rows from the index tree entirely, allowing the uniqueness check to ignore them without table scans. The \`COALESCE\(deleted\_at, 'infinity'\)\` hack is dangerous: it bloats the index with high values and breaks PostgreSQL's autovacuum heuristics. For MySQL, the \`is\_active\` boolean approach is the only performant path, but requires triggers to maintain the flag to avoid application bugs.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T08:08:11.033654+00:00— report_created — created