Aynı Sorgu, Üç Lehçe — PostgreSQL, SQL Server, Oracle
Önce şunu oku: SQL mi, NoSQL mi? — Önce Erişim Desenini Yaz
30 saniyede özet
SQL ortak bir dil, ama her veritabanı onu kendi şivesiyle konuşur. Yazım farkları hemen hata verir ve kolay bulunur. Asıl tehlike sessiz farklardır: Oracle'da boş metin NULL'dır, SQL Server çoğu zaman büyük-küçük harfi ayırmaz.
Oracle’dan PostgreSQL’e geçiş bitti, bütün testler yeşil. İki hafta sonra müşteri hizmetleri, ikinci adı olmayan müşterilerin faturalarında adın boş göründüğünü bildirdi. Hiçbir sorgu hata vermemişti.
-
Bayt: Oracle'dan PostgreSQL'e geçtik, bütün testler yeşil!
-
Sen: Harika. Sonra?
-
Bayt: İki hafta sonra bazı faturalarda müşterinin adı boş çıkmaya başladı. Tek bir hata yok!
-
Bayt: Aynı kelime iki ülkede farklı şey anlatabilir. SQL için de öyle mi?
Ortak dil, farklı şive
SQL bir ANSI/ISO standardıdır. Her motor bu standardın bir kısmını uygular, üstüne kendi SQL lehçesiBir veritabanının standart SQL'e eklediği ya da ondan farklı uyguladığı sözdizimi ve davranışlar: T-SQL, PL/SQL, PL/pgSQL.Sözlükte gör → ekler: PostgreSQL’de PL/pgSQL, SQL Server’da T-SQL, Oracle’da PL/SQL.
Farkları iki gruba ayırmak işe yarar. Gürültülü farklar sözdizimi hatası verir; ilk çalıştırmada görünür. Sessiz farklar çalışır ve başka bir sonuç döndürür.
Kafam karıştı, daha basit anlat
SQL ortak bir dildir, ama her veritabanının kendi şivesi vardır. Bazı farklar hemen hata verir, bazıları ise sessizce başka bir sonuç döndürür.
Bir veritabanından diğerine taşırken hangi tür fark daha pahalıdır?
Sessiz farklar
Oracle'da name kolonuna '' (boş string) yazdın. WHERE name IS NULL bu satırı bulur mu? Cevabı göster
Bulur. Oracle VARCHAR2’de boş string ile NULL’ı aynı sayar. WHERE name = '' ise hiçbir satır bulmaz, çünkü NULL hiçbir şeye eşit değildir.
Adım adım oku
- İki veritabanında da aynı sorgu çalışıyor: ad, ikinci ad ve soyad birleştiriliyor; ikinci ad boş.
- Oracle boş metni NULL sayar ve birleştirirken NULL'u atlar: ad yine de oluşur.
- PostgreSQL boş metni ayrı tutar; NULL ile yapılan her birleştirme NULL döner.
- Sorgu hata vermez, ama ikinci adı olmayan müşterinin adı faturada boş görünür.
En sık görülen üç sessiz fark:
- Boş string: Oracle’da
''NULL’dır; PostgreSQL ve SQL Server’da bir değerdir. - NULL ile birleştirme: Oracle’da
'Ali' || NULLsonucu'Ali'dir; PostgreSQL’de NULL’dır. - Harf duyarlılığı: SQL Server’da karşılaştırma collationMetinlerin nasıl sıralanıp karşılaştırılacağını belirleyen kurallar: büyük/küçük harf ve aksan duyarlılığı. SQL Server'da çoğu kurulumun varsayılanı harfe duyarsızdır.Sözlükte gör →’a bağlıdır ve çoğu kurulumda
'Ali' = 'ali'doğrudur.
Kafam karıştı, daha basit anlat
Sessiz farklar en tehlikelisidir: sorgu çalışır, ama sonuç başka çıkar. Oracle’da boş yazı ile NULL aynı şeydir, diğerlerinde değildir.
Oracle'da son iki sorgu ne döndürür?
SQL Server'dan PostgreSQL'e geçtikten sonra bazı kullanıcılar giriş yapamıyor. Giriş sorgusu `WHERE email = ?`. En olası sebep?
Kendin gör
Aynı SQL, başka bir veritabanında
Tohum 173032Veri: users tablosuna name = '' olan bir satır eklendi
Oynat ya da adımla.
Şu an ne oldu?
Boş string: '' NULL mı?: Oracle → PostgreSQL
Aynı SQL cümlesi hedef veritabanında çalıştırılacak. Hata mı verecek, aynı sonucu mu, yoksa sessizce başka bir sonucu mu?
Görevler0/3
Hata vermeden farklı sonuç veren bir taşıma bulaçık
İpucu
NULL, boş string ya da harf duyarlılığı.
Sözdizimi hatasıyla duran bir taşıma bulaçık
İpucu
Bir motora özgü bir anahtar kelime.
Sayfalamayı iki farklı veritabanı arasında değiştirmeden taşıaçık
İpucu
Standart sözdizimiyle yazılmış kaynaktan başla.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Oracle’daki boş string sorgusu PostgreSQL’de başka bir sayı döndürdü.
- Ad birleştirme, Oracle → PostgreSQL. İkinci adı olmayanın tüm adı NULL oldu.
- E-posta karşılaştırma, SQL Server → PostgreSQL. Giriş sessizce bozuldu.
- Sayfalama, PostgreSQL → SQL Server. Gürültülü: hemen hata.
- Sayfalama, SQL Server → Oracle. Standart sözdizimi olduğu gibi taşındı.
Simülatörde Oracle'daki `first || ' ' || middle || ' ' || last` PostgreSQL'e taşınınca ikinci adı olmayanlar için NULL döndü. Neden, ve PostgreSQL'de doğru yazım ne?
Aynı iş, üç yazım
Günlük işlerin çoğu, satır varsa güncelleyip yoksa eklemek (upsertKayıt varsa güncelleyip yoksa ekleyen tek işlem. PostgreSQL'de ON CONFLICT, SQL Server ve Oracle'da MERGE ile yazılır; eşzamanlılıkta davranışları farklıdır.Sözlükte gör →) dahil, üç motorda farklı yazılır.
| İş | PostgreSQL | SQL Server | Oracle |
|---|---|---|---|
| Otomatik id | GENERATED AS IDENTITY | IDENTITY(1,1) | GENERATED AS IDENTITY (12c+) |
| Eklenen id’yi al | RETURNING id | OUTPUT inserted.id | RETURNING id INTO :id |
| Sayfalama | LIMIT ya da OFFSET … FETCH | OFFSET … FETCH | OFFSET … FETCH (12c+) |
| Upsert | ON CONFLICT … DO UPDATE | MERGE + HOLDLOCK | MERGE |
| Boolean kolon | boolean | bit | BOOLEAN (23ai), öncesinde NUMBER(1) |
Standart sözdizimi olan yerde onu seç: OFFSET … FETCH ve GENERATED AS IDENTITY üç motorda da çalışır.
Küçük bir banka örneğine bakalım. Her sabah günün döviz kurları tabloya yazılır: kur varsa güncellenir, yoksa eklenir. Aynı işi üç motorda yan yana görünce farklar kendiliğinden göze çarpıyor.
Derinleş · Günün döviz kuru: aynı upsert, üç lehçe 4 dosya · ~71 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
Mümkün olan yerde herkesin anladığı standart yazımı seç. Böylece veritabanı değişse de sorgun aynı kalır.
Üç motorda da (PostgreSQL, SQL Server, güncel Oracle) değiştirmeden çalışan sayfalama yazımı hangisi?
Her taşıma farkını gürültülü (hata verir) ya da sessiz (farklı sonuç verir) olarak ayır.
Tuzaklar
MERGE atomik sanılır. Eşzamanlı iki MERGE aynı yeni anahtarı ekleyebilir ve biri unique ihlaliyle düşer. PostgreSQL’in ON CONFLICT’i bu durum için tasarlanmıştır.
@@IDENTITY. SQL Server’da bir trigger başka bir tabloya ekleme yaptıysa onun id’sini döndürür; SCOPE_IDENTITY() ya da OUTPUT kullan.
ROWNUM ve ORDER BY. Oracle’da WHERE ROWNUM <= 10 ORDER BY … önce 10 satır seçer, sonra sıralar.
Tanımlayıcı harfleri. PostgreSQL tırnaksız isimleri küçük harfe, Oracle büyük harfe çevirir. Tırnakla oluşturulan "OrderItem" her sorguda tırnak ister.
Oracle'da 'en yüksek tutarlı 10 sipariş' raporu yanlış siparişleri gösteriyor. Hatalı satır hangisi?
Kendini sına
SQL bir standarttır ama her veritabanı kendi lehçesini ekler.
SQL Server'da `MERGE` ile yazılmış bir upsert, yük altında arada primary key ihlali veriyor. Neden ve tipik düzeltme ne?
Aklında kalacak üç şey
- 1 Yazım farkları (LIMIT, ON CONFLICT, dual) hata verir ve ilk testte yakalanır. Pahalı olanlar, hata vermeden farklı sonuç veren farklardır.
- 2 Oracle VARCHAR2'de boş metni NULL sayar. SQL Server'da metin karşılaştırması collation ayarına bağlıdır ve çoğu kurulumda büyük-küçük harfe duyarsızdır.
- 3 Taşınabilirlik için standart yazımı tercih et (OFFSET … FETCH, GENERATED AS IDENTITY) ve kenar durumları gerçek hedef veritabanında test et.
5 kart sonraki derste seni bekliyor