۱۳۸۷/۱۰/۲۴

مشكل ي و ك فارسي و عربي در يك ديتابيس اس كيوال سرور


ديروز به من اطلاع دادند كه در يكي از برنامه‌ها دو تا گروه "تاسيسات مكانيكي" پيدا شده!!
تاسيسات مكانيكي
تاسيسات مکانیکی

استاندارد اين شركت، استفاده از kbdfa.dll مخصوص و نسبتا قديمي است. بنابراين استاندارد مورد استفاده همان ي و ك عربي است. (كاري ندارم خوب است يا بد، يا بايد اينطور باشد يا نه، بحث اين است كه فعلا اينطور است و قرار نيست چيزي عوض بشود!)
در مثال فوق، ي و ك عبارت دوم فارسي است. يعني نصب kbdfa.dll روي ويندوز تازه نصب شده، فراموش شده بوده.

راه حل‌ها:
الف) قبل از ثبت، يكسان سازي صورت گيرد. يعني اجراي متدي شبيه به متد زير بر روي هر ورودي متني فارسي:

public string SafeFarsiStr(string input)
{
return input.Replace("ی", "ي").Replace("ک", "ك");
}

ب) خوب، الان كه اين يكسان سازي صورت نگرفته چه بايد كرد؟
اسكريپتي را تهيه كرده‌ام (مخصوص SQL Server 2005 به بعد) به صورت زير كه اين تبديل را براي شما انجام مي‌دهد.
به صورت خودكار تمامي فيلدهاي متني كليه جداول ديتابيس جاري شما را يافته و ي و ك آن‌ها را يكسان مي‌كند. البته همانطور كه عرض شد، مطابق استاندارد اين شركت و استفاده از فايل kbdfa.dll قديمي مورد استفاده، تمام ي و ك هاي فارسي به عربي تبديل مي‌شوند.

--اسكريپتي براي يك دست سازي ي و ك در تمامي ركوردهاي تمامي جداول ديتابيس جاري
-- اسكريپت زير ي و ك فارسي را به عربي تبديل مي‌كند
-- در صورت نياز به حالت عكس ، جاي مقادير عددي يونيكد را تعويض نمائيد

USE TestDb;

DECLARE @Table NVARCHAR(MAX),
@Col NVARCHAR(MAX)

DECLARE Table_Cursor CURSOR
FOR
--پيدا كردن تمام فيلدهاي متني تمام جداول ديتابيس جاري
SELECT a.name, --table
b.name --col
FROM sysobjects a,
syscolumns b
WHERE a.id = b.id
AND a.xtype = 'u' --User table
AND (
b.xtype = 99 --ntext
OR b.xtype = 35 -- text
OR b.xtype = 231 --nvarchar
OR b.xtype = 167 --varchar
OR b.xtype = 175 --char
OR b.xtype = 239 --nchar
)

OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @Table,@Col
WHILE (@@FETCH_STATUS = 0)
BEGIN
EXEC (
'update [' + @Table + '] set [' + @Col +
']= REPLACE(REPLACE(CAST([' + @Col +
'] as nvarchar(max)) , NCHAR(1740), NCHAR(1610)),NCHAR(1705),NCHAR(1603)) '
)

FETCH NEXT FROM Table_Cursor INTO @Table,@Col
END CLOSE Table_Cursor DEALLOCATE Table_Cursor

توضيحات و نكاتي در مورد اسكريپت فوق:
الف) براي آشنايي با انواع XType Datatype مورد استفاده در كوئري فوق به اين آدرس مراجعه نمائيد.
ب) همانطور كه در مطالب قبلي اين وبلاگ نيز ذكر شد، امكان استفاده از تابع replace بر روي فيلدهاي text و ntext وجود ندارد. هيچ اشكالي ندارد! تمام آن‌ها به nvarchar از نوع max دار cast شده و اين مشكل به اين صورت حل مي‌شود.
ج) اس كيوال سرور اجازه تعريف يك جدول يا فيلد را به صورت متغير بكار رفته در يك كوئري T-SQL نمي‌دهد. براي حل اين موضوع بايد عبارت SQL مورد نظر را به صورت يك رشته درآورد و سپس exec كرد.
د) مجبور شدم از معاد‌ل‌هاي عددي براي دقت بيشتر كار استفاده كنم



(در كل از تابع UNICODE اس كيوال سرور براي بدست آوردن اين اعداد مي‌توان استفاده كرد)

تذكر: اين اسكريپت بر روي يك ديتابيس كاري تست شده و نتيجه رضايت بخش بوده؛ اما اگر شما روزي خواستيد از آن استفاده كنيد، حتما full backup را قبل از اجراي آن فراموش نكنيد و پس از اجرا، تابع SafeFarsiStr فوق را براي ادامه كار حتما لحاظ نمائيد يا از يك kbdfa.dll هماهنگ استفاده كنيد.