PostgreSQL'de kısıtlar, veri tiplerinin tek başına sağlayamadığı kuralları veritabanı düzeyinde zorunlu kılar: PRIMARY KEY satırı benzersiz ve NULL olmayan bir anahtarla tanımlar, FOREIGN KEY (REFERENCES) başka bir tablodaki var olan bir satıra başvurmayı şart koşar ve ON DELETE ile başvurulan satır silinince ne olacağını belirler, UNIQUE tekrarı, CHECK koşula uymayan değeri, NOT NULL boş değeri, EXCLUDE ise çakışan aralıkları engeller. Bir kural ihlal edildiğinde komut hata verir ve satır yazılmaz.

Bu yazıda kılavuzun Constraints bölümünü, Tutorial'daki foreign key örneğini ve CREATE TABLE, ALTER TABLE başvuru sayfalarındaki ayrıntıları; PostgreSQL 18 ile gelen NOT ENFORCED ve adlandırılabilir NOT NULL kısıtlarıyla birlikte örneklerle anlatıyoruz. Bütün hata çıktıları PostgreSQL 18.1'de ornek_kisit veritabanında alındı. Tablo oluşturmanın genel söz dizimi CREATE TABLE ve ALTER TABLE yazısında; serinin geri kalanı PostgreSQL öğrenme rehberi sayfasında. Çıktılarda yer kazanmak için CREATE ve INSERT gibi komutların onay satırlarını yer yer çıkardık; sorgu sonuçları ve hata mesajları olduğu gibidir.

Örnek şema: müşteri, sipariş, sipariş kalemi

Örnek şema: müşteri, sipariş, sipariş kalemi

Kısıt türlerinin hepsini görebilmek için üç tablolu küçük bir sipariş şeması kuruyoruz. Sütun kısıtları sütun tanımının hemen ardından, tablo kısıtları ise virgülle ayrılmış ayrı bir öğe olarak yazılır; belge birden çok sütunu kapsayan kısıtların tablo kısıtı olarak yazılması gerektiğini, her sütun kısıtının da tablo kısıtı olarak yazılabileceğini belirtir. CONSTRAINT ad ile verdiğimiz adlar hata mesajlarında görünür ve kısıtı sonradan değiştirmek için gerekir; ad vermezseniz sistem tablo_sütun_check gibi bir ad seçer.

sql
CREATE TABLE musteri (
    musteri_no integer PRIMARY KEY,
    ad         text NOT NULL,
    eposta     text UNIQUE,
    vergi_no   text CONSTRAINT vergi_no_10_hane CHECK (length(vergi_no) = 10)
);
CREATE TABLE siparis (
    siparis_no integer PRIMARY KEY,
    musteri_no integer NOT NULL REFERENCES musteri ON DELETE RESTRICT,
    tutar      numeric(10,2) CHECK (tutar > 0),
    indirim    numeric(10,2) DEFAULT 0,
    CONSTRAINT indirim_tutardan_kucuk CHECK (indirim < tutar)
);
CREATE TABLE siparis_kalemi (
    siparis_no integer REFERENCES siparis ON DELETE CASCADE,
    satir      integer,
    urun       text NOT NULL,
    adet       integer NOT NULL CHECK (adet > 0),
    PRIMARY KEY (siparis_no, satir)
);
INSERT INTO musteri VALUES (1, 'Zeynep Kaya', 'zeynep@ornek.com.tr', '1234567890');
INSERT INTO musteri VALUES (2, 'Burak Demir', NULL, NULL);
INSERT INTO siparis VALUES (100, 1, 250.00, 25.00);
INSERT INTO siparis_kalemi VALUES (100, 1, 'Kahve', 2), (100, 2, 'Fincan', 4);

REFERENCES musteri yazarken sütun belirtmedik; belgeye göre sütun listesi verilmezse başvurulan tablonun birincil anahtarı kullanılır. siparis_kalemi tablosunun birincil anahtarı iki sütundan oluşuyor ve yabancı anahtarla örtüşüyor; bu, bir siparişin parçası olan kalemler için tipik bir tasarımdır.

Her kısıt türü nasıl hata verir?

Aşağıdaki altı komutun her biri farklı bir kısıtı ihlal ediyor. Hata mesajlarını tanımak, uygulamanızın günlüklerinde ne olduğunu hızla anlamanızı sağlar:

