Suka @lad2025 berkomentar , status
harus benar-benar boolean
. Lebih murah, lebih bersih.
Apa pun itu, Anda dapat menerapkan aturan dengan indeks unik parsial :
Untuk mengizinkan nol atau satu baris dengan status = 'Active'
di seluruh tabel :
CREATE UNIQUE INDEX tbl_active_uni ON tbl (status)
WHERE status = 'Active';
Untuk mengizinkan nol atau satu baris dengan status = 'Active'
per userid
, buat userid
kolom yang diindeks:
CREATE UNIQUE INDEX tbl_userid_active_uni ON tbl (userid)
WHERE status = 'Active';
Perhatikan bahwa userid IS NULL
tidak akan memicu pelanggaran unik, karena dua nilai NULL tidak pernah dianggap sama. userid
harus setel NOT NULL
dalam hal ini.
Mengapa indeks dan bukan kendala?
Mengatasi pertanyaan di komentar
:Ini adalah indeks, bukan CONSTRAINT
.
Indeks untuk kasus pertama adalah kecil , memegang satu atau tidak ada baris.
Indeks untuk kasus kedua menampung satu baris per userid
yang ada , tapi ini adalah cara termurah dan tercepat , selain bersih dan aman. Anda akan memerlukan indeks untuk memeriksa baris lain dalam hal apa pun untuk mempercepatnya.
Anda tidak dapat memiliki CHECK
pemeriksaan kendala pada baris lain - setidaknya tidak dengan cara yang bersih dan andal. Ada beberapa cara yang pasti tidak akan saya rekomendasikan untuk kasus ini:
- Pemicu vs. batasan pemeriksaan
- Bagaimana cara menghindari ketergantungan siklik (referensi melingkar) antara 3 tabel?
- Nonaktifkan semua batasan dan pemeriksaan tabel saat memulihkan dump
Jika Anda menggunakan UNIQUE
batasan pada (userid, status)
(yang juga diimplementasikan dengan indeks unik di latar belakang!), Anda tidak dapat membuatnya sebagian , dan semua kombinasi dipaksakan menjadi unik. Anda bisa masih gunakan ini jika Anda bekerja dengan status IS NULL
untuk semua kasus kecuali 'Active'
kasus. Tapi itu sebenarnya akan memaksakan indeks yang jauh lebih besar termasuk semua baris.