SQL UNIQUE belirli bir sütunda veya sütun grubunda aynı değerin tekrar kullanılmasını engeller; SQL CHECK ise eklenen ya da güncellenen değerin tanımlanan mantıksal koşulu karşılamasını ister. Böylece e-posta adresinin iki öğrenciye atanması veya not alanına 150 yazılması gibi veri bütünlüğünü bozan durumlar veri tabanı seviyesinde durdurulur.
Form kontrolleri ve uygulamadaki if blokları kullanıcıya hızlı geri bildirim verir; ancak farklı bir istemci, yönetim paneli, arka plan görevi ya da doğrudan SQL bağlantısı aynı tabloya erişebilir. Bu nedenle uygulama kontrolü atlandığında bile kuralların korunması için veri tabanı kısıtları son savunma hattı olarak düşünülmelidir. Python projelerinde bu mantığı birebir Python dersleri kapsamında öğrenirken, doğrulamayı yalnızca forma değil veri akışının tamamına yerleştirmek önemlidir.
UNIQUE ve CHECK Kısıtları Neden Gereklidir?
Bir veri tabanı tablosu, yalnızca uygulamanın beklediği yoldan veri almaz. Aynı tabloya mobil istemci, web uygulaması, yönetici ekranı veya zamanlanmış bir görev yazabilir. Bu kaynaklardan biri doğrulama adımını atladığında, hatalı kayıtlar kalıcı hâle gelebilir. UNIQUE ve CHECK kısıtları bu riski azaltarak kuralları doğrudan tablonun yapısına taşır.
- UNIQUE: Tek bir sütundaki veya birlikte değerlendirilen sütun grubundaki değerlerin yinelenmesini engeller. Öğrenci e-posta adresi, kullanıcı adı veya okul numarası gibi alanlarda kullanılabilir.
- CHECK: Bir sütunun belirli bir koşulu sağlamasını ister. Notun 0 ile 100 arasında olması, yaşın negatif olmaması veya durum alanının izin verilen değerlerden birini taşıması buna örnektir.
Bu kısıtlar yalnızca INSERT sırasında değil, mevcut bir kaydı geçersiz hâle getirebilecek UPDATE işlemlerinde de dikkate alınır. Kısıt ihlal edildiğinde veri tabanı işlemi reddeder ve istemci uygulamaya bir hata iletir. Hatanın metni, istisna sınıfı ve ayrıntı alanları kullanılan veri tabanı motoruna ve sürücüsüne göre değişebileceği için uygulama kodu tek bir hata metnini ayrıştırmaya dayanmamalıdır. Örneğin PostgreSQL, bütünlük kısıtı hataları için SQLSTATE kodları ve ilgili kısıt adını sağlayabilir; farklı sistemlerde uygulama arayüzü değişebilir. ([postgresql.org](https://www.postgresql.org/docs/18/sql-createtable.html?utm_source=openai))
Öğrenci Kayıt Tablosunda UNIQUE ve CHECK Tanımlama

Aşağıdaki örnek PostgreSQL sözdizimiyle hazırlanmıştır. Aynı kavramlar başka SQL motorlarında da bulunabilir; ancak veri türleri, kısıt adlandırma ayrıntıları ve hata raporlama biçimi hedef sistemde ayrıca kontrol edilmelidir.
CREATE TABLE ogrenciler (
ogrenci_id INTEGER PRIMARY KEY,
ad_soyad VARCHAR(100) NOT NULL,
eposta VARCHAR(255) NOT NULL UNIQUE,
not_puani INTEGER NOT NULL CHECK (not_puani BETWEEN 0 AND 100)
);
INSERT INTO ogrenciler
(ogrenci_id, ad_soyad, eposta, not_puani)
VALUES
(1, 'Ayşe Yılmaz', '[email protected]', 85);
-- UNIQUE ihlali: aynı e-posta tekrar kullanılamaz
INSERT INTO ogrenciler
(ogrenci_id, ad_soyad, eposta, not_puani)
VALUES
(2, 'Mehmet Kaya', '[email protected]', 90);
-- CHECK ihlali: not 0 ile 100 arasında olmalıdır
INSERT INTO ogrenciler
(ogrenci_id, ad_soyad, eposta, not_puani)
VALUES
(3, 'Zeynep Demir', '[email protected]', 105);
PRIMARY KEY, her öğrenciyi ayırt edenogrenci_iddeğerinin benzersiz ve boş olmamasını sağlar.eposta VARCHAR(255) NOT NULL UNIQUE, e-posta adresinin hem zorunlu olmasını hem de tabloda tekrar etmemesini ister.not_puani INTEGER NOT NULL CHECK (not_puani BETWEEN 0 AND 100), notun boş bırakılamamasını ve yalnızca tanımlanan aralıkta olmasını sağlar.
Burada e-posta benzersizliği ile not aralığı iki farklı veri kuralıdır. Aynı e-postayı yeniden göndermek UNIQUE ihlalidir; 105 gibi aralık dışı bir değer göndermek ise CHECK ihlalidir. PostgreSQL belgelerine göre CHECK ifadesi TRUE veya UNKNOWN sonucunda satırı kabul edebilir; bu nedenle koşulun yanında NOT NULL kullanmak, NULL değerlerin yanlışlıkla geçerli sayılmasını önlemek için önemlidir. ([postgresql.org](https://www.postgresql.org/docs/17/sql-createtable.html?utm_source=openai))
Geçerli ve Hatalı INSERT İşlemlerini Karşılaştırma
Aşağıdaki örnekte e-posta adresinin tekrar etmemesi, notun ise 0 ile 100 arasında olması istenir. Geçerli kayıt eklenirken işlem tamamlanır; aynı e-posta veya izin verilen aralık dışındaki not kullanıldığında veri tabanı satırı kabul etmez.
CREATE TABLE ogrenci (
id INTEGER PRIMARY KEY,
ad VARCHAR(80) NOT NULL,
eposta VARCHAR(120) UNIQUE,
notu INTEGER CHECK (notu BETWEEN 0 AND 100)
);
INSERT INTO ogrenci VALUES (1, 'Ayşe Demir', '[email protected]', 85);
INSERT INTO ogrenci VALUES (2, 'Mehmet Kaya', '[email protected]', 70);
INSERT INTO ogrenci VALUES (3, 'Zeynep Arslan', '[email protected]', 105);
İlk INSERT geçerlidir. İkinci sorguda daha önce kullanılan [email protected] tekrar edildiği için UNIQUE kuralı ihlal edilir. Üçüncü sorgudaki 105 değeri 0–100 aralığının dışında kaldığından CHECK kuralı devreye girer.
| işlem | ihlal edilen kural | beklenen kavramsal sonuç |
|---|---|---|
| Ayşe Demir kaydı | Yok | Satır eklenir. |
| Mehmet Kaya kaydı | UNIQUE: e-posta tekrarı | Satır reddedilir; mevcut kayıt korunur. |
| Zeynep Arslan kaydı | CHECK: not 0–100 dışında | Satır reddedilir; geçersiz değer yazılmaz. |
Hata kodu, mesajın yazımı ve bir hata sonrasında transaction’ın nasıl ele alınacağı veri tabanı motoruna ve kullanılan bağlantı kütüphanesine göre değişebilir. Örneğin PostgreSQL hata kodları dokümantasyonu bütünlük kısıtı ihlallerini ayrı sınıflarda raporlar; bazı transaction akışlarında işlem bloğunun geri alınması veya yeniden başlatılması gerekebilir. Bu nedenle uygulama, belirli bir mesaj metnine güvenmek yerine bağlantı sürücüsünün sunduğu hata türünü ve kısıt adını kontrollü biçimde ele almalıdır.
Uygulama Doğrulaması ile Veri Tabanı Kısıtının Görev Ayrımı

Pratik karar sorusu şudur: Kullanıcıya anında geri bildirim mi lazım, yoksa veri her koşulda bozulmamalı mı? Form alanının boş bırakılmaması, e-posta biçiminin kontrol edilmesi ve not alanına gerçekten sayı girilmesi uygulama katmanında hızlı mesaj göstermek için yapılır. Ancak benzersizlik ve izin verilen değer aralığı, veri tabanına ulaşan her yazma yolunda korunması gereken kurallardır.
| kural | öncelikli katman | gerekçe | diğer katmanda neden tekrar düşünülebilir |
|---|---|---|---|
| Boş alan kontrolü | Uygulama | Kullanıcıya anında ve anlaşılır mesaj verilir. | NOT NULL, doğrudan SQL erişimine karşı son güvenlik katmanıdır. |
| E-posta biçimi | Uygulama | Hatalı giriş form gönderilmeden açıklanabilir. | Gerekirse veri tabanında ek biçim kuralları uygulanabilir. |
| Aynı e-postayı engelleme | Veri tabanı | Tüm servisler ve yazma yolları için geçerlidir. | Uygulama, daha kullanıcı dostu hata mesajı gösterebilir. |
| Notun 0–100 aralığı | Veri tabanı | Toplu aktarımda veya farklı serviste de veri korunur. | Uygulama, aralık dışı değeri önceden işaretleyebilir. |
“Formda kontrol edildiği için UNIQUE veya CHECK gereksizdir” yaklaşımı risklidir. Bir yönetici paneli, toplu içe aktarma betiği veya başka bir servis aynı tabloya yazdığında formdaki kontroller çalışmayabilir. Java ile veri tabanı kullanan öğrenciler, bu katman ayrımını Java özel eğitiminde JDBC işlemleri ve hata yönetimi üzerinden somutlaştırabilir.
- Kullanıcıya hızlı bir doğrulama mesajı gerekiyor mu?
- Aynı anda iki istek gelirse UNIQUE kuralı veri tabanında korunuyor mu?
- Tabloya doğrudan SQL erişimi var mı?
- Toplu içe aktarma sırasında uygulama kontrolleri atlanabilir mi?
- Farklı servisler aynı tabloya yazıyor mu?
Bu sorulardan biri bile “evet” ise, uygulama doğrulamasını veri tabanı kısıtlarının yerine değil, onların önünde çalışan kullanıcı deneyimi katmanı olarak düşünmek gerekir.
Python veya Java'da Kısıt İhlali Hatasını Yönetme
Bir INSERT işlemi uygulama tarafından gönderildiğinde, veri tabanı UNIQUE veya CHECK kısıtını ihlal eden veriyi reddeder. Python tarafında bu sonuç bir istisna olarak try-except bloğunda, Java tarafında ise try-catch bloğunda yakalanabilir. Amaç, ham hata metnini kullanıcıya göstermek değil; teknik sonucu anlaşılır ve güvenli bir mesaja dönüştürmektir.
Örneğin e-posta adresi zaten kullanılıyorsa kullanıcıya “Bu e-posta adresi zaten kayıtlı.”, not aralık dışındaysa “Not 0 ile 100 arasında olmalıdır.” mesajı gösterilebilir. Bu ayrım mümkünse hata metnini arayarak değil, kısıt adı, hata kodu veya sürücünün sağladığı yapılandırılmış alanlar üzerinden yapılmalıdır. Böylece hata mesajı dili, sürüm veya veri tabanı ayarları değişse bile uygulamanın davranışı daha kararlı olur.
Python’da PostgreSQL ile kullanılan Psycopg sürücüsü, benzersizlik ihlali için UniqueViolation, kontrol koşulu ihlali için CheckViolation sınıflarını sunar. Hatanın diag alanında sunucudan gelen constraint_name ve sqlstate gibi bilgiler bulunabilir. PostgreSQL için benzersizlik ihlalinin SQLSTATE kodu 23505, CHECK ihlalinin kodu ise 23514 olarak belgelenmiştir. Bu ayrıntılar belirli bir sürücü ve veri tabanı kombinasyonuna aittir; başka sistemlerde istisna sınıfları, alan adları ve kodlar değişebilir. ([psycopg.org](https://www.psycopg.org/psycopg3/docs/api/errors.html?utm_source=openai))
Kavramsal Python akışı şu şekilde düşünülebilir:
- Form verilerini temel biçim kontrollerinden geçir.
INSERTkomutunu parametreli olarak çalıştır.- Önce özel kısıt ihlali türlerini yakala.
constraint_nameveya SQLSTATE bilgisine göre kullanıcı mesajı seç.- Beklenmeyen hataları logla, kullanıcıya genel bir işlem hatası göster.
Java’da da aynı karar mantığı SQLException veya kullanılan veri erişim katmanının sunduğu daha özel istisnalar üzerinden kurulabilir. Örneğin getSQLState(), hata kodu ya da sürücünün eklediği hata bilgileri incelenebilir. Ancak yalnızca hata mesajında “duplicate” veya “check” kelimesi geçiyor diye karar vermek kırılgan bir yaklaşımdır.
Bu ayrımı uygularken birebir Python ve Java dersleri kapsamında özellikle parametreli sorgu, istisna yönetimi ve veri tabanı katmanlarının birlikte tasarlanması üzerinde çalışılabilir.
Ham hata mesajını son kullanıcıya aktarmayın. Bu mesajlar tablo veya kısıt adlarını açığa çıkarabilir, teknik terimler içerebilir ve kullanıcıya ne yapması gerektiğini anlatmayabilir. Teknik ayrıntıyı geliştirici loglarında saklayıp arayüzde kısa, eyleme dönük ve güvenli bir açıklama kullanmak daha doğrudur.
UNIQUE, CHECK, NOT NULL ve PRIMARY KEY Farkları
Bu dört kısıt aynı tabloda birlikte kullanılabilir; ancak her biri farklı bir veri bütünlüğü sorusunu çözer. PostgreSQL belgelerinde PRIMARY KEY değerlerin hem benzersiz hem de boş olmamasını zorunlu kılar. UNIQUE ise bir sütunun veya sütun grubunun tekrar etmesini sınırlar. CHECK satırdaki değerlerin belirli bir koşula uymasını ister; NOT NULL ise değerin boş bırakılmasını engeller. ([postgresql.org](https://www.postgresql.org/docs/18/ddl-constraints.html?utm_source=openai))
- PRIMARY KEY: Satırı benzersiz biçimde tanımlayan anahtardır. Bir tabloda tek bir primary key tanımı bulunur; bu tanım tek sütunlu veya bileşik olabilir.
- UNIQUE: E-posta, kullanıcı adı veya birden fazla sütunun kombinasyonu gibi alanlarda tekrarları sınırlar. Bir tabloda birden fazla UNIQUE kısıtı bulunabilir.
- CHECK: Yaşın negatif olmaması veya notun 0–100 arasında kalması gibi koşulları denetler.
- NOT NULL: Alanın boş bırakılmasını engeller. CHECK koşulu tek başına her zaman NOT NULL yerine geçmez; çünkü bazı sistemlerde NULL değerler koşul değerlendirmesinden farklı şekilde ele alınabilir.
Bileşik UNIQUE kısıtında tek tek sütunların değil, birlikte değerlendirilen değer kombinasyonunun tekrar edip etmediği önemlidir. NULL değerlerin UNIQUE karşılaştırmasına nasıl katıldığı ise veri tabanı motoruna ve yapılandırmasına göre değişebilir. Bu nedenle taşınabilir bir uygulamada NULL davranışını kullandığınız sistemin belgeleriyle doğrulamak gerekir. ([postgresql.org](https://www.postgresql.org/docs/18/ddl-constraints.html?utm_source=openai))
Tablo tasarlarken şu dört soruluk kontrol listesini kullanın:
- Bu alan satırı tanımlıyor mu?
- Tekrar edebilir mi?
- Hangi aralık veya koşul geçerli?
- Boş bırakılabilir mi?
Sık Sorulan Sorular
UNIQUE kısıtı varken e-posta adresini uygulama kodunda da kontrol etmek gerekir mi?
Evet, kullanıcıya hızlı ve anlaşılır geri bildirim vermek için uygulama katmanında kontrol yapılabilir. Ancak kesin güvence veri tabanındaki UNIQUE kısıtından gelmelidir; iki isteğin aynı anda gelmesi gibi durumlarda yalnızca uygulama kontrolü yeterli olmaz.
CHECK kısıtı bir sütunun 0 ile 100 arasında olmasını nasıl sağlar?
Örneğin CHECK (notu >= 0 AND notu <= 100) koşulu, eklenen veya güncellenen satırdaki notun belirtilen aralıkta olmasını ister. Alanın boş kalması da engellenecekse ayrıca NOT NULL kullanılmalıdır.
UNIQUE veya CHECK ihlalinde kullanıcıya veri tabanının ham hata mesajı gösterilmeli mi?
Hayır. Ham mesaj teknik ayrıntılar ve iç yapı bilgileri içerebilir. Uygulama, yapılandırılmış hata bilgisine göre güvenli bir kullanıcı mesajı üretmeli; ayrıntılı teknik kayıt ise log sistemine yazılmalıdır.
Bir tabloda PRIMARY KEY ve UNIQUE kısıtı aynı anda kullanılabilir mi?
Evet. Primary key satırın ana kimliğini belirlerken UNIQUE e-posta veya kullanıcı adı gibi başka bir alanın tekrarını sınırlayabilir.
Uygulama katmanı doğrulaması ile veri tabanı doğrulaması arasındaki temel fark nedir?
Uygulama doğrulaması anında kullanıcı geri bildirimi sağlar; veri tabanı kısıtı ise farklı uygulamalardan veya doğrudan SQL işlemlerinden gelen verilerde bütünlüğü korur.
Doğru tasarım, bu iki katmanı birbirinin alternatifi değil, tamamlayıcısı olarak kullanır.