sql
INSERT INTO musteri VALUES (1, 'Ali Veli', NULL, NULL);
INSERT INTO musteri VALUES (3, NULL, NULL, NULL);
INSERT INTO musteri VALUES (3, 'Selin Ak', 'zeynep@ornek.com.tr', NULL);
INSERT INTO musteri VALUES (3, 'Selin Ak', NULL, '12345');
INSERT INTO siparis VALUES (101, 99, 100.00, 0);
INSERT INTO siparis VALUES (102, 2, 50.00, 60.00);
text
ERROR:  duplicate key value violates unique constraint "musteri_pkey"
DETAIL:  Key (musteri_no)=(1) already exists.
ERROR:  null value in column "ad" of relation "musteri" violates not-null constraint
DETAIL:  Failing row contains (3, null, null, null).
ERROR:  duplicate key value violates unique constraint "musteri_eposta_key"
DETAIL:  Key (eposta)=(zeynep@ornek.com.tr) already exists.
ERROR:  new row for relation "musteri" violates check constraint "vergi_no_10_hane"
DETAIL:  Failing row contains (3, Selin Ak, null, 12345).
ERROR:  insert or update on table "siparis" violates foreign key constraint "siparis_musteri_no_fkey"
DETAIL:  Key (musteri_no)=(99) is not present in table "musteri".
ERROR:  new row for relation "siparis" violates check constraint "indirim_tutardan_kucuk"
DETAIL:  Failing row contains (102, 2, 50.00, 60.00).

Çıktıdaki her satırın başında psql'in eklediği psql:ks1.sql:27: gibi dosya ve satır bilgisini kısalık için çıkardık. Birincil anahtar ve UNIQUE ihlalleri aynı mesajla (duplicate key value) gelir, çünkü ikisi de arka planda benzersiz bir B-tree indeksle uygulanır; farkı kısıt adından anlarsınız. Kısıt adı vermek bu yüzden yararlıdır: vergi_no_10_hane adı, otomatik üretilmiş bir addan çok daha açıklayıcıdır. Bu hataların SQLSTATE kodları (23505, 23502, 23514, 23503) ve uygulamada nasıl yakalanacakları sık hatalar ve SQLSTATE kodları yazısında.

PRIMARY KEY ve UNIQUE

Birincil anahtar, değerlerin hem benzersiz hem NULL olmayan olmasını gerektirir; belgeye göre UNIQUE NOT NULL ile aynı veriyi kabul eder. Fark anlamdadır: bir tabloda en fazla bir birincil anahtar olabilir, yabancı anahtarlar sütun belirtilmediğinde onu hedef alır ve istemci araçları satırları onunla tanımlar. Belge, PostgreSQL bunu zorlamasa da her tablonun bir birincil anahtarı olmasını önerir. Birincil anahtar ve benzersizlik kısıtı eklemek otomatik olarak benzersiz bir B-tree indeks oluşturur; birincil anahtar ayrıca sütunları NOT NULL yapar.

UNIQUE kısıtında NULL'ların davranışı sık şaşırtır. Varsayılan olarak iki NULL eşit sayılmaz; bu yüzden benzersiz bir sütunda istediğiniz kadar NULL bulunabilir. Örnek şemamızda e-postası olmayan iki müşteri sorunsuz eklendi. Belge, SQL standardının bu konuyu uygulamaya bıraktığını ve diğer sistemlerin farklı davranabileceğini hatırlatır. NULL'ların da tek sayılmasını istiyorsanız NULLS NOT DISTINCT yazarsınız:

sql
INSERT INTO musteri VALUES (4, 'Can Er', NULL, NULL);
SELECT count(*) AS eposta_bos FROM musteri WHERE eposta IS NULL;
CREATE TABLE kupon (kod text UNIQUE NULLS NOT DISTINCT, oran integer);
INSERT INTO kupon VALUES (NULL, 5);
INSERT INTO kupon VALUES (NULL, 10);
text
 eposta_bos 
------------
          2
(1 row)

CREATE TABLE
INSERT 0 1
psql:ks2.sql:4: ERROR:  duplicate key value violates unique constraint "kupon_kod_key"
DETAIL:  Key (kod)=(null) already exists.

