SQL Server'da Collation (Karşılaştırma Seti) Sorunu ve Çözümü
Projelerinizde metinsel verileri sıralarken, ararken veya iki tabloyu birleştirirken (JOIN) karakter uyumsuzluğu hataları alıyorsanız, veritabanınızın Collation ayarı projenizin dil kurallarıyla uyuşmuyor demektir.
Genelde SQL Server kurulurken varsayılan olarak bırakılan ayarlar, veritabanı büyüdükçe bu tarz kronik sorunlara yol açar. Çözüm ise veritabanını güvenle Turkish_CI_AS (büyük/küçük harf duyarsız, aksan duyarlı) formatına geçirmektir.
Peki, canlıdaki bir veritabanını patlatmadan ve veri kaybı yaşamadan bu değişiklik en pratik yoldan nasıl yapılır?
Sadece Veritabanı Ayarını Değiştirmek Yetmez
En sık yapılan hata, sadece tek satırlık bir ALTER DATABASE ... COLLATE komutu çalıştırıp her şeyin çözüldüğünü sanmaktır.
Bu komut sadece veritabanının genel ayarını değiştirir; içerideki mevcut tabloların ve sütunların (NVARCHAR, VARCHAR vb.) ayarları eski haliyle kalır. Gerçek bir çözüm için hem veritabanı seviyesini hem de tüm sütunları tek tek güncellemek gerekir.
Güvenli Geçiş İçin Pratik Yol Haritası
İşlemi canlı ortamda yapacaksanız, sıfır riskle ilerlemek için şu basit adımları izleyin:
1. Tam Yedek Alın: Bu tarz yapısal değişikliklerde ilk kural her zaman arkamızı sağlama almaktır. İşleme başlamadan önce veritabanınızın temiz bir yedeğini mutlaka kenara koyun.
2. Canlı Bağlantıları Kesin: Veritabanı üzerinde bu kadar köklü bir değişiklik yaparken dışarıdan sorgu gelmemesi gerekir. Bu yüzden uygulamayı kısa süreliğine bakım moduna alın ve veritabanını
SINGLE_USER(Tek Kullanıcı) moduna çekerek dış dünyaya kapatın.3. Ana Ayarı Güncelleyin: Bağlantıları kestiyseniz, ilk olarak veritabanının genel collation ayarını
Turkish_CI_ASolarak güncelleyin.4. Sütunları Dönüştürün: Veritabanındaki tüm tabloları tarayıp, metin içeren sütunları yeni collation ayarına geçirmeniz gerekir. Eğer sütun üzerinde bir Foreign Key (ilişki) veya yardımcı indeks varsa, SQL Server hata verecektir. Bu yüzden güvenli bir script önce bu ilişkileri ve indeksleri geçici olarak kaldırır, sütunu günceller ve ardından otomatik olarak geri yükler.
5. Dünyayı Yeniden Açın: Tüm sütunlar güncellenikten sonra veritabanını tekrar
MULTI_USERmoduna alıp uygulamanızı ayağa kaldırabilirsiniz.Dikkat Edilmesi Gereken İstisnalar
Primary Key ve Formüllü Sütunlar: Eğer metin tabanlı bir sütun aynı zamanda bir Primary Key (Birincil Anahtar) ise veya hesaplanmış (Computed) bir sütunsa, bunları otomatik scriptlerle değiştirmek yerine elle (manuel) müdahale etmek daha güvenlidir.
Performans Kontrolü: İşlem sırasında metin sütunlarındaki yardımcı indeksler kaldırılacağı için, geçiş sonrasında performans düşüşü yaşamamak adına bu indeksleri tekrar kontrol edip oluşturmayı unutmayın.
-- Değiştirilecek collation'ı tanımlayın
DECLARE @NewCollation NVARCHAR(128) = 'Turkish_CI_AS'; -- Örnek: Turkish_CI_AS (istediğiniz collation'ı buraya yazın)
-- 1. Veritabanı collation'ını değiştir
DECLARE @DatabaseName NVARCHAR(128) = DB_NAME(); -- Mevcut veritabanı adını al
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = 'ALTER DATABASE [' + @DatabaseName + '] COLLATE ' + @NewCollation;
EXEC sp_executesql @SQL;
-- Veritabanını single-user moda al (isteğe bağlı, değişikliklerin uygulanması için)
SET @SQL = 'ALTER DATABASE [' + @DatabaseName + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
EXEC sp_executesql @SQL;
SET @SQL = 'ALTER DATABASE [' + @DatabaseName + '] SET MULTI_USER';
EXEC sp_executesql @SQL;
-- 2. Tüm tabloların metin sütunlarının collation'larını değiştir
SET @SQL = '';
SELECT
@SQL = @SQL +
'ALTER TABLE [' + s.name + '].[' + t.name + '] ' +
'ALTER COLUMN [' + c.name + '] ' +
TYPE_NAME(c.system_type_id) +
CASE
WHEN c.max_length = -1 THEN '(MAX)'
WHEN TYPE_NAME(c.system_type_id) IN ('NVARCHAR', 'NCHAR') THEN '(' + CAST(c.max_length / 2 AS NVARCHAR(10)) + ')'
WHEN TYPE_NAME(c.system_type_id) IN ('VARCHAR', 'CHAR') THEN '(' + CAST(c.max_length AS NVARCHAR(10)) + ')'
ELSE ''
END +
' COLLATE ' + @NewCollation + ' ' +
CASE WHEN c.is_nullable = 1 THEN 'NULL' ELSE 'NOT NULL' END + ';' + CHAR(13)
FROM
sys.tables t
JOIN sys.schemas s ON t.schema_id = s.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
JOIN sys.types tp ON c.system_type_id = tp.system_type_id
WHERE
tp.name IN ('CHAR', 'VARCHAR', 'NCHAR', 'NVARCHAR') -- Metin tabanlı sütunlar
AND c.collation_name IS NOT NULL
AND c.collation_name != @NewCollation; -- Zaten hedef collation değilse
-- Oluşturulan SQL komutlarını çalıştır
IF @SQL != ''
BEGIN
PRINT @SQL; -- Önce komutları görmek için yazdır
EXEC sp_executesql @SQL; -- Komutları çalıştır
END
ELSE
BEGIN
PRINT 'Değiştirilecek sütun bulunamadı.';
END
Bir Yorum Bırakın