Saya punya kolom: standard BOOLEAN NOT NULL
Saya ingin menegakkan satu baris Benar, dan semua lainnya Salah. Tidak ada FK atau apa pun tergantung pada kendala ini. Saya tahu saya bisa mencapainya dengan plpgsql, tapi ini sepertinya palu godam. Saya lebih suka sesuatu seperti CHECK
atau UNIQUE
kendala. Semakin sederhana semakin baik.
Satu baris harus Benar, semuanya tidak bisa Salah (jadi baris pertama yang dimasukkan harus Benar).
Baris perlu diperbarui, yang berarti saya harus menunggu untuk memeriksa batasan sampai pembaruan selesai, karena semua baris mungkin ditetapkan Salah dulu dan satu baris Benar setelahnya.
Ada FK antara products.tax_rate_id
dan tax_rate.id
, tetapi tidak ada hubungannya dengan tarif pajak standar atau standar, yang dapat dipilih pengguna untuk memudahkan menciptakan produk baru ..
PostgreSQL 9.5 jika itu penting.
Latar Belakang
Tabelnya adalah tarif pajak. Salah satu tarif pajak adalah default ( standard
karena default adalah perintah Postgres). Ketika produk baru ditambahkan, tarif pajak standar diterapkan ke produk. Jika tidak ada standard
, database harus melakukan tebakan atau semua jenis cek yang tidak diperlukan. Solusi sederhana, saya pikir, adalah untuk memastikan ada standard
.
Secara "default" di atas, maksud saya untuk lapisan presentasi (UI). Ada opsi pengguna untuk mengubah tarif pajak standar. Saya juga perlu menambahkan pemeriksaan tambahan untuk memastikan GUI / pengguna tidak mencoba untuk mengatur tax_rate_id ke NULL, atau kemudian hanya menetapkan tarif pajak default.
Jawaban:
Varian 1
Karena yang Anda butuhkan adalah satu kolom dengan
standard = true
, tetapkan standar ke NULL di semua baris lainnya. MakaUNIQUE
kendala polos berfungsi, karena nilai NULL tidak melanggarnya:DEFAULT
adalah pengingat opsional bahwa baris pertama yang dimasukkan harus menjadi default. Itu tidak menegakkan apa pun. Meskipun Anda tidak dapat mengatur lebih dari satu barisstandard = true
, Anda masih dapat mengatur semua baris NULL. Tidak ada cara bersih untuk mencegah hal ini dengan hanya kendala dalam satu tabel.CHECK
kendala tidak mempertimbangkan baris lain (tanpa trik kotor).Terkait:
Batasi dua nilai kolom tertentu dari yang ada pada saat yang sama
Tambahkan kendala untuk membuat kolom menjadi unik per grup baris
Untuk memperbaharui:
Untuk mengizinkan perintah seperti (di mana batasan hanya dipenuhi di akhir pernyataan):
..
UNIQUE
kendala harusDEFERRABLE
. Lihat:Aku di sini
Varian 2
Memiliki tabel kedua dengan satu baris seperti:
Buat ini sebagai superuser:
Sekarang selalu ada satu baris yang menunjuk ke standar (dalam kasus sederhana ini juga mewakili tingkat standar secara langsung). Hanya superuser yang bisa memecahkannya. Anda mungkin melarang itu juga, dengan pemicu
BEFORE DELETE
.Aku di sini
Terkait:
Anda dapat menambahkan
VIEW
untuk melihat sama seperti dalam varian 1 :Dalam kueri di mana yang Anda inginkan adalah kurs standar, gunakan (hanya)
taxrate_standard.taxrate
secara langsung.Anda kemudian menambahkan:
Sebuah implementasi orang miskin dari varian 2 akan hanya menambahkan baris ke
products
(atau tabel serupa) menunjuk ke tarif pajak standar; produk tiruan yang Anda sebut "Tarif pajak standar" - jika pengaturan Anda memungkinkan.Kendala FK memberlakukan integritas referensial. Untuk menyelesaikannya, tegakkan
tax_rate_id IS NOT NULL
untuk baris (jika itu tidak berlaku untuk kolom secara umum). Dan melarang penghapusannya. Keduanya bisa dimasukkan ke dalam pemicu. Tidak ada meja tambahan, tapi kurang elegan dan tidak bisa diandalkan.sumber
CROSS JOIN
melawan standar,LEFT JOIN
ke spesifik, dan kemudian diCOALESCE
antara keduanya.CONSTRAINT standard_only_1_true UNIQUE (standard)
: Saya kira tabel tidak akan besar sehingga tidak masalah banyak tetapi karena kendala akan menentukan indeks pada seluruh tabel, bukankah sebagian indeks unik denganWHERE (standard)
menggunakan lebih sedikit ruang?Anda dapat menggunakan indeks yang difilter
Aku di sini
Tapi seperti yang Anda katakan, baris pertama harus benar, maka Anda bisa menggunakan PERIKSA kendala, tetapi bahkan menggunakan fungsi Anda dapat menghapus baris pertama nanti.
Aku di sini
Anda bisa menyelesaikannya dengan menambahkan pemicu SEBELUM DELETE untuk memastikan baris pertama (foo benar) tidak pernah dihapus.
Aku di sini
sumber