Yalnızca bazı satırlarda geçerli olan bir benzersizlik kuralı (örneğin yalnızca aktif kayıtlar arasında tekil e-posta) UNIQUE kısıtıyla yazılamaz; belge bunun için kısmi benzersiz indeks önerir, indeks türleri yazısında örneği var. Ayrıca bir birincil anahtarı silmek, ona başvuran yabancı anahtarlar varken mümkün değildir:

sql
ALTER TABLE musteri DROP CONSTRAINT musteri_pkey;
text
ERROR:  cannot drop constraint musteri_pkey on table musteri because other objects depend on it
DETAIL:  constraint siparis_musteri_no_fkey on table siparis depends on index musteri_pkey
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

NOT NULL ve CHECK

NOT NULL bir sütunun NULL olamayacağını söyler. Belgeye göre CHECK (sütun IS NOT NULL) ile işlevsel olarak eşdeğerdir ama PostgreSQL'de açık bir not-null kısıtı daha verimlidir ve bir sütunun en fazla bir açık not-null kısıtı olabilir. Belgenin tavsiyesi nettir: çoğu tasarımda sütunların büyük kısmı not null olmalıdır. PostgreSQL 18 sürüm notlarına göre sütunların NOT NULL tanımları artık pg_constraint katalogunda saklanıyor; bu sayede not-null kısıtlarına ad verilebiliyor ve ALTER TABLE ile NOT VALID olarak eklenebiliyor:

sql
CREATE TABLE personel (sicil integer CONSTRAINT sicil_zorunlu NOT NULL, ad text NOT NULL);
SELECT conname, contype FROM pg_constraint WHERE conrelid = 'personel'::regclass ORDER BY conname;
ALTER TABLE personel ALTER COLUMN ad DROP NOT NULL;
text
       conname        | contype 
----------------------+---------
 personel_ad_not_null | n
 sicil_zorunlu        | n
(2 rows)

ALTER TABLE

contype = n not-null kısıtını gösteriyor; ad vermediğimiz sütun için sistem personel_ad_not_null adını seçti. Not-null kısıtını kaldırmanın en kısa yolu yine ALTER COLUMN ... DROP NOT NULL, eklemenin yolu SET NOT NULL biçimidir; belge ikisinin de kısıt zaten istenen durumdaysa sessizce hiçbir şey yapmadığını belirtir.

CHECK en genel kısıttır ve bir boolean ifadenin doğru olmasını ister. Gözden kaçan kural şudur: belgeye göre kontrol ifadesi doğru veya NULL sonuç verdiğinde kısıt sağlanmış sayılır. İfadelerin çoğu bir işleneni NULL olduğunda NULL döndürdüğü için CHECK tek başına NULL değerleri engellemez:

sql
INSERT INTO siparis VALUES (103, 2, NULL, 10.00);
SELECT siparis_no, tutar, indirim FROM siparis ORDER BY siparis_no;
text
INSERT 0 1
 siparis_no | tutar  | indirim 
------------+--------+---------
        100 | 250.00 |   25.00
        103 |        |   10.00
(2 rows)

tutar > 0 ve indirim < tutar kontrollerinin ikisi de NULL döndürdüğü için tutarı boş bir sipariş kabul edildi. Tutarın zorunlu olması gerekiyorsa sütuna ayrıca NOT NULL ekleyin. Belgenin iki önemli uyarısı daha var. Birincisi, CHECK yalnızca kontrol edilen satırın değerlerine bakmalıdır; başka satırlara veya tablolara başvuran bir kontrol basit testlerde çalışıyor gibi görünse de tutarlılığı garanti etmez ve döküm geri yüklenirken başarısız olabilir. Satırlar ve tablolar arası kurallar için UNIQUE, EXCLUDE veya FOREIGN KEY kullanın. İkincisi, PostgreSQL CHECK ifadesinin değişmez olduğunu varsayar; içinde kullandığınız bir fonksiyonun davranışını sonradan değiştirirseniz mevcut satırlar yeniden kontrol edilmez. Belge bu durumda kısıtı silip fonksiyonu değiştirmeyi ve kısıtı yeniden eklemeyi önerir. Birden çok CHECK kısıtı olan tabloda kontroller, not-null kısıtlarından sonra, ada göre alfabetik sırayla yapılır.

