Saya ingin menegaskan bahwa hanya satu catatan dalam tabel dianggap sebagai nilai "default" untuk kueri atau tampilan lain yang mungkin mengakses tabel itu.
Pada dasarnya, saya ingin menjamin bahwa permintaan ini akan selalu mengembalikan tepat satu baris:
SELECT ID, Zip
FROM PostalCodes
WHERE isDefault=True
Bagaimana saya melakukannya dalam SQL?
mysql
database-design
emaynard
sumber
sumber
PostalCodes
kosong? Jika suatu baris sudah memiliki properti seharusnya, itu dicegah dari disetel ke false kecuali baris lain (jika ada) disetel ke true dalam pernyataan SQL yang sama? Bisakah nol baris memiliki properti di antara batas-batas transaksi? Haruskah baris terakhir dalam tabel dipaksa untuk memiliki properti dan dicegah agar tidak dihapus? Pengalaman mengatakan kepada saya bahwa "menjamin tepat satu baris" cenderung berarti sesuatu yang berbeda dalam kenyataan, seringkali hanya "paling banyak satu baris".Jawaban:
Sunting: ini ditujukan untuk SQL Server sebelum kita tahu MySQL
Ada
45 cara untuk melakukan ini: dalam urutan yang paling diinginkan hingga yang tidak diinginkanKami tidak tahu apa RDBMS ini jika untuk jadi tidak semua mungkin berlaku
Cara terbaik adalah indeks yang difilter. Ini menggunakan DRI untuk mempertahankan keunikan.
Kolom yang dihitung dengan keunikan (lihat jawaban Jack Douglas) (ditambah dengan edit 2)
Tampilan terindeks / terwujud yang seperti indeks yang difilter menggunakan DRI
Pemicu (sesuai jawaban lain)
Periksa kendala dengan UDF. Ini tidak aman untuk konkurensi dan isolasi snapshot. Lihat Satu Dua Tiga Empat
Perhatikan bahwa persyaratan untuk "satu standar" ada di atas meja, bukan prosedur tersimpan. Prosedur tersimpan akan memiliki masalah konkurensi yang sama dengan kendala cek dengan udf
Catatan: sering ditanyakan SO:
sumber
Catatan: Jawaban ini diberikan sebelum jelas penanya menginginkan sesuatu yang spesifik MySQL. Jawaban ini bias terhadap SQL Server.
Menerapkan batasan PERIKSA ke tabel yang memanggil UDF dan memastikan nilai kembalinya <= 1. UDF hanya dapat menghitung baris dalam tabel MANA
isDefault = TRUE
. Ini akan memastikan bahwa tidak ada lebih dari 1 baris default dalam tabel.Anda harus menambahkan bitmap atau indeks yang difilter pada
isDefault
kolom (tergantung platforom Anda) untuk memastikan UDF ini berjalan sangat cepat.Peringatan
PostalCodes
tabel, namun ini tetap menjadi masalah kinerja untuk situasi-situasi di mana aktivitas berbasis set mungkin.Dengan semua peringatan ini, saya sarankan menggunakan saran GBN tentang indeks unik yang difilter alih-alih kendala pemeriksaan.
sumber
Berikut ini adalah Prosedur Tersimpan (Dialek MySQL):
Untuk memastikan meja Anda bersih dan prosedur tersimpan berfungsi, dengan anggapan ID 200 adalah default, jalankan langkah-langkah ini:
Alih-alih Prosedur Tersimpan, bagaimana dengan Pemicu?
Untuk memastikan meja Anda bersih dan pemicu berfungsi, dengan asumsi ID 200 adalah default, jalankan langkah-langkah ini:
sumber
Anda bisa menggunakan pemicu untuk menerapkan aturan. Ketika pernyataan UPDATE atau INSERT menetapkan isDefault ke True, SQL di pemicu dapat mengatur semua baris lainnya ke False.
Anda harus mempertimbangkan situasi lain saat menerapkan ini. Misalnya, apa yang harus terjadi jika lebih dari satu baris masuk dan UPDATE atau INSERT menetapkan isDefault ke True? Aturan apa yang akan berlaku untuk menghindari melanggar aturan?
Juga, mungkinkah kondisi di mana tidak ada default? Apa yang akan terjadi ketika pembaruan menetapkan isDefault dari True ke False.
Setelah Anda menetapkan aturan, Anda bisa membuatnya di pelatuk.
Kemudian, seperti ditunjukkan dalam jawaban lain, Anda ingin menerapkan batasan pemeriksaan untuk membantu menegakkan aturan.
sumber
Berikut ini menyiapkan contoh tabel dan data:
Jika Anda membuat prosedur tersimpan untuk mengatur bendera IsDefault dan menghapus izin untuk mengubah tabel dasar, Anda bisa menerapkannya dengan kueri di bawah ini. Itu akan membutuhkan pemindaian tabel setiap kali.
Bergantung pada ukuran tabel, indeks pada IsDefault (DESC) dapat menghasilkan salah satu atau kedua pertanyaan di bawah ini menghindari pemindaian penuh.
Jika Anda tidak dapat menghapus izin dari tabel dasar, perlu menegakkan integritas dengan cara lain dan menggunakan SQL2008, Anda dapat menggunakan indeks unik yang difilter:
sumber
Untuk MySQL yang tidak memiliki indeks filter, Anda bisa melakukan sesuatu seperti berikut ini. Ini mengeksploitasi fakta bahwa MySQL memungkinkan beberapa NULL dalam indeks unik, dan menggunakan tabel khusus dan kunci asing untuk mensimulasikan tipe data yang hanya dapat memiliki NULL dan 1 sebagai nilai.
Dengan solusi ini, alih-alih benar / salah, Anda hanya akan menggunakan 1 / NULL.
Satu-satunya hal yang bisa salah, saya pikir, adalah jika seseorang menambahkan baris ke
DefaultFlag
meja. Saya pikir ini bukan masalah besar, dan Anda selalu dapat memperbaikinya dengan izin jika Anda benar-benar ingin aman.sumber
Ini pada dasarnya memberi Anda masalah karena Anda meletakkan bidang di tempat yang salah dan hanya itu.
Memiliki tabel 'Defaults', dengan PostalCode di dalamnya, yang berisi id yang Anda cari. Secara umum, ada baiknya untuk memberi nama tabel Anda sesuai dengan satu catatan, jadi nama tabel awal Anda akan lebih baik disebut 'Kode Pos'. Default akan menjadi tabel baris tunggal, sampai Anda perlu mengkhususkan standar Anda terhadap beberapa konfigurasi lain (seperti sejarah).
Permintaan akhir yang Anda inginkan adalah sebagai berikut:
sumber