Postgresql veritabanlarının NULL kayıtlardaki davranışı
Veritabanı yönetim sistemlerinde NULL, çoğu zaman yanlış anlaşılan ve beklenmedik sonuçlara yol açabilen özel bir kavramdır.
PostgreSQL’de NULL değeri, bir verinin atanmadığını veya mevcut olmadığını temsil eder. Kafa karıştırıcı olan nokta, NULL değerinin sıfır (0) veya boş bir metin (”) ile aynı şey olmamasıdır.
SQL standartlarına göre NULL hiçbir şeye eşit değildir, kendisine bile. Bu nedenle klasik eşittir (=) operatörüyle sorgulama yapamazsınız.
- Yanlış: SELECT * FROM tablo WHERE kolon = NULL; (Hiçbir sonuç dönmez)
- Doğru: SELECT * FROM tablo WHERE kolon IS NULL;
PostgreSQL sorguları değerlendirirken sadece TRUE veya FALSE değil, aynı zamanda UNKNOWN sonucunu da kullanır. Bir NULL değerini herhangi bir sayıyla toplarsanız veya karşılaştırırsanız, sonuç her zaman NULL (UNKNOWN) olur.
Postgresql veritabanlarında NULL olan kayıtlar için diğer veritabanlarına göre davranışı biraz farklıdır.
NULL Nedir? Ne Değildir?
| Değer | Anlamı | NULL ile Eşit mi? |
| 0 (sayı) | Sıfır değeri | Hayır |
| ” (boş string) | Uzunluğu 0 olan karakter dizisi | Hayır |
| false (boolean) | Mantıksal yanlış | Hayır |
| NULL | Bilinmiyor / Tanımsız | Hayır (kendisiyle bile eşit değildir!) |
PostgreSQL’de NULL = NULL ifadesinin sonucu NULL (bilinmiyor) olarak değerlendirilir, true değil. Bu nedenle eşitlik kontrolü için = yerine IS NULL operatörü kullanılmalıdır.
-- Yanlış kullanım:
SELECT * FROM users WHERE age = NULL; -- Hiç sonuç döndürmez
-- Doğru kullanım:
SELECT * FROM users WHERE age IS NULL;
Karşılaştırma Operatörleri ve NULL
PostgreSQL, üç değerli mantık (three-valued logic) kullanır: TRUE, FALSE, UNKNOWN (NULL). Bir karşılaştırmada taraflardan biri NULL ise sonuç her zaman UNKNOWN olur.
| İfade | Sonuç |
| NULL = NULL | NULL |
| NULL <> NULL | NULL |
| NULL > 10 | NULL |
| NULL = ” | NULL |
| NULL IS NULL | TRUE |
| NULL IS NOT NULL | FALSE |
-- Örnek tablo
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name TEXT,
bonus INTEGER
);
INSERT INTO employees (name, bonus) VALUES
('Ahmet', 1000),
('Mehmet', NULL),
('Zeynep', 0);
-- Sorgular ve sonuçları:
SELECT * FROM employees WHERE bonus = NULL; -- 0 satır
SELECT * FROM employees WHERE bonus IS NULL; -- Mehmet gelir
SELECT * FROM employees WHERE bonus = 0; -- Zeynep gelir
NULL ile Mantıksal İşlemler (AND / OR)
PostgreSQL’de mantıksal işlemlerde NULL, UNKNOWN olarak ele alınır:
| A | B | A AND B | A OR B | NOT A |
| TRUE | NULL | UNKNOWN | TRUE | FALSE |
| FALSE | NULL | FALSE | UNKNOWN | TRUE |
| NULL | NULL | UNKNOWN | UNKNOWN | UNKNOWN |
-- WHERE koşullarında UNKNOWN, FALSE gibi davranır (satırı elemez)
SELECT * FROM employees WHERE bonus = 1000 OR bonus = NULL;
-- Sadece bonus=1000 olan Ahmet gelir, çünkü bonus=NULL olan koşul UNKNOWN verir.
NULL ve Aggregate Fonksiyonları
PostgreSQL, toplamsal (aggregate) fonksiyonlarda NULL değerleri yok sayar:
| Fonksiyon | Davranış |
| COUNT(*) | NULL’ları sayar (tüm satırları sayar) |
| COUNT(column) | NULL’ları saymaz |
| SUM(column) | NULL’ları yok sayar, toplama katmaz |
| AVG(column) | NULL’ları yok sayar, sadece NULL olmayanların ortalamasını alır |
| MAX(column) / MIN(column) | NULL’ları yok sayar |
SELECT
COUNT(*) AS total_satir, -- 3
COUNT(bonus) AS bonus_olmayan, -- 2 (Mehmet sayılmaz)
SUM(bonus) AS toplam_bonus, -- 1000
AVG(bonus) AS ortalama_bonus -- 500 (1000/2, 3'e bölünmez!)
FROM employees;
AVG beklenmedik sonuç verebilir. Yukarıdaki örnekte ortalama (1000+0)/2 = 500 olarak hesaplanır, (1000+0+NULL)/3 = 333 değil.
NULL ve DISTINCT / GROUP BY
- DISTINCT: Tüm NULL değerleri tek bir grup olarak değerlendirir.
- GROUP BY: NULL değerler kendi grubunda toplanır.
INSERT INTO employees (name, bonus) VALUES ('Ayşe', NULL);
SELECT bonus, COUNT(*) FROM employees GROUP BY bonus;
-- Sonuç:
-- bonus | count
-- -------+-------
-- 1000 | 1
-- 0 | 1
-- NULL | 2 (Mehmet ve Ayşe)
NULL ve Eşitsizlik ifadesi
PostgreSQL’de varsayılan olarak bir sorguda eşitsizlik operatörü kullanıldığında NULL değerler gelmez. Aşağıdaki gibi bir sorguda bonus değeri 0 (sıfır) olmayanlar eşitsizliğinde , NULL olan kayıtlar gelmeyecektir.
SELECT name, bonus FROM employees where bonus<>0;
-- Ahmet (1000)
NULL olan kayıtların da eşitsizlik operatöründe gelmesini istiyorsak ilave koşul belirtmek gerekecektir.
SELECT name, bonus FROM employees where bonus<>0 or bonus IS NULL;
NULL ve Sıralama (ORDER BY)
PostgreSQL’de varsayılan sıralamada NULL değerler en büyük kabul edilir (ASC’de sonda, DESC’de başta gelir). Bu davranış NULLS FIRST ve NULLS LAST ile değiştirilebilir.
SELECT name, bonus FROM employees ORDER BY bonus ASC;
-- Zeynep (0), Ahmet (1000), Mehmet (NULL), Ayşe (NULL)
SELECT name, bonus FROM employees ORDER BY bonus ASC NULLS FIRST;
-- Mehmet (NULL), Ayşe (NULL), Zeynep (0), Ahmet (1000)
SELECT name, bonus FROM employees ORDER BY bonus DESC NULLS LAST;
-- Ahmet (1000), Zeynep (0), Mehmet (NULL), Ayşe (NULL)
NULL ve Benzersiz Kısıtlamalar (UNIQUE)
PostgreSQL’de UNIQUE kısıtlaması, NULL değerleri birbirinden farklı kabul etmez mi? Hayır, tam tersi:
- Bir sütun UNIQUE ise, birden fazla NULL değer girebilir.
- Çünkü PostgreSQL, NULL = NULL eşitliğini sağlamadığı için her NULL’u farklı bir değer olarak görür.
CREATE TABLE test_unique (id INT UNIQUE);
INSERT INTO test_unique VALUES (NULL); -- Başarılı
INSERT INTO test_unique VALUES (NULL); -- Başarılı (2. NULL)
-- İki NULL değer aynı anda bulunabilir.
İstisna: PRIMARY KEY sütunu NULL olamaz (hem NOT NULL hem UNIQUE içerir).
NULL ile String Birleştirme (Concatenation)
PostgreSQL’de || operatörü ile string birleştirmede eğer operandlardan biri NULL ise sonuç NULL olur.
SELECT 'Hello' || NULL || 'World'; -- NULL
SELECT CONCAT('Hello', NULL, 'World'); -- 'HelloWorld' (CONCAT NULL'ı yok sayar)
Öneri: NULL değerleri yönetmek için COALESCE veya CONCAT kullanın.
NULL Yönetimi için Pratik Fonksiyonlar
| Fonksiyon | Açıklama | Örnek |
| COALESCE(value, default) | İlk NULL olmayan değeri döndürür | COALESCE(bonus, 0) |
| NULLIF(a, b) | a = b ise NULL, değilse a döndürür | NULLIF(division, 0) |
| ISNULL() (SQL Server) | PostgreSQL’de yok, COALESCE kullanın | |
| CASE | Koşullu NULL yönetimi | CASE WHEN bonus IS NULL THEN 0 ELSE bonus END |
-- Kullanıcı adı ve bonusu göster, NULL ise 0 göster
SELECT name, COALESCE(bonus, 0) AS bonus_amount FROM employees;
En Çok Yapılan Hatalar ve Çözümleri
| Hatalı Kullanım | Sonuç | Doğru Kullanım |
| column = NULL | Her zaman FALSE | column IS NULL |
| column <> NULL | Her zaman FALSE | column IS NOT NULL |
| COUNT(column) | NULL’ları saymaz | COUNT(*) veya SUM(CASE WHEN column IS NULL THEN 1 ELSE 0 END) |
| column IN (1,2,NULL) | NULL içeren IN ifadesi UNKNOWN döndürür | column IN (1,2) OR column IS NULL |
| NOT IN (SELECT … WHERE col IS NULL) | Hiç satır döndürmeyebilir | NOT EXISTS kullanın |
NOT IN alt sorgusu NULL içeriyorsa, ana sorgu hiçbir satır döndürmez!
-- YANLIŞ:
SELECT * FROM employees WHERE bonus NOT IN (1000, NULL); -- 0 satır
-- DOĞRU:
SELECT * FROM employees WHERE bonus NOT IN (1000) OR bonus IS NULL;
-- veya
SELECT * FROM employees WHERE NOT EXISTS (
SELECT 1 FROM (VALUES (1000), (NULL)) AS t(val) WHERE t.val = employees.bonus
);
Performans ve İndeksleme
PostgreSQL’de NULL değerler B-tree indekslerinde yer alır. Ancak IS NULL sorguları, indeks kullanımı açısından özel durum gerektirebilir.
-- Bu sorgu indeks kullanabilir:
CREATE INDEX idx_bonus ON employees(bonus);
SELECT * FROM employees WHERE bonus IS NULL; -- İndeksi kullanır (PG 9.2+)
-- Ancak kısmi indeks daha verimli olabilir:
CREATE INDEX idx_bonus_null ON employees(bonus) WHERE bonus IS NULL;
Öneriler :
- NULL’u asla sıfır veya boş string ile karıştırmayın.
- Eşitlik kontrolünde daima IS NULL / IS NOT NULL kullanın.
- Aggregate fonksiyonlarının NULL’ları yok saydığını unutmayın.
- NOT IN kullanırken alt sorguda NULL olabileceğini göz önünde bulundurun.
- Sıralama davranışını NULLS FIRST/LAST ile netleştirin.
- COALESCE ile NULL’ları varsayılan değerlere dönüştürün.
- Veritabanı tasarımında mümkünse NOT NULL kısıtlaması kullanın.
- <> operatörüyle birlikte “or is null” koşulunu da ekleyin.










