Postgresql: Koşullu olarak benzersiz kısıtlama


116

Yalnızca tablonun bir bölümünde bir sütunda benzersizliği zorlayan bir kısıtlama eklemek istiyorum.

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

Yukarıdaki WHEREbölüm arzulu bir düşüncedir.

Bunu yapmanın herhangi bir yolu var mı? Yoksa ilişkisel çizim tahtasına geri mi dönmeliyim?


2
Genellikle yapılır. "Kısmi benzersiz dizin" Bkz
Craig Zil

11
@yvesonline hayır, bu normal bir benzersiz kısıtlamadır. Poster, kısmi benzersiz bir kısıtlama istiyor .
Craig Ringer

Yanıtlar:


186

PostgreSQL kısmi (yani şartlı) tanımlamıyor UNIQUEancak, - kısıt olabilir oluşturmak kısmi benzersiz bir dizin . PostgreSQL, benzersiz kısıtlamaları uygulamak için benzersiz indeksler kullanır, bu nedenle etki aynıdır, sadece listelenen kısıtlamayı görmezsiniz information_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

Kısmi dizinlere bakın .


24
Süper! "Kısıtlamanın" bir kısıtlama olarak görünmemesi sezgisel değil, ancak yine de istenen hatayı veriyorERROR: duplicate key value violates unique constraint "stop_myc"
EoghanM

7
Bunun, kısmen benzersiz alan olan FK referanslarının oluşturulmasına izin vermeyeceği unutulmamalıdır.
ffflabs

11
Ayrıca bu indeks etkilerinin ertelenemeyeceğini de belirtmek gerekir. Toplu güncellemeler yapmanız gerekiyorsa, bu, bir kısıtlama için olduğu gibi ifadeden sonra veya ertelenebilir bir kısıtlama gibi işlemden sonra değil, her satırdan sonra benzersizlik kontrol edildiğinden bir sorun oluşturabilir.
sage88

37

PG'nin kısmi (yani koşullu) bir UNIQUE kısıtlamasını tanımlamadığı zaten söylendi. Ayrıca belgeler, bir tabloya benzersiz bir kısıtlama eklemenin tercih edilen yolunun Benzersiz Dizinler olduğunu söylüyorADD CONSTRAINT

Bir tabloya benzersiz bir kısıtlama eklemenin tercih edilen yolu ALTER TABLE ... ADD CONSTRAINT'dir. Benzersiz kısıtlamaları uygulamak için dizinlerin kullanılması, doğrudan erişilemeyen bir uygulama ayrıntısı olarak düşünülebilir. Bununla birlikte, benzersiz sütunlarda dizinleri manuel olarak oluşturmaya gerek olmadığı unutulmamalıdır; bunu yapmak sadece otomatik olarak oluşturulan dizini kopyalar.

Hariç Tutma Kısıtlamalarını kullanarak uygulamanın bir yolu var (bu çözüm için @dukelion'a teşekkürler)

Senin durumunda şöyle görünecek

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

Bu yaklaşımda, dizin yöntemini tanımlamak için "kullanma" yı kullanmazsınız, bu nedenle aşırı derecede yavaş olabilir veya postgres bunun üzerinde varsayılan bir dizin oluşturur? Bu yöntem kanonik seçimdir, ancak hiçbir zaman daha iyi bir seçim değildir! Sanırım bu seçimi daha iyi yapmak için indeksli "kullanma" cümlesine ihtiyacın olacak.
Natan Medeiros

10
Daha yavaş olsa da, hariç tutma çözümünün avantajı ertelenebilir olmasıdır (ve varsayılan olarak ifadenin sonuna kadar ertelenir). Bunun aksine, kabul edilen benzersiz dizin çözümü ertelenemez (ve her satır değişikliğinden sonra kontrol edilir). Bu nedenle, atomik güncelleme bildiriminin sonunda ihlal edilmemiş olsa bile, güncelleme sırasındaki adımlar benzersiz kısıtlamayı ihlal edeceğinden toplu güncelleme genellikle mümkün değildir.
sage88

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.