Misalnya, dengan tabel yang mirip dengan ini:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Tidak masalah jika bendera diimplementasikan sebagai char(1)
, a, bit
atau apa pun. Saya hanya ingin dapat menegakkan batasan yang hanya dapat ditetapkan pada satu baris.
constraint
database-agnostic
referential-integrity
Jack Douglas
sumber
sumber
Jawaban:
SQL Server 2008 - Indeks unik yang difilter
sumber
SQL Server 2000, 2005:
Anda dapat memanfaatkan fakta bahwa hanya satu nol yang diizinkan dalam indeks unik:
untuk tahun 2000, Anda mungkin perlu
SET ARITHABORT ON
(terima kasih kepada @gbn untuk info ini)sumber
Peramal:
Karena Oracle tidak mengindeks entri di mana semua kolom yang diindeks adalah nol, Anda dapat menggunakan indeks unik berbasis fungsi:
Indeks ini paling banyak hanya akan mengindeks satu baris.
Mengetahui fakta indeks ini, Anda juga dapat mengimplementasikan kolom bit sedikit berbeda:
Di sini nilai yang mungkin untuk kolom
chk
adalahY
danNULL
. Hanya satu baris paling banyak yang dapat memiliki nilaiY.
sumber
not null
kendala?not null
batasan jika Anda tidak ingin nulls (Tidak jelas bagi saya dari spesifikasi pertanyaan). Hanya satu baris yang dapat memiliki nilai 'Y' dalam hal apa pun.default
)?Y
ataunull
, lihat pembaruan saya.null
yang dilewati - dengan biaya beberapa kejelasan mungkinSaya pikir ini adalah kasus penataan tabel database Anda dengan benar. Untuk membuatnya lebih konkret, jika Anda memiliki seseorang dengan beberapa alamat dan Anda ingin seseorang menjadi default, saya pikir Anda harus menyimpan addressID dari alamat default di tabel orang, tidak memiliki kolom default di tabel alamat:
Anda dapat membuat DefaultAddressID nullable, tetapi dengan cara ini struktur memberlakukan kendala Anda.
sumber
MySQL:
Batasan pemeriksaan diabaikan di MySQL sehingga kami harus mempertimbangkan
null
ataufalse
salah dantrue
benar. Paling banyak 1 baris dapat memilikichk=true
Anda mungkin menganggapnya sebagai peningkatan untuk menambahkan pemicu untuk diubah
false
menjaditrue
pada saat memasukkan / memperbarui sebagai solusi untuk kurangnya batasan pemeriksaan - IMO itu bukan perbaikan.Saya berharap dapat menggunakan char (0) karena itu
Sayangnya, dengan MyISAM dan InnoDB setidaknya, saya mengerti
--edit
ini bukan solusi yang baik karena pada MySQL,
boolean
adalah sinonim untuktinyint(1)
, dan memungkinkan nilai-nilai non-nol dari 0 atau 1. Ada kemungkinan bahwa itubit
akan menjadi pilihan yang lebih baiksumber
null
,false
,true
- saya lakukan heran jika ada sesuatu yang lebih rapi ...SQL Server:
Bagaimana cara melakukannya:
Cara terbaik adalah indeks yang difilter. Menggunakan DRI
SQL Server 2008+
Kolom yang dihitung dengan keunikan. Menggunakan DRI.
Lihat jawaban Jack Douglas. SQL Server 2005 dan sebelumnya
Tampilan terindeks / terwujud yang seperti indeks yang difilter. Menggunakan DRI
Semua versi.
Pelatuk. Menggunakan Kode, bukan DRI.
Semua versi
Bagaimana tidak melakukannya:
Lihat Satu Dua Tiga Empat
sumber
PostgreSQL:
--edit
atau (jauh lebih baik), gunakan indeks parsial unik :
sumber
Masalah semacam ini adalah alasan lain mengapa saya menanyakan pertanyaan ini:
Pengaturan Aplikasi dalam Database
Jika Anda memiliki tabel pengaturan aplikasi di database Anda, Anda bisa memiliki entri yang akan merujuk ID dari satu catatan yang Anda ingin dianggap 'istimewa'. Maka Anda hanya akan mencari apa ID dari tabel pengaturan Anda, dengan cara ini Anda tidak perlu seluruh kolom untuk hanya satu item yang ditetapkan.
sumber
Kemungkinan pendekatan menggunakan teknologi yang diimplementasikan secara luas:
1) Cabut hak istimewa 'penulis' di atas meja. Buat prosedur CRUD yang memastikan kendala diberlakukan pada batas-batas transaksi.
2) 6NF: jatuhkan
CHAR(1)
kolom. Tambahkan tabel referensi dibatasi untuk memastikan kardinalitasnya tidak dapat melebihi satu:Ubah semantik aplikasi sehingga 'default' yang dianggap adalah baris dalam tabel baru. Mungkin menggunakan tampilan untuk merangkum logika ini.
3) Jatuhkan
CHAR(1)
kolom. Tambahkanseq
kolom bilangan bulat. Beri batasan unikseq
. Ubah aplikasi semantik sehingga dianggap 'default' adalah baris di manaseq
nilainya adalah satu atauseq
nilai terbesar / nilai terkecil atau serupa. Mungkin menggunakan tampilan untuk merangkum logika ini.sumber
Bagi mereka yang menggunakan MySQL, berikut ini adalah Prosedur Tersimpan yang sesuai:
Untuk memastikan meja Anda bersih dan prosedur tersimpan berfungsi, dengan anggapan ID 200 adalah default, jalankan langkah-langkah ini:
Berikut adalah Pemicu yang membantu juga:
Untuk memastikan meja Anda bersih dan pemicu berfungsi, dengan anggapan ID 200 adalah default, jalankan langkah-langkah ini:
Cobalah !!!
sumber
Dalam SQL Server 2000 dan lebih Anda dapat menggunakan Tampilan Terindeks untuk mengimplementasikan kendala kompleks (atau multi-tabel) seperti yang Anda minta.
Oracle juga memiliki implementasi serupa untuk tampilan terwujud dengan kendala pemeriksaan tangguhan.
Lihat posting saya di sini .
sumber
Standar Transisi SQL-92, diimplementasikan secara luas misalnya SQL Server 2000 dan di atas:
Cabut hak istimewa 'penulis' dari tabel. Buat dua tampilan untuk
WHERE chk = 'Y'
danWHERE chk = 'N'
masing - masing, termasukWITH CHECK OPTION
. UntukWHERE chk = 'Y'
tampilan, sertakan kondisi pencarian agar efek kardinalitasnya tidak melebihi satu. Berikan 'penulis' hak istimewa pada pandangan.Kode contoh untuk tampilan:
sumber
Inilah solusi untuk MySQL dan MariaDB menggunakan kolom virtual yang sedikit lebih elegan. Ini membutuhkan MySQL> = 5.7.6 atau MariaDB> = 5.2:
Buat kolom virtual yang NULL jika Anda tidak ingin memaksakan contrraint Unik:
(Untuk MySQL, gunakan
STORED
sebagai gantiPERSISTENT
.)sumber
Standar FULL SQL-92: gunakan subquery dalam
CHECK
batasan, tidak diimplementasikan secara luas misalnya didukung dalam Access2000 (ACE2007, Jet 4.0, apa pun) dan di atasnya saat dalam Mode Kueri ANSI-92 .Kode contoh:
CHECK
batasan note di Access selalu level tabel. KarenaCREATE TABLE
pernyataan dalam pertanyaan menggunakanCHECK
batasan tingkat baris , itu perlu diubah sedikit dengan menambahkan koma:sumber
Saya hanya membaca jawaban secara singkat, jadi saya mungkin melewatkan jawaban yang sama. Idenya adalah untuk menggunakan kolom yang dihasilkan baik pk atau konstanta yang tidak ada sebagai nilai untuk pk
AFAIK ini valid dalam SQL2003 (karena Anda mencari solusi agnostik). DB2 memungkinkannya, tidak yakin berapa banyak vendor lain yang menerimanya.
sumber