Saya punya tabel seperti berikut:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
Dan saya ingin (id_A, id_B, id_C)
tampil beda dalam situasi apa pun. Jadi, dua sisipan berikut harus menghasilkan kesalahan:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Tapi itu tidak berperilaku seperti yang diharapkan karena menurut dokumentasi, dua NULL
nilai tidak dibandingkan satu sama lain, sehingga kedua sisipan lulus tanpa kesalahan.
Bagaimana saya bisa menjamin kendala unik saya bahkan jika id_C
bisa NULL
dalam kasus ini? Sebenarnya, pertanyaan sebenarnya adalah: dapatkah saya menjamin keunikan seperti ini di "pure sql" atau apakah saya harus mengimplementasikannya pada level yang lebih tinggi (java dalam kasus saya)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
sumber
sumber
(1,2,1)
dan(1,2,2)
di(A,B,C)
kolom. Haruskah(1,2,NULL)
diizinkan untuk ditambahkan atau tidak?Jawaban:
Anda dapat melakukannya dalam SQL murni . Buat indeks unik parsial selain yang Anda miliki:
Dengan cara ini Anda dapat memasukkan untuk
(a, b, c)
di tabel Anda:Tapi tidak ada yang kedua kalinya.
Atau gunakan dua
UNIQUE
indeks parsial dan tidak ada indeks lengkap (atau kendala). Solusi terbaik tergantung pada detail kebutuhan Anda. Membandingkan:Meskipun ini elegan dan efisien untuk satu kolom yang dapat dibatalkan dalam
UNIQUE
indeks, ini menjadi cepat hilang untuk lebih banyak. Membahas ini - dan bagaimana menggunakan UPSERT dengan indeks parsial:Selain itu
Tidak digunakan untuk pengidentifikasi kasus campuran tanpa tanda kutip ganda di PostgreSQL.
Anda mungkin menganggap
serial
kolom sebagai kunci utama atauIDENTITY
kolom di Postgres 10 atau lebih baru. Terkait:Begitu:
Jika Anda tidak mengharapkan lebih dari 2 miliar baris (> 2147483647) selama masa hidup tabel Anda (termasuk baris buang dan hapus), pertimbangkan
integer
(4 byte) alih-alihbigint
(8 byte).sumber
Saya memiliki masalah yang sama dan saya menemukan cara lain untuk memiliki NULL yang unik ke dalam tabel.
Dalam kasus saya, bidang
foreign_key_field
adalah bilangan bulat positif dan tidak akan pernah -1.Jadi, untuk menjawab Manual Leduc, solusi lain bisa jadi
Saya berasumsi bahwa id tidak akan -1.
Apa keuntungan membuat indeks parsial?
Jika Anda tidak memiliki klausa NOT NULL
id_a
,,id_b
danid_c
dapat NULL bersama hanya sekali.Dengan indeks parsial, 3 bidang bisa NULL lebih dari sekali.
sumber
COALESCE
bisa efektif dalam membatasi duplikat, tetapi indeks tidak akan sangat berguna dalam permintaan sebagai indeks ekspresi yang mungkin tidak akan cocok dengan ekspresi permintaan. Yaitu, kecuali AndaSELECT COALESCE(col, -1) ...
tidak akan memukul indeks.Null dapat berarti bahwa nilai tidak diketahui untuk baris tersebut saat ini tetapi akan ditambahkan, ketika diketahui, di masa mendatang (contoh
FinishDate
untuk menjalankanProject
) atau bahwa tidak ada nilai yang dapat diterapkan untuk baris itu (contohEscapeVelocity
untuk lubang hitamStar
).Menurut pendapat saya, biasanya lebih baik untuk menormalkan tabel dengan menghilangkan semua Nulls.
Dalam kasus Anda, Anda ingin memperbolehkan
NULLs
di kolom Anda, namun Anda hanya menginginkan satu yangNULL
diizinkan. Mengapa? Hubungan macam apa ini di antara kedua tabel?Mungkin Anda bisa dengan mudah mengubah kolom ke
NOT NULL
dan menyimpan, alih-alihNULL
, nilai khusus (seperti-1
) yang diketahui tidak pernah muncul. Ini akan menyelesaikan masalah kendala keunikan (tetapi mungkin memiliki efek samping lain yang mungkin tidak diinginkan. Misalnya, menggunakan-1
berarti "tidak dikenal / tidak berlaku" akan memiringkan perhitungan jumlah atau rata-rata pada kolom. Atau semua perhitungan seperti itu harus diambil memperhitungkan nilai khusus dan mengabaikannya.)sumber