Jika Anda membutuhkan untuk mengizinkan nilai NULL, gunakan UNIQUE
kendala alih-alih PRIMARY KEY
(dan tambahkan kolom PK pengganti, saya sarankan serial
). Ini memungkinkan kolom menjadi NULL:
CREATE TABLE distributor (
distributor_id serial PRIMARY KEY
, m_id integer
, x_id integer
, UNIQUE(m_id, x_id)
);
Catatan , namun (per dokumentasi):
Untuk tujuan batasan unik, nilai nol tidak dianggap sama.
Dalam kasus Anda, Anda dapat memasukkan sesuatu seperti (1, NULL)
untuk (m_id, x_id)
beberapa kali tanpa melanggar batasan. Postgres tidak pernah menganggap dua nilai NULL sama - sesuai definisi dalam standar SQL.
Jika Anda perlu memperlakukan NULL
nilai sama dengan melarang "duplikat" tersebut, Saya melihat dua opsi :
1. Dua indeks parsial
Selain itu ke UNIQUE
batasan di atas:
CREATE UNIQUE INDEX dist_m_uni_idx ON distributor (m_id) WHERE x_id IS NULL;
CREATE UNIQUE INDEX dist_x_uni_idx ON distributor (x_id) WHERE m_id IS NULL;
Tapi ini keluar dari tangan dengan cepat dengan lebih dari dua kolom yang bisa NULL. Lihat:
- Buat batasan unik dengan kolom nol
2. Sebuah UNIQUE
multi-kolom indeks pada ekspresi
Alih-alih kendala UNIK. Kami membutuhkan nilai default gratis yang tidak pernah ada di kolom yang terlibat, seperti -1
. Tambahkan CHECK
batasan untuk melarangnya:
CREATE TABLE distributor (
distributor serial PRIMARY KEY
, m_id integer
, x_id integer
, CHECK (m_id <> -1)
, CHECK (x_id <> -1)
);
CREATE UNIQUE INDEX distributor_uni_idx ON distributor (COALESCE(m_id, -1)
, COALESCE(x_id, -1))
Bagaimana RDBMS tertentu menangani berbagai hal tidak selalu merupakan indikator yang berguna untuk perilaku yang tepat. Petunjuk Postgres mengisyaratkan hal ini:
Itu berarti bahkan dengan adanya batasan unik, dimungkinkan untuk menyimpan baris duplikat yang berisi nilai nol di setidaknya salah satu kolom yang dibatasi. Perilaku ini sesuai dengan standar SQL, tetapi kami telah mendengar bahwa database SQL lain mungkin tidak mengikuti aturan ini .Jadi berhati-hatilah saat mengembangkan aplikasi yang dimaksudkan untuk portabel.
Penekanan saya yang berani.