MariaDB ve MySQL’de UPPER ve LOWER ile Büyük Küçük Harf Dönüşümü

Veritabanlarında metin verileriyle çalışırken en sık karşılaşılan sorunlardan biri tutarsız harf kullanımıdır. Kullanıcılar “istanbul”, “İstanbul”, “ISTANBUL” veya “Istanbul” şeklinde veri girmiş olabilir. Bu kaos içinde anlamlı sorgular yazmak, raporlar üretmek veya veriyi temizlemek için SQL’in UPPER() ve LOWER() fonksiyonları gerçek bir cankurtaran haline gelir. Bu yazıda bu iki fonksiyonu her açıdan ele alacağız, gerçek dünya senaryolarıyla nasıl kullanacağınızı göstereceğiz.

UPPER ve LOWER Nedir?

MariaDB ve MySQL’de UPPER() ve LOWER() fonksiyonları, bir metin değerini tamamen büyük harfe veya tamamen küçük harfe dönüştürür. Sözdizimi son derece basittir:

  • UPPER(str): Verilen string değerini tüm harflerini büyük harfe çevirir
  • LOWER(str): Verilen string değerini tüm harflerini küçük harfe çevirir
  • UCASE(str): UPPER() fonksiyonunun tam eşdeğeridir, alias olarak kullanılır
  • LCASE(str): LOWER() fonksiyonunun tam eşdeğeridir, alias olarak kullanılır

Bu fonksiyonlar hem bir sütun adı, hem bir string literal, hem de başka bir fonksiyonun döndürdüğü değer üzerinde çalışabilir. Yani oldukça esnek yapılardır.

Temel Kullanım Örnekleri

En basit haliyle bu fonksiyonlar şu şekilde kullanılır:

-- Temel UPPER ve LOWER kullanımı
SELECT UPPER('merhaba dünya');
-- Sonuç: MERHABA DÜNYA

SELECT LOWER('MERHABA DÜNYA');
-- Sonuç: merhaba dünya

SELECT UPPER('Istanbul'), LOWER('ANKARA'), UPPER(LOWER('izMiR'));
-- Sonuç: ISTANBUL | ankara | IZMIR

Bir tablo üzerinde çalışırken de kullanım aynı mantıkla ilerler. Diyelim ki musteriler adında bir tablonuz var:

-- Tablo üzerinde UPPER ve LOWER kullanımı
SELECT 
    musteri_id,
    UPPER(ad) AS buyuk_ad,
    LOWER(soyad) AS kucuk_soyad,
    email
FROM musteriler
LIMIT 10;

Bu sorgu ad sütununu büyük harfle, soyad sütununu ise küçük harfle döndürür. Orijinal veriler tabloda değişmez, sadece sorgu sonucunda farklı görünür.

Gerçek Dünya Senaryosu 1: Tutarsız Veri Karşılaştırması

Bir e-ticaret sitesinin sysadmin’i olarak kullanıcı kayıt sisteminde çalışıyorsunuz. Kullanıcılar e-posta adreslerini farklı harf kombinasyonlarıyla giriyor: “[email protected]”, “[email protected]”, “[email protected]” gibi. Mükerrer kayıt kontrolü yapmanız gerekiyor.

-- Büyük/küçük harf bağımsız mükerrer e-posta tespiti
SELECT 
    LOWER(email) AS normalized_email,
    COUNT(*) AS kayit_sayisi
FROM kullanicilar
GROUP BY LOWER(email)
HAVING COUNT(*) > 1
ORDER BY kayit_sayisi DESC;

Bu sorgu size hangi e-posta adresinin kaç farklı varyasyonla kayıtlı olduğunu gösterir. HAVING COUNT(*) > 1 filtresi sayesinde sadece mükerrer olanlar listelenir.

Peki bu mükerreratı temizlemek için ne yaparsınız? Önce hangi kayıtları silmeniz gerektiğini tespit edersiniz:

-- En eski kaydı tutup diğerlerini tespit etme
SELECT 
    k1.kullanici_id,
    k1.email,
    k1.kayit_tarihi
FROM kullanicilar k1
INNER JOIN kullanicilar k2 
    ON LOWER(k1.email) = LOWER(k2.email)
    AND k1.kullanici_id > k2.kullanici_id
ORDER BY LOWER(k1.email);

Bu self-join sorgusu, aynı e-postanın büyük/küçük harf duyarsız karşılaştırmasını yaparak eski kaydı tutup yeni kayıtları tespit eder.

Gerçek Dünya Senaryosu 2: Arama Fonksiyonları

Bir içerik yönetim sisteminde (CMS) kullanıcılar arama yapıyor. Kullanıcı “linux” arar ama veritabanında bazı makaleler “Linux”, bazıları “LINUX”, bazıları “linux” başlığıyla kayıtlıdır. Büyük/küçük harf duyarsız arama yapmak için LOWER() kullanabilirsiniz:

-- Büyük/küçük harf duyarsız arama
SELECT 
    makale_id,
    baslik,
    yazar,
    yayin_tarihi
FROM makaleler
WHERE LOWER(baslik) LIKE LOWER('%linux sistem yönetimi%')
   OR LOWER(etiketler) LIKE LOWER('%linux%')
ORDER BY yayin_tarihi DESC;

Performans notu: Bu yaklaşım sütun üzerindeki index’i kullanamaz. Büyük tablolarda bu tür aramaları sık yapıyorsanız, ya COLLATE ayarını utf8mb4_general_ci (case insensitive) olarak değiştirmeyi, ya da Full-Text Search kullanmayı düşünün.

Gerçek Dünya Senaryosu 3: Veri Temizleme ve Normalizasyon

Bir şirket veritabanında şehir adları berbat bir halde olabilir. “ankara”, “ANKARA”, “Ankara”, “aNkArA” gibi girişler aynı şehri temsil ediyor ama sorgularda farklı gruplar oluşturuyor. Önce durumu analiz edin:

-- Şehir adlarındaki tutarsızlıkları tespit etme
SELECT 
    sehir,
    COUNT(*) AS kayit_sayisi,
    LOWER(sehir) AS normalized
FROM adresler
GROUP BY sehir
ORDER BY LOWER(sehir), sehir;

Sonra bu veriyi temizlemek için UPDATE ile UPPER() veya LOWER() kombinasyonunu kullanabilirsiniz. Ancak dikkatli olun, bu işlem kalıcıdır:

-- Tüm şehir adlarını tutarlı formata çekme (önce backup alın!)
-- Önce neyin değişeceğini görün
SELECT sehir, UPPER(LEFT(sehir, 1)) 
    || LOWER(SUBSTRING(sehir, 2)) AS hedef_format
FROM adresler
WHERE sehir != CONCAT(UPPER(LEFT(sehir, 1)), LOWER(SUBSTRING(sehir, 2)))
LIMIT 20;

-- Emin olduysanız güncelleme yapın
UPDATE adresler
SET sehir = CONCAT(UPPER(LEFT(sehir, 1)), LOWER(SUBSTRING(sehir, 2)))
WHERE sehir IS NOT NULL;

Bu UPDATE sorgusu her şehir adının ilk harfini büyük, geri kalanını küçük yaparak “Ankara”, “Istanbul”, “Izmir” formatına getirir. LEFT() ve SUBSTRING() ile birleşince UPPER() ve LOWER() çok daha güçlü hale gelir.

Gerçek Dünya Senaryosu 4: Rapor Formatı Standartlaştırma

Yöneticiler için hazırladığınız raporlarda kolon başlıklarının her zaman büyük harfle görünmesini isteyebilirsiniz. Ya da departman adlarının standart bir formatta çıkmasını:

-- Rapor için standartlaştırılmış çıktı
SELECT 
    UPPER(departman) AS DEPARTMAN,
    UPPER(CONCAT(ad, ' ', soyad)) AS PERSONEL_ADI,
    LOWER(email) AS email_adresi,
    maas,
    CASE 
        WHEN maas > 10000 THEN UPPER('üst segment')
        WHEN maas > 5000 THEN UPPER('orta segment')
        ELSE UPPER('alt segment')
    END AS MAAS_SEGMENTI
FROM personel
WHERE aktif = 1
ORDER BY departman, soyad;

Bu sorgu hem sütun verilerini hem de CASE ifadesi içindeki dinamik değerleri standart hale getirir.

UPPER ve LOWER ile JOIN İşlemleri

İki farklı sistemden gelen veriyi birleştirirken harf tutarsızlığı ciddi sorun çıkarır. Örneğin bir ERP sisteminden gelen müşteri adları büyük harfle, CRM sisteminden gelenler mixed case’de olabilir:

-- Farklı sistemlerden gelen veriyi normalize ederek birleştirme
SELECT 
    e.musteri_no,
    UPPER(e.musteri_adi) AS musteri_adi,
    c.telefon,
    c.son_iletisim_tarihi
FROM erp_musteriler e
LEFT JOIN crm_musteriler c 
    ON UPPER(TRIM(e.musteri_adi)) = UPPER(TRIM(c.musteri_adi))
WHERE e.aktif = 1
ORDER BY e.musteri_adi;

Burada TRIM() ile de birleştirme yaptığımıza dikkat edin. Baştaki ve sondaki boşluklar da JOIN’leri bozabilir, UPPER(TRIM(...)) kombinasyonu bu iki sorunu aynı anda çözer.

Gerçek Dünya Senaryosu 5: Kullanıcı Adı ve Şifre Yönetimi

Bir uygulama üzerinde kullanıcı adlarının büyük/küçük harf duyarsız olmasını istiyorsunuz ama veritabanı collation ayarını değiştirme yetkiniz yok. Bu durumda uygulama katmanında yapmak yerine SQL ile halledilebilir:

-- Kullanıcı adı duyarsız login kontrolü
SELECT 
    kullanici_id,
    kullanici_adi,
    email,
    son_giris,
    hesap_durumu
FROM kullanicilar
WHERE LOWER(kullanici_adi) = LOWER('AhmetYilmaz')
  AND hesap_durumu = 'aktif';
-- Yeni kayıt öncesi kullanıcı adı müsaitlik kontrolü
SELECT COUNT(*) AS kullanici_var
FROM kullanicilar
WHERE LOWER(kullanici_adi) = LOWER('yeni_kullanici_adi');
-- Sonuç 0 ise kullanıcı adı müsaittir

Bu yaklaşım, “AhmetYilmaz”, “ahmetyilmaz” ve “AHMETYILMAZ” kullanıcı adlarının aynı hesabı işaret etmesini sağlar.

UPPER ve LOWER ile Stored Procedure

Sık tekrar eden normalizasyon işleri için stored procedure yazmak iyi bir pratiktir. Örneğin yeni müşteri eklerken otomatik olarak bazı alanları standartlaştıran bir prosedür:

-- Müşteri ekleme prosedürü ile otomatik normalizasyon
DELIMITER $$

CREATE PROCEDURE musteri_ekle(
    IN p_ad VARCHAR(100),
    IN p_soyad VARCHAR(100),
    IN p_email VARCHAR(200),
    IN p_sehir VARCHAR(100)
)
BEGIN
    -- E-posta her zaman küçük harf
    -- Ad ve soyad ilk harf büyük, geri kalan küçük
    -- Şehir tamamen büyük harf
    INSERT INTO musteriler (ad, soyad, email, sehir, kayit_tarihi)
    VALUES (
        CONCAT(UPPER(LEFT(TRIM(p_ad), 1)), LOWER(SUBSTRING(TRIM(p_ad), 2))),
        CONCAT(UPPER(LEFT(TRIM(p_soyad), 1)), LOWER(SUBSTRING(TRIM(p_soyad), 2))),
        LOWER(TRIM(p_email)),
        UPPER(TRIM(p_sehir)),
        NOW()
    );
    
    SELECT LAST_INSERT_ID() AS yeni_musteri_id;
END$$

DELIMITER ;

-- Prosedürü çağırma
CALL musteri_ekle('ahMET', 'YILMAZ', '[email protected]', 'ankara');

Bu prosedür girişte ne kadar tutarsız veri gelse de çıkışta standart formatta kaydeder.

Collation ile UPPER/LOWER İlişkisi

MariaDB ve MySQL’de harf dönüşümü collation ayarlarından etkilenir. Türkçe karakterler için özellikle dikkat etmek gerekir:

-- Mevcut collation ayarını kontrol etme
SHOW VARIABLES LIKE 'collation%';
SHOW VARIABLES LIKE 'character_set%';

-- Tablo collation bilgisini görme
SHOW CREATE TABLE musteriler;

-- Sütun bazlı collation kontrolü
SELECT 
    COLUMN_NAME,
    CHARACTER_SET_NAME,
    COLLATION_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'veritabanim'
  AND TABLE_NAME = 'musteriler';
-- utf8mb4 ile Türkçe karakter testi
SET NAMES utf8mb4;

SELECT 
    UPPER('istanbul') AS buyuk,
    LOWER('İSTANBUL') AS kucuk,
    UPPER('şişli') AS sisli_buyuk,
    LOWER('ÇANKAYA') AS cankaya_kucuk;

Önemli not: Türkçe’de “i” ve “İ” birbirinin büyük/küçük karşılığıdır. Ancak bazı collation ayarlarında bu doğru çalışmayabilir. Uygulamanızda Türkçe karakter sorunları yaşıyorsanız utf8mb4_turkish_ci collation’ını değerlendirin.

UPPER ve LOWER ile View Oluşturma

Sürekli normalizasyon sorguları yazmak yerine, view oluşturup uygulamanın bu view’i kullanmasını sağlayabilirsiniz:

-- Normalize edilmiş müşteri view'i
CREATE OR REPLACE VIEW v_musteriler_normalize AS
SELECT 
    musteri_id,
    CONCAT(UPPER(LEFT(ad, 1)), LOWER(SUBSTRING(ad, 2))) AS ad,
    CONCAT(UPPER(LEFT(soyad, 1)), LOWER(SUBSTRING(soyad, 2))) AS soyad,
    LOWER(email) AS email,
    UPPER(sehir) AS sehir,
    UPPER(ulke) AS ulke,
    telefon,
    kayit_tarihi,
    aktif
FROM musteriler
WHERE aktif = 1;

-- View üzerinden sorgu
SELECT * FROM v_musteriler_normalize
WHERE sehir = 'ISTANBUL'
ORDER BY soyad, ad;

View yaklaşımı sayesinde uygulama kodu sadece v_musteriler_normalize view’ini kullanır, normalizasyon mantığı merkezi bir yerde yönetilir.

Performans Konuları

UPPER() ve LOWER() kullanımında dikkat edilmesi gereken bazı performans noktaları vardır:

  • Index kullanımı: WHERE LOWER(kolon) = 'deger' şeklindeki sorgular normal index’i kullanamaz. Çözüm olarak functional index oluşturabilirsiniz (MariaDB 10.4+ ve MySQL 8.0+):
-- Functional index oluşturma (MariaDB 10.4+ / MySQL 8.0+)
CREATE INDEX idx_email_lower ON kullanicilar ((LOWER(email)));
CREATE INDEX idx_kullanici_adi_lower ON kullanicilar ((LOWER(kullanici_adi)));

-- Artık bu sorgu index kullanır
SELECT * FROM kullanicilar WHERE LOWER(email) = '[email protected]';

-- Index kullanımını doğrulama
EXPLAIN SELECT * FROM kullanicilar WHERE LOWER(email) = '[email protected]';
  • Büyük tablolarda dikkat: Milyonlarca satırlık tablolarda WHERE koşuluna UPPER() veya LOWER() koymak full table scan’e neden olabilir. Yukarıdaki functional index yaklaşımını veya case-insensitive collation’ı tercih edin.
  • SELECT listesinde kullanım: SELECT UPPER(kolon) şeklindeki kullanımlar performansı ciddi etkilemez, sorun WHERE ve JOIN koşullarındadır.

Pratik İpuçları

Günlük işlerinizde bu fonksiyonları kullanırken aklınızda bulundurmanız gereken bazı noktalara değinelim:

  • NULL davranışı: UPPER(NULL) ve LOWER(NULL) her ikisi de NULL döndürür, hata vermez. Güvenli kullanım için COALESCE(UPPER(kolon), '') şeklinde kullanabilirsiniz.
  • Sayısal değerlere uygulanırsa: UPPER(123) ve LOWER(123) her ikisi de '123' döndürür, sayılar üzerinde harflendirme değişikliği olmaz.
  • Boş string: UPPER('') boş string döndürür, NULL değil.
  • TRIM kombinasyonu: Gerçek projede neredeyse her zaman UPPER(TRIM(kolon)) veya LOWER(TRIM(kolon)) şeklinde kullanın. Başta/sonda boşluk bırakmak çok yaygın bir kullanıcı hatasıdır.
  • Nested kullanım: UPPER(LOWER('Metin')) ile UPPER('Metin') aynı sonucu verir, önce küçük sonra büyük yapmanın bir anlamı olmaz. Gereksiz iç içe kullanımdan kaçının.

Sonuç

UPPER() ve LOWER() fonksiyonları SQL’in en basit ama en çok işe yarayan araçlarından ikisidir. Veri temizleme, normalizasyon, büyük/küçük harf duyarsız arama, rapor formatı standartlaştırma ve farklı sistemlerden gelen verileri birleştirme gibi çok farklı senaryolarda bu iki fonksiyon olmadan hayat çok daha zor olurdu.

Özellikle Türkçe veri içeren projelerde collation ayarlarına da dikkat etmek gerektiğini unutmayın. utf8mb4 karakter seti ve uygun collation seçimi, bu fonksiyonların doğru çalışması için temel şarttır.

Performans açısından kritik sorgularda UPPER() ve LOWER() kullanmak zorundaysanız, functional index oluşturmayı değerlendirin. Büyük tablolarda bunu yapmadan WHERE koşuluna bu fonksiyonları koymak ciddi yavaşlamalara neden olabilir.

Son olarak şunu söyleyeyim: Bu fonksiyonlar veritabanı katmanında veriyi güzelleştirmek için harika araçlar, ancak en iyi senaryo veriyi kaynağında doğru formatta almaktır. Eğer uygulamanızın giriş katmanında validasyon ve normalizasyon yapabiliyorsanız, veritabanında sonradan temizlik yapmak zorunda kalmazsınız. Ama gerçek dünyada bu her zaman mümkün olmaz, o yüzden bu fonksiyonları iyi bilmek her zaman işe yarar.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir