Oracle'dan PostgreSQL'e geçişte veri temiz taşınır, şema uyar, uygulama derlenir — ama bazı sorgular sessizce farklı sonuç vermeye başlar. Çoğu zaman kök neden tek bir davranış farkıdır: Oracle boş string '''yı NULL olarak ele alır, PostgreSQL ise '''yı gerçek, uzunluğu sıfır bir değer olarak tutar. İkisi Oracle'da aynı şeydi; PostgreSQL'de değil.

Farkı iki satırda gör

Oracle'da boş string NULL'dır:

sql
Oracle 19c → PG 17
-- Oracle 19c
SELECT CASE WHEN '' IS NULL THEN 'null' ELSE 'bos-string' END FROM dual;
-- sonuç: null

PostgreSQL'de '' bir değerdir, NULL değildir:

sql
Oracle 19c → PG 17
-- PostgreSQL 17
SELECT CASE WHEN '' IS NULL THEN 'null' ELSE 'bos-string' END;
-- sonuç: bos-string

Bu, Oracle'dan taşınan sorguların iki noktada bozulmasına yol açar.

1. IS NULL ile boş kayıt aramak

Oracle'da "adı girilmemiş" kayıtları bulmak için WHERE ad IS NULL yeterdi — çünkü kullanıcı boş bıraktığında Oracle onu NULL yapardı. Aynı sorgu PostgreSQL'de, uygulaman veritabanına '' yazıyorsa, o kayıtları kaçırır:

sql
Oracle 19c → PG 17
-- PG'de hem NULL hem boş string'i yakalamak istiyorsan ikisini de yaz:
SELECT * FROM musteri WHERE ad IS NULL OR ad = '';

Tersi de geçerli: WHERE ad = '' PostgreSQL'de boş string satırları getirir; Oracle'da bu koşul hiçbir zaman doğru olmazdı (çünkü = NULL daima "bilinmeyen"dir).

2. String birleştirmede sessiz kayıp

En tehlikelisi bu, çünkü hata vermez — yanlış çıktı verir. Oracle || ile birleştirmede NULL'ı boş string gibi davranır:

sql
Oracle 19c → PG 17
-- Oracle: NULL yok sayılır
SELECT 'Ali ' || NULL || 'Veli' FROM dual;   -- 'Ali Veli'

PostgreSQL'de bir ifadedeki NULL, tüm sonucu NULL yapar:

sql
Oracle 19c → PG 17
-- PostgreSQL: tek NULL her şeyi NULL yapar
SELECT 'Ali ' || NULL || 'Veli';             -- NULL

İkinci adı olmayan müşterilerin tam adı, migrasyondan sonra aniden boş görünür. Çözüm, birleştirmede NULL'ları açıkça boşa çevirmek:

sql
Oracle 19c → PG 17
SELECT 'Ali ' || COALESCE(NULL, '') || 'Veli';   -- 'Ali Veli'
-- ya da PG'nin concat() fonksiyonu NULL'ları yok sayar:
SELECT concat('Ali ', NULL, 'Veli');             -- 'Ali Veli'
Dikkat

NOT NULL kısıtı da tuzaktır. Oracle'da NOT NULL bir kolona '' yazmak, '' = NULL olduğu için hata verir. PostgreSQL'de '' geçerli bir değerdir ve NOT NULL'ı geçer. Yani Oracle'da "asla boş olamaz" varsayımına güvenen uygulama mantığı, PostgreSQL'de boş string'lerin sızmasıyla bozulur. Migrasyondan sonra kritik kolonlarda CHECK (kolon <> '') eklemeyi düşün.

Migrasyonda politika belirle

Veriyi taşırken tek bir kural seç ve her yerde uygula: ya kaynaktaki tüm boş string'leri PostgreSQL'de de NULL'a normalize et (Oracle semantiğini koru), ya da uygulamayı '' ve NULL'ı ayrı ele alacak şekilde güncelle. ora2pg gibi araçlar veriyi taşırken bu davranışı yapılandırmana izin verir; ama asıl iş, Oracle'da ''/NULL eşitliğine bel bağlayan uygulama sorgularını taramaktır — özellikle || birleştirmeleri ve NVL/IS NULL kontrolleri.

Hızlı karar tablosu

| Oracle davranışı | PostgreSQL karşılığı | Ne yap | |---|---|---| | '' IS NULL → doğru | '' bir değerdir | IS NULL OR = '' | | 'a' \|\| NULL'a' | 'a' \|\| NULL → NULL | COALESCE(x,'') veya concat() | | NOT NULL kolona '' → hata | '' geçer | Gerekirse CHECK (x <> '') | | NVL(x, '-') | COALESCE(x, '-') | Boş string ayrıca ele alınmalı |

Özet

Oracle'ın '' = NULL eşitliği, PostgreSQL'e taşındığında iki yerde ısırır: IS NULL filtreleri boş string'leri kaçırır, || birleştirmeleri tek NULL yüzünden komple boşalır. İkisi de hata vermez, sadece yanlış sonuç üretir. Geçiş öncesi bir normalizasyon politikası belirle, taşınan sorgularda || ve IS NULL kullanan yerleri tara, kritik kolonlara CHECK (x <> '') koy. Bu farkı test ortamında bir avuç gerçek sorguyla doğrulamak, production'da "müşterinin soyadı neden kayboldu" sorusundan çok daha ucuzdur.