FOREIGN KEY ve ON DELETE davranışları

FOREIGN KEY ve ON DELETE davranışları: NO ACTION (varsayılan), RESTRICT, CASCADE, SET NULL

Yabancı anahtar, bir sütun grubundaki değerlerin başka bir tablodaki bir satırla eşleşmesini zorunlu kılar; buna referans bütünlüğü denir. Başvurulan sütunlar birincil anahtar, benzersizlik kısıtı veya kısmi olmayan benzersiz bir indeks olmalıdır. Başvuran tarafta bir veya daha fazla sütun NULL ise satırın eşleşme koşulunu sağlaması gerekmez; bunu istemiyorsanız başvuran sütunları NOT NULL yapın ya da çok sütunlu anahtarlarda MATCH FULL kullanın.

Başvurulan satır silindiğinde veya anahtarı güncellendiğinde ne olacağını ON DELETE ve ON UPDATE belirler. Örnek şemamızda müşteri için RESTRICT, sipariş kalemleri için CASCADE seçmiştik:

sql
DELETE FROM musteri WHERE musteri_no = 1;
DELETE FROM siparis WHERE siparis_no = 100;
SELECT count(*) AS kalan_kalem FROM siparis_kalemi;
text
ERROR:  update or delete on table "musteri" violates RESTRICT setting of foreign key constraint "siparis_musteri_no_fkey" on table "siparis"
DETAIL:  Key (musteri_no)=(1) is referenced from table "siparis".
DELETE 1
 kalan_kalem 
-------------
           0
(1 row)

Siparişi olan müşteri silinemedi; silinen siparişin iki kalemi ise kendiliğinden gitti. SET NULL eylemi başvuran sütunu NULL yapar ve bilginin isteğe bağlı olduğu ilişkiler için uygundur:

sql
CREATE TABLE temsilci (id integer PRIMARY KEY, ad text);
CREATE TABLE bayi (id integer PRIMARY KEY, ad text,
    temsilci_id integer REFERENCES temsilci ON DELETE SET NULL);
INSERT INTO temsilci VALUES (7, 'Elif Arslan');
INSERT INTO bayi VALUES (1, 'Ankara Bayi', 7);
DELETE FROM temsilci WHERE id = 7;
SELECT * FROM bayi;
text
 id |     ad      | temsilci_id 
----+-------------+-------------
  1 | Ankara Bayi |            
(1 row)
EylemBaşvurulan satır silininceNe zaman uygun
NO ACTION (varsayılan)Komutun sonunda başvuran satır varsa hata; ertelenebilirBağımsız nesneler, ertelenmiş kontrol gerekiyorsa
RESTRICTHemen hata; ertelenemezBağımsız nesneler, silme kesinlikle engellenmeli
CASCADEBaşvuran satırlar da silinirParçası olduğu bütün olmadan var olamayan kayıtlar
SET NULLBaşvuran sütunlar NULL olurİsteğe bağlı ilişki
SET DEFAULTBaşvuran sütunlar varsayılanına dönerVarsayılan değer geçerli bir anahtar ise

Belgenin seçim için verdiği ölçüt şudur: başvuran kayıt, başvurulan kaydın bir parçasıysa ve tek başına var olamıyorsa (sipariş kalemi ile sipariş gibi) CASCADE uygun olabilir; iki tablo bağımsız nesneleri temsil ediyorsa (müşteri ile sipariş gibi) RESTRICT ya da NO ACTION daha doğrudur ve ikisini birden silmek isteyen uygulama bunu açıkça iki komutla yapmalıdır. NO ACTION ile RESTRICT arasındaki fark, ertelenmiş kontrolde ortaya çıkar: NO ACTION aynı transaction içinde durumu düzeltmenize izin verir, RESTRICT izin vermez. SET NULL ve SET DEFAULT diğer kısıtlardan muaf değildir; örneğin varsayılan değer başvurulan tabloda yoksa silme yine başarısız olur. PostgreSQL bu eylemlere sütun listesi vermenize de izin verir: ON DELETE SET NULL (author_id) gibi bir tanım, çok sütunlu bir anahtarda yalnızca belirtilen sütunu boşaltır.

Ertelenebilir kısıtlar: DEFERRABLE

