MySQL CONCAT_WS() ile NULL'a Takılmayan Birleştirme

Selamlar, bu yazımda MySQL'in görece sessiz kalan ama bir kez alıştığınızda elinizden düşmeyecek fonksiyonlarından biri olan CONCAT_WS()'e bakacağız. Bilhassa nullable kolonlardan ad-soyad ya da adres üreten herkesin başına gelmiştir: CONCAT() ile string birleştiriyorsunuz, ortadaki bir kolon NULL çıkıyor ve sonuç bir anda komple NULL oluyor. Hadi CONCAT_WS() bu kâbusu nasıl bitiriyor, bakalım.

CONCAT_WS() nedir?

İsmindeki WS, 'with separator' kısaltması; yani 'ayraçlı birleştir'. Fonksiyon iki ya da daha fazla string'i, ilk argüman olarak verdiğiniz ayraçla bir araya getiriyor. Asıl can alıcı özelliği ise şu: argümanlardan biri NULL ise onu sessizce atlar, geriye düzgün bir sonuç döndürür.

İmzası şöyle:

CONCAT_WS(ayrac, str1, str2, str3, ...)

Üç kuralı baştan aklınızda tutun: ayraç zorunlu, ayraç NULL olursa sonuç NULL döner ve gerisindeki NULL argümanlar atlanırken yerlerinde çift ayraç bırakmazlar. Son madde aslında en kıymetlisi - üreteceğiniz string'in cımbızla temizlenmesine gerek kalmıyor.

Temel kullanım

Üç hızlı örnekle ısınalım:

SELECT CONCAT_WS(', ', 'Ayşe', 'Yılmaz', 'İstanbul');
-- Sonuc: 'Ayşe, Yılmaz, İstanbul'

SELECT CONCAT_WS('-', '2026', '05', '08');
-- Sonuc: '2026-05-08'

SELECT CONCAT_WS(' | ', 'MySQL', '8.0', 'String Fonksiyonlari');
-- Sonuc: 'MySQL | 8.0 | String Fonksiyonlari'

Görüyorsunuz, ayraç tek karakter olmak zorunda değil; çok karakterli ayraç da çalışıyor. Bu sayede kayıt sınırlayıcı yerine ' - ' gibi okunabilir ayraçlar koyabiliyorsunuz.

CONCAT()'tan farkı: NULL muamelesi

İşin can damarı burası. Aynı veriyi iki fonksiyona verelim:

-- CONCAT() bir argüman bile NULL'sa sonucu NULL yapar
SELECT CONCAT('Ayşe', NULL, 'Yılmaz');
-- Sonuc: NULL

-- CONCAT_WS() NULL argümanı görmemiş gibi geçer
SELECT CONCAT_WS(' ', 'Ayşe', NULL, 'Yılmaz');
-- Sonuc: 'Ayşe Yılmaz'

Şahsi kanaatim, kolonun nullable olduğu her senaryoda CONCAT() kullanmak başınıza iş açar. COALESCE(col, '') ile bunu manuel çözmeye çalışırsanız bu sefer ortada boş ayraçlar belirir. CONCAT_WS() ikisini de tek hamlede halleder.

Nullable kolonlardan tam ad üretmek

Klasik senaryo: ikinci adı opsiyonel olan bir kişi tablosu. Hadi gerçek veriyle bakalım:

CREATE TABLE kisiler (
    kisi_id     INT PRIMARY KEY,
    ad          VARCHAR(50),
    ikinci_ad   VARCHAR(50),
    soyad       VARCHAR(50)
);

INSERT INTO kisiler VALUES
(1, 'Ayşe',  'Nur',   'Yılmaz'),
(2, 'Mehmet', NULL,   'Demir'),
(3, 'Zeynep', 'Su',    NULL);

SELECT
    kisi_id,
    CONCAT_WS(' ', ad, ikinci_ad, soyad) AS tam_ad
FROM kisiler;

Sonuç:

kisi_id tam_ad
1 Ayşe Nur Yılmaz
2 Mehmet Demir
3 Zeynep Su

İkinci satırda 'Mehmet Demir' gibi çift boşluklu bir çıktı yok; üçüncü satırda da sondan sarkan bir boşluk yok. Çünkü NULL argüman tamamen atlanıyor, yerine ayraç eklenmiyor.

Adresleri ve etiketli string'leri kurmak

Adres kolonları neredeyse her zaman kısmen NULL'dur. CONCAT_WS() burada da bir nimet:

SELECT
    CONCAT_WS(', ', sokak, mahalle, ilce, sehir, posta_kodu) AS tam_adres
FROM adresler;

Eksik kolon hangisi olursa olsun, çıktı temiz kalır. Aynı mantığı raporlama için de kullanabilirsiniz:

SELECT
    calisan_id,
    CONCAT_WS(' - ', isim, COALESCE(departman, 'Atanmamis'), CONCAT('₺', FORMAT(maas, 0))) AS etiket
FROM calisanlar;
-- Ornek: 'Ayşe Yılmaz - Mühendislik - ₺85,000'

Burada COALESCE'i bilinçli olarak kullandım: departmanın NULL olmasını atlamak değil, 'Atanmamis' yazmak istiyorum. CONCAT_WS()'in NULL davranışı her zaman aradığınız şey olmayabilir, ikisini birlikte kullanmak şart.

Sık karşılaşılan tuzaklar

  • Ayracın kendisinin NULL olması: SELECT CONCAT_WS(NULL, 'a', 'b'); çağrısı NULL döner. Eğer ayracı bir alt sorgudan ya da değişkenden alıyorsanız, IFNULL(ayrac, ',') ile garanti altına almakta fayda var.
  • Boş string ile NULL'u karıştırmak: '' (boş string) NULL değildir; CONCAT_WS() bunu atlamaz, normal değer gibi araya ekler ve çift ayraç oluşur. Boş string'leri de atlamak istiyorsanız NULLIF(col, '') ile önce NULL'a çevirin.
  • Sayısal kolonlarda otomatik dönüşüm: Sayısal kolonlar string'e cast edilir, sorun yok; ama bilhassa DECIMAL kolonlarda biçim beklediğiniz gibi gelmeyebilir. FORMAT() ile önden biçimlendirmek sağlıklı.
  • GROUP_CONCAT() ile karıştırmak: CONCAT_WS() aynı satırdaki kolonları birleştirir; birden fazla satırı tek string'e toplamak için GROUP_CONCAT() lazım. İkisi farklı işlerdir.

Kapanış

CONCAT_WS() kâğıt üstünde küçük bir fonksiyon ama nullable kolonlarla çalışırken CONCAT() + IFNULL() kombinasyonunun sıkıntısını tamamen ortadan kaldırıyor. Bana sorarsanız, ad-soyad veya adres benzeri her birleştirmede varsayılanınız CONCAT_WS() olsun; ihtiyacınız değişirse CONCAT()'a düşersiniz, tersi acı verici. Bir sonraki yazıda görüşmek üzere.