MySQL ve MariaDB’de REPLACE Fonksiyonu ile Metin İçinde Değiştirme
Veritabanı yönetiminde en sık karşılaşılan ihtiyaçlardan biri, mevcut verilerin belirli bir kısmını güncellemektir. Özellikle büyük tablolarda URL değişiklikleri, şirket adı güncellemeleri veya format standartlaştırmaları gibi işlemlerde tek tek satır güncellemek hem zaman alıcı hem de hata yaratma riski yüksek bir yaklaşımdır. İşte tam bu noktada MariaDB ve MySQL’in REPLACE() fonksiyonu devreye giriyor.
REPLACE() Fonksiyonu Nedir?
REPLACE() fonksiyonu, bir metin içindeki belirli bir karakter dizisini başka bir karakter dizisiyle değiştirmek için kullanılır. SQL’in standart string fonksiyonlarından biri olan bu araç, özellikle UPDATE sorguları ile birleştirildiğinde son derece güçlü bir veri temizleme ve güncelleme aracına dönüşür.
Söz dizimi son derece basittir:
REPLACE(str, find_string, replace_with)
- str: İşlem yapılacak kaynak metin veya sütun adı
- find_string: Aranacak ve değiştirilecek metin
- replace_with: Yerine geçecek yeni metin
Burada dikkat edilmesi gereken önemli bir nokta var: REPLACE() fonksiyonu büyük/küçük harf duyarlıdır. Yani “MySQL” ile “mysql” aynı string olarak değerlendirilmez. Bu davranış, kullandığınız sütunun collation ayarına göre farklılık gösterebilir, ancak genel kural olarak büyük/küçük harf duyarlılığını göz önünde bulundurmanız gerekir.
Temel Kullanım Örnekleri
En basit haliyle REPLACE() fonksiyonunu bir SELECT sorgusu içinde test edebilirsiniz:
SELECT REPLACE('Merhaba Dunya', 'Dunya', 'MySQL');
-- Sonuç: Merhaba MySQL
SELECT REPLACE('www.eski-site.com', 'eski-site', 'yeni-site');
-- Sonuç: www.yeni-site.com
Bu basit örnek, fonksiyonun mantığını anlamak için yeterli. Şimdi gerçek dünya senaryolarına geçelim.
Sütun Değerlerinde Değiştirme
Bir tablodaki sütun verilerini doğrudan güncellemek için UPDATE ile birleştiririz:
UPDATE urunler
SET aciklama = REPLACE(aciklama, 'eski marka', 'yeni marka')
WHERE aciklama LIKE '%eski marka%';
Burada WHERE koşulunu kullanmak önemli bir optimizasyon tekniğidir. LIKE '%eski marka%' filtresi sayesinde sadece ilgili satırlarda işlem yapılır, tablonun tamamı gereksiz yere güncellenmez. Özellikle milyonlarca satır içeren tablolarda bu fark, sorgu süresini ciddi ölçüde etkiler.
Gerçek Dünya Senaryosu 1: URL Migrasyonu
Bir e-ticaret sitesinin veritabanını HTTP’den HTTPS’e geçirdiğinizi düşünün. Ürün açıklamalarında, blog içeriklerinde ve kullanıcı profil sayfalarında yüzlerce hatta binlerce eski HTTP URL’si bulunabilir.
-- Önce kaç satırın etkileneceğini kontrol edin
SELECT COUNT(*) as etkilenen_satir
FROM blog_icerikler
WHERE icerik LIKE '%http://www.sirketim.com%';
-- Sonra güncellemeyi yapın
UPDATE blog_icerikler
SET icerik = REPLACE(icerik, 'http://www.sirketim.com', 'https://www.sirketim.com')
WHERE icerik LIKE '%http://www.sirketim.com%';
-- Değişikliği doğrulayın
SELECT COUNT(*) as kalan_http
FROM blog_icerikler
WHERE icerik LIKE '%http://www.sirketim.com%';
Bu üç adımlı yaklaşım, her güncelleme işleminden önce mutlaka uygulamanız gereken bir alışkanlık. Önce ne kadar etkileneceğini görün, güncelle, sonra doğrula.
Gerçek Dünya Senaryosu 2: Telefon Numarası Standartlaştırma
Müşteri veritabanlarında telefon numaraları genellikle farklı formatlarda girilmiş olur. Kimisi “(0212) 555-1234” yazarken kimisi “0212-555-1234” ya da “02125551234” yazar. Bu kaosla başa çıkmak için REPLACE() fonksiyonunu zincirleme kullanabilirsiniz:
-- Parantezleri, tire ve boşlukları kaldır
UPDATE musteriler
SET telefon = REPLACE(
REPLACE(
REPLACE(
REPLACE(telefon, '(', ''),
')', ''),
'-', ''),
' ', '');
Zincirleme REPLACE() kullanımı güçlü bir tekniktir. Her REPLACE() çağrısı, bir öncekinin çıktısını işler. Bu şekilde tek bir UPDATE sorgusunda birden fazla karakter değişikliği yapabilirsiniz.
Sonucu kontrol etmek için:
SELECT telefon, LENGTH(telefon) as uzunluk
FROM musteriler
WHERE LENGTH(telefon) != 10
LIMIT 20;
Gerçek Dünya Senaryosu 3: WordPress Veritabanı Migrasyonu
WordPress site taşıma işlemlerinde en sık karşılaşılan sorunlardan biri, veritabanında eski domain adresinin onlarca farklı tabloda bulunmasıdır. Üstelik wp_options ve wp_postmeta tablolarında bu veriler serialized PHP formatında saklanır. Ancak düz metin içeren alanlarda REPLACE() oldukça işe yarar:
-- wp_posts tablosundaki içerikleri güncelle
UPDATE wp_posts
SET post_content = REPLACE(post_content, 'http://eski-domain.com', 'https://yeni-domain.com')
WHERE post_content LIKE '%http://eski-domain.com%';
-- wp_posts tablosundaki guid'leri güncelle
UPDATE wp_posts
SET guid = REPLACE(guid, 'http://eski-domain.com', 'https://yeni-domain.com')
WHERE guid LIKE '%http://eski-domain.com%';
-- Menü linklerini güncelle
UPDATE wp_postmeta
SET meta_value = REPLACE(meta_value, 'http://eski-domain.com', 'https://yeni-domain.com')
WHERE meta_value LIKE '%http://eski-domain.com%'
AND meta_key = '_menu_item_url';
Önemli uyarı: WordPress için wp_options tablosundaki siteurl ve home değerlerini doğrudan UPDATE sorgusuyla veya phpMyAdmin üzerinden güncellemek çok daha güvenlidir. Serialized verilerde REPLACE() kullanmak, PHP’nin serialize boyut bilgilerini bozarak sitenizin çökmesine neden olabilir.
SELECT ile Değişikliği Önizleme
Üretim veritabanlarında UPDATE çalıştırmadan önce mutlaka sonuçları önizleyin. REPLACE() fonksiyonu SELECT içinde de çalıştığı için güncelleme öncesi nasıl görüneceğini görebilirsiniz:
SELECT
id,
baslik,
aciklama AS eski_aciklama,
REPLACE(aciklama, 'Şirket A.Ş.', 'Şirket Ltd. Şti.') AS yeni_aciklama
FROM urunler
WHERE aciklama LIKE '%Şirket A.Ş.%'
LIMIT 10;
Bu yaklaşım özellikle kritik verilerde çok değerlidir. Değişikliğin tam olarak istediğiniz gibi olup olmadığını görmeden UPDATE çalıştırmak, geri dönüşü zor hatalar yaratabilir.
REPLACE() ile Boşluk ve Özel Karakter Temizleme
Veritabanına dışarıdan aktarılan verilerde (CSV import, API entegrasyonu gibi) çeşitli görünmez karakterler ve istenmeyen boşluklar bulunabilir:
-- Çift boşlukları tek boşluğa indir
UPDATE makaleler
SET baslik = REPLACE(baslik, ' ', ' ')
WHERE baslik LIKE '% %';
-- Tab karakterlerini boşlukla değiştir
UPDATE log_kayitlari
SET mesaj = REPLACE(mesaj, 't', ' ')
WHERE mesaj LIKE '%t%';
-- Satır sonu karakterlerini temizle (Windows rn formatından Unix n formatına)
UPDATE formlar
SET kullanici_girisi = REPLACE(kullanici_girisi, 'rn', 'n')
WHERE kullanici_girisi LIKE '%rn%';
Büyük/Küçük Harf Duyarlılığı Sorunu
Daha önce belirttiğimiz gibi REPLACE() varsayılan olarak büyük/küçük harf duyarlıdır. Eğer harf büyüklüğünden bağımsız bir değiştirme yapmak istiyorsanız, birkaç farklı yöntem mevcuttur:
Yöntem 1: Tüm varyasyonları ayrı ayrı güncellemek
UPDATE urunler SET aciklama = REPLACE(aciklama, 'mysql', 'MariaDB') WHERE aciklama LIKE '%mysql%';
UPDATE urunler SET aciklama = REPLACE(aciklama, 'MySQL', 'MariaDB') WHERE aciklama LIKE '%MySQL%';
UPDATE urunler SET aciklama = REPLACE(aciklama, 'MYSQL', 'MariaDB') WHERE aciklama LIKE '%MYSQL%';
Yöntem 2: REGEXP_REPLACE kullanmak (MariaDB 10.0.5+ ve MySQL 8.0+)
-- Case-insensitive değiştirme için REGEXP_REPLACE
UPDATE urunler
SET aciklama = REGEXP_REPLACE(aciklama, '(?i)mysql', 'MariaDB')
WHERE aciklama REGEXP '(?i)mysql';
REGEXP_REPLACE() çok daha güçlü bir fonksiyon olmakla birlikte, sürüm uyumluluğunu kontrol etmek önemlidir. MariaDB 10.0.5 öncesi ve MySQL 8.0 öncesi sürümlerde bu fonksiyon bulunmaz.
Transaction ile Güvenli Güncelleme
Büyük güncelleme işlemlerini her zaman bir transaction içinde yapın. Böylece bir şeyler ters giderse kolayca geri alabilirsiniz:
-- Transaction başlat
START TRANSACTION;
-- Değişikliği yap
UPDATE urunler
SET urun_kodu = REPLACE(urun_kodu, 'OLD-', 'NEW-')
WHERE urun_kodu LIKE 'OLD-%';
-- Kaç satır etkilendi?
SELECT ROW_COUNT() as guncellenen_satir;
-- Sonuçları kontrol et
SELECT urun_kodu FROM urunler WHERE urun_kodu LIKE 'NEW-%' LIMIT 5;
-- Her şey yolundaysa onayla, değilse geri al
COMMIT;
-- Veya: ROLLBACK;
Bu alışkanlık, özellikle üretim ortamında çalışırken sizi ciddi sorunlardan koruyacaktır. ROW_COUNT() fonksiyonu son DML sorgusunun kaç satırı etkilediğini gösterir ve bu bilgi beklentilerinizle uyuşmuyorsa hemen ROLLBACK yapabilirsiniz.
Performans Optimizasyonu
REPLACE() fonksiyonu ile büyük tablolarda çalışırken dikkat edilmesi gereken birkaç önemli nokta var:
WHERE koşulu olmadan kullanmaktan kaçının
-- YANLIŞ: Tablodaki her satırı günceller, gereksiz yük oluşturur
UPDATE buyuk_tablo SET icerik = REPLACE(icerik, 'eski', 'yeni');
-- DOGRU: Sadece gerekli satırları günceller
UPDATE buyuk_tablo
SET icerik = REPLACE(icerik, 'eski', 'yeni')
WHERE icerik LIKE '%eski%';
Büyük tablolarda batch güncelleme yapın
Milyonlarca satırlı tablolarda tek seferde tüm verileri güncellemek, tabloya uzun süreli kilit koyabilir ve uygulamanızın yavaşlamasına neden olabilir. Bunun yerine batch güncelleme tercih edin:
-- Her seferinde 1000 satır güncelle
UPDATE buyuk_tablo
SET icerik = REPLACE(icerik, 'http://', 'https://')
WHERE icerik LIKE '%http://%'
AND id BETWEEN 1 AND 1000;
-- Sonraki batch
UPDATE buyuk_tablo
SET icerik = REPLACE(icerik, 'http://', 'https://')
WHERE icerik LIKE '%http://%'
AND id BETWEEN 1001 AND 2000;
Bu işlemi otomatikleştirmek için bir shell script yazabilirsiniz:
#!/bin/bash
DB_HOST="localhost"
DB_USER="root"
DB_PASS="sifreniz"
DB_NAME="veritabaniniz"
BATCH_SIZE=1000
# Toplam etkilenecek satır sayısını al
TOTAL=$(mysql -h$DB_HOST -u$DB_USER -p$DB_PASS $DB_NAME -se
"SELECT COUNT(*) FROM buyuk_tablo WHERE icerik LIKE '%http://%'")
echo "Toplam etkilenecek satir: $TOTAL"
# Max ID'yi al
MAX_ID=$(mysql -h$DB_HOST -u$DB_USER -p$DB_PASS $DB_NAME -se
"SELECT MAX(id) FROM buyuk_tablo")
START=1
while [ $START -le $MAX_ID ]; do
END=$((START + BATCH_SIZE - 1))
mysql -h$DB_HOST -u$DB_USER -p$DB_PASS $DB_NAME -e
"UPDATE buyuk_tablo SET icerik = REPLACE(icerik, 'http://', 'https://')
WHERE icerik LIKE '%http://%' AND id BETWEEN $START AND $END"
echo "ID $START - $END islendi"
START=$((END + 1))
sleep 0.1 # Sunucuya nefes aldır
done
echo "Islem tamamlandi!"
REPLACE() ile Birleşik Sorgular
REPLACE() fonksiyonu diğer SQL fonksiyonlarıyla da güzel kombinasyonlar oluşturur:
-- CONCAT ile birlikte: Değiştirme sonucuna ek metin ekle
SELECT CONCAT('[GUNCELLENDI] ', REPLACE(baslik, 'Draft', 'Taslak')) as yeni_baslik
FROM yazilar
WHERE baslik LIKE '%Draft%';
-- TRIM ile birlikte: Önce boşlukları temizle, sonra değiştir
UPDATE yorumlar
SET yorum_metni = REPLACE(TRIM(yorum_metni), ' ', ' ')
WHERE yorum_metni LIKE '% %';
-- LOWER ile birlikte: Küçük harfe çevir ve normalize et
UPDATE etiketler
SET etiket_adi = REPLACE(LOWER(etiket_adi), ' ', '-')
WHERE etiket_adi LIKE '% %';
Sık Yapılan Hatalar ve Çözümleri
Hata 1: Yedek almadan güncelleme yapmak
Bunu bir kural olarak benimseyin: Her büyük güncelleme öncesi etkilenecek tabloyu yedekleyin.
-- Güncelleme öncesi tablo yedeği
CREATE TABLE urunler_yedek_20240115 AS SELECT * FROM urunler;
-- Güncellemeyi yap
UPDATE urunler SET aciklama = REPLACE(aciklama, 'eski', 'yeni') WHERE aciklama LIKE '%eski%';
-- Sorun çıkarsa geri yükle
-- INSERT INTO urunler SELECT * FROM urunler_yedek_20240115;
Hata 2: NULL değerleri göz ardı etmek
REPLACE() fonksiyonu NULL değerler için NULL döndürür, bu genellikle beklenen davranıştır. Ancak dikkatli olunması gereken durumlar var:
-- NULL kontrolü ile güvenli güncelleme
UPDATE urunler
SET aciklama = REPLACE(aciklama, 'eski', 'yeni')
WHERE aciklama IS NOT NULL
AND aciklama LIKE '%eski%';
Hata 3: Çok geniş kapsamlı değiştirmeler
Çok kısa veya yaygın string’leri değiştirmeye çalışmak istenmeyen sonuçlar doğurabilir:
-- TEHLİKELİ: 'id' kelimesi beklenmedik yerlerde de geçiyor olabilir
UPDATE urunler SET aciklama = REPLACE(aciklama, 'id', 'kimlik');
-- "Ürün kodu" -> "Ürün komliklik" gibi çarpıcı sonuçlar çıkabilir
-- GÜVENLİ: Daha spesifik bir pattern kullan
UPDATE urunler SET aciklama = REPLACE(aciklama, ' id ', ' kimlik ')
WHERE aciklama LIKE '% id %';
REPLACE Komutundan Farklı: INSERT OR REPLACE
Burada önemli bir ayrımı da vurgulamak gerekiyor. SQL’de REPLACE adında hem bir fonksiyon hem de bir komut bulunur. Bu ikisi tamamen farklı şeylerdir:
REPLACE()fonksiyonu: String içinde metin değiştirmeREPLACE INTOkomutu: Eğer kayıt varsa sil ve yeniden ekle, yoksa ekle
-- Bu KOMUT'tur, fonksiyon değil!
-- Mevcut satırı siler ve yeni satır ekler
REPLACE INTO urunler (id, ad, fiyat)
VALUES (1, 'Yeni Ürün Adı', 99.90);
Bu ikisini karıştırmak, özellikle yeni başlayanlar arasında sık görülen bir hatadır.
Sonuç
REPLACE() fonksiyonu, MariaDB ve MySQL yöneticilerinin araç kutusunda mutlaka bulunması gereken basit ama son derece etkili bir fonksiyondur. Doğru kullanıldığında saatler sürecek manuel güncellemeleri saniyeler içinde halledebilir.
Özetlemek gerekirse:
- Her zaman önce SELECT ile test edin, ardından UPDATE çalıştırın
- Transaction kullanmayı alışkanlık haline getirin, özellikle kritik tablolarda
- WHERE koşuluyla daraltın, gereksiz satırları güncellemeyin
- Büyük tablolarda batch işlem yapın, sunucunuzu boğmayın
- Yedek alın, her zaman geri dönüş planınız olsun
- NULL değerlere dikkat edin, özellikle karmaşık sorgularda
- REPLACE() fonksiyonu ile REPLACE INTO komutunu karıştırmayın
Bu prensipleri takip ettiğinizde, veri migrasyonları ve toplu güncellemeler artık sizi tedirgin eden işlemler olmaktan çıkar, güvenle ve hızla tamamladığınız rutin sysadmin görevlerine dönüşür.