Varsayılan olarak kısıtlar her komuttan sonra kontrol edilir. UNIQUE, PRIMARY KEY, EXCLUDE ve yabancı anahtar kısıtları DEFERRABLE tanımlanabilir; bu durumda transaction içinde SET CONSTRAINTS ... DEFERRED ile kontrol transaction sonuna bırakılabilir. NOT NULL ve CHECK ertelenemez. Başvuru sayfasının Compatibility bölümü bir ayrıntıyı daha açıklar: ertelenemez bir UNIQUE veya birincil anahtar kısıtını PostgreSQL her satır eklenir veya değiştirilirken hemen kontrol eder, SQL standardı ise kontrolün komut sonunda yapılmasını ister. Standart davranış için kısıtı DEFERRABLE INITIALLY IMMEDIATE tanımlamanız önerilir. Farkı iki satırın sırasını tek komutla değiştirerek gördük:

sql
CREATE TABLE sira (konum integer UNIQUE DEFERRABLE INITIALLY IMMEDIATE, ad text);
INSERT INTO sira VALUES (1, 'birinci'), (2, 'ikinci');
UPDATE sira SET konum = CASE konum WHEN 1 THEN 2 ELSE 1 END;
CREATE TABLE sira2 (konum integer UNIQUE, ad text);
INSERT INTO sira2 VALUES (1, 'a'), (2, 'b');
UPDATE sira2 SET konum = CASE konum WHEN 1 THEN 2 ELSE 1 END;
text
UPDATE 2
ERROR:  duplicate key value violates unique constraint "sira2_konum_key"
DETAIL:  Key (konum)=(2) already exists.

Ertelenebilir kısıtlı tabloda değiş tokuş başarılı oldu, normal tabloda ise ilk satır güncellenir güncellenmez çakışma yakalandı. Kontrolü transaction sonuna ertelemek için:

sql
BEGIN;
SET CONSTRAINTS ALL DEFERRED;
UPDATE sira SET konum = 3 WHERE konum = 1;
UPDATE sira SET konum = 1 WHERE konum = 2;
UPDATE sira SET konum = 2 WHERE konum = 3;
COMMIT;

Belge iki bedel hatırlatır: ertelenebilir benzersizlik kontrolü anlık kontrolden belirgin biçimde yavaş olabilir ve ertelenebilir kısıtlar INSERT ... ON CONFLICT komutunda çakışma hakemi olarak kullanılamaz; UPSERT yazısına bakın.

EXCLUDE: çakışan aralıkları engellemek

Dışlama kısıtı, belirtilen sütunlar belirtilen operatörlerle karşılaştırıldığında herhangi iki satır için karşılaştırmaların hepsinin doğru dönmemesini garanti eder. Bütün operatörler eşitlik olsaydı bu UNIQUE ile aynı olurdu; asıl değeri, örneğin aralıkların kesişimini (&&) yasaklayabilmesidir. Pratikte GiST veya SP-GiST indeksiyle uygulanır. Bir toplantı odasının aynı zaman diliminde iki kez ayrılmasını engelleyelim:

sql
CREATE TABLE toplanti_odasi (oda text, zaman tstzrange,
    EXCLUDE USING gist (zaman WITH &&));
INSERT INTO toplanti_odasi VALUES ('Mavi', '[2026-11-10 10:00+03, 2026-11-10 11:00+03)');
INSERT INTO toplanti_odasi VALUES ('Mavi', '[2026-11-10 10:30+03, 2026-11-10 12:00+03)');
INSERT INTO toplanti_odasi VALUES ('Mavi', '[2026-11-10 11:00+03, 2026-11-10 12:00+03)');
text
INSERT 0 1
ERROR:  conflicting key value violates exclusion constraint "toplanti_odasi_zaman_excl"
DETAIL:  Key (zaman)=(["2026-11-10 10:30:00+03","2026-11-10 12:00:00+03")) conflicts with existing key (zaman)=(["2026-11-10 10:00:00+03","2026-11-10 11:00:00+03")).
INSERT 0 1

Aralıklar [ ile kapalı, ) ile açık uçlu yazıldığı için 11:00'de başlayan üçüncü toplantı ilkiyle çakışmadı. Bu örnekte kısıt bütün odalar için geçerli; oda başına kural yazmak için oda WITH = öğesini de eklemek gerekir, ancak kılavuzun Range Types bölümüne göre düz bir metin veya sayı sütununu GiST dışlama kısıtında eşitlikle karşılaştırmak için btree_gist eklentisinin kurulması gerekir; bu yazıda eklenti kurmadan kalıyoruz. PostgreSQL 18 sürüm notlarına göre aynı ihtiyaç için artık birincil anahtar ve UNIQUE kısıtlarında WITHOUT OVERLAPS, yabancı anahtarlarda PERIOD kullanılabilen zamansal kısıtlar da var; özet PostgreSQL 18 yenilikleri yazısında.

Büyük tablolara kısıt eklemek: NOT VALID ve VALIDATE

ALTER TABLE ... ADD CONSTRAINT normalde bütün tabloyu tarayıp mevcut satırların kısıtı sağladığını doğrular; büyük tablolarda bu uzun sürer ve komut tamamlanana kadar diğer güncellemeler bekler. NOT VALID seçeneği (yabancı anahtar, CHECK ve not-null kısıtları için) bu taramayı atlar: kısıt hemen yeni satırlara uygulanmaya başlar ama mevcut satırlar daha sonra VALIDATE CONSTRAINT ile doğrulanır. Belgeye göre doğrulama adımı yalnızca SHARE UPDATE EXCLUSIVE kilit alır ve eşzamanlı güncellemeleri durdurmaz. Bu yöntem, kuralı ihlal eden eski satırları olan bir tabloda da işe yarar:

sql
CREATE TABLE eski_fatura (no integer, tutar numeric);
INSERT INTO eski_fatura VALUES (1, 100), (2, -5);
ALTER TABLE eski_fatura ADD CONSTRAINT tutar_pozitif CHECK (tutar > 0);
ALTER TABLE eski_fatura ADD CONSTRAINT tutar_pozitif CHECK (tutar > 0) NOT VALID;
INSERT INTO eski_fatura VALUES (3, -1);
ALTER TABLE eski_fatura VALIDATE CONSTRAINT tutar_pozitif;
UPDATE eski_fatura SET tutar = 5 WHERE no = 2;
ALTER TABLE eski_fatura VALIDATE CONSTRAINT tutar_pozitif;
text
ERROR:  check constraint "tutar_pozitif" of relation "eski_fatura" is violated by some row
ALTER TABLE
ERROR:  new row for relation "eski_fatura" violates check constraint "tutar_pozitif"
DETAIL:  Failing row contains (3, -1).
ERROR:  check constraint "tutar_pozitif" of relation "eski_fatura" is violated by some row
UPDATE 1
ALTER TABLE

Sırayla: doğrudan ekleme eski hatalı satır yüzünden reddedildi; NOT VALID ile eklenen kısıt yeni hatalı satırı hemen engelledi; ilk doğrulama hâlâ düzeltilmemiş satır olduğu için başarısız oldu; satır düzeltildikten sonra doğrulama geçti. Kısıtın durumunu pg_constraint içindeki convalidated sütunu gösterir.

NOT ENFORCED: PostgreSQL 18 ile gelen belge niteliğinde kısıt

PostgreSQL 18 sürüm notlarına göre CHECK ve yabancı anahtar kısıtları artık NOT ENFORCED olarak tanımlanabiliyor ve pg_constraint kataloguna conenforced sütunu eklendi. Böyle bir kısıt veritabanı tarafından kontrol edilmez; kuralın sağlanması uygulamanın sorumluluğundadır. Belge bunu, çalışma zamanında kontrolü çok pahalı olan kurallar için belge niteliğinde kullanılabilecek bir seçenek olarak tanımlar ve sistemin yine de verinin kısıtı sağladığını varsayıp bunu sonucu değiştirmeyecek optimizasyonlarda kullanabileceğini belirtir. Diğer kısıt türlerinde desteklenmez:

sql
ALTER TABLE eski_fatura ADD CONSTRAINT no_kucuk CHECK (no < 1000) NOT ENFORCED;
INSERT INTO eski_fatura VALUES (5000, 10);
ALTER TABLE eski_fatura ADD CONSTRAINT x UNIQUE (no) NOT ENFORCED;
text
ALTER TABLE
INSERT 0 1
ERROR:  UNIQUE constraints cannot be marked NOT ENFORCED
LINE 1: ...ER TABLE eski_fatura ADD CONSTRAINT x UNIQUE (no) NOT ENFORC...
                                                             ^

Kurala aykırı 5000 numaralı satır kabul edildi. Bu yüzden NOT ENFORCED kısıtı veri doğruluğu için değil, şemanın niyetini belgelemek için düşünün. Başvuru sayfasına göre NOT ENFORCED bir kısıtı VALIDATE CONSTRAINT ile doğrulamaya çalışmak hata verir.

Sık yapılan hatalar

Sık yapılan hatalar: CHECK'in NULL'ı engellediğini sanmak, UNIQUE sütunda tek NULL beklemek, Yabancı anahtar sütununu indekslememek, Her yerde CASCADE kullanmak
  • CHECK'in NULL'ı engellediğini sanmak: NULL sonuç kısıtı sağlar; zorunlu alanlara ayrıca NOT NULL ekleyin.
  • UNIQUE sütunda tek NULL beklemek: Varsayılan olarak birden çok NULL kabul edilir; tek NULL istiyorsanız NULLS NOT DISTINCT kullanın.
  • Yabancı anahtar sütununu indekslememek: Başvurulan tablodan silme ve güncellemeler yavaşlar; kısıt indeks oluşturmaz.
  • Her yerde CASCADE kullanmak: Bağımsız nesneler arasında ON DELETE CASCADE, tek bir yanlış silmenin zincirleme veri kaybına dönüşmesine yol açabilir.
  • CHECK içinde başka tabloya bakmak: Fonksiyon aracılığıyla bile olsa belge bunu desteklemez; tablolar arası kurallar için yabancı anahtar veya tetikleyici kullanın (trigger yazısı).
  • Kısıtlara ad vermemek: Otomatik adlar sürüm ve tablo adına göre değişebilir; hata mesajlarında ve göç betiklerinde anlamlı adlar işinizi kolaylaştırır.
  • Büyük tabloya doğrudan kısıt eklemek: Tarama süresince güncellemeler bekler; NOT VALID ve ardından VALIDATE CONSTRAINT kullanın.

Sık Sorulan Sorular

Bir tablonun kısıtlarını nasıl listelerim?

psql'de \d tablo indeksleri, CHECK kısıtlarını, yabancı anahtarları ve tabloya başvuran diğer tabloları ayrı başlıklar altında gösterir. SQL ile SELECT conname, contype FROM pg_constraint WHERE conrelid = 'tablo'::regclass; sorgusu kullanılabilir; contype değerleri p birincil anahtar, u benzersizlik, f yabancı anahtar, c check, n not-null, x dışlama kısıtıdır.

Kısıt adını sonradan değiştirebilir miyim?

Evet, ALTER TABLE tablo RENAME CONSTRAINT eski TO yeni; biçimi vardır. Bir kısıtı silmek için adını bilmeniz gerekir; ad vermediyseniz \d çıktısından bulun.

Yabancı anahtar kontrolünü geçici olarak kapatabilir miyim?

Kalıcı bir kural için doğru yol, kısıtı DEFERRABLE tanımlayıp transaction içinde SET CONSTRAINTS ... DEFERRED kullanmaktır; kontrol yine yapılır ama transaction sonunda. Toplu yükleme sırasında kısıtı silip sonra NOT VALID ile ekleyip doğrulamak da bir seçenektir. Kontrolü tamamen kaldırıp kuralı yalnızca belgelemek istiyorsanız PostgreSQL 18'deki NOT ENFORCED seçeneği vardır, ama bu durumda veri tutarlılığı garanti edilmez.

ON UPDATE CASCADE ne işe yarar?

Başvurulan anahtar değeri değiştiğinde yeni değeri başvuran satırlara kopyalar. Anahtar değerleri hiç değişmeyen yapay anahtarlar (identity gibi) kullanıyorsanız buna genellikle ihtiyaç olmaz; doğal anahtarların değişebildiği tasarımlarda işe yarar.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PostgreSQL öğrenme rehberi · CREATE TABLE ve ALTER TABLE · İndeks türleri · UPSERT ve ON CONFLICT · SQLSTATE hata kodları · Trigger oluşturma