# پایگاه‌های داده > SQL Server > T-SQL >  آموزش اصلاح کلمات عربی در دیتابیس

## یوسف زالی

سلام خدمت دوستان.
برای اینکه یک بار برای همیشه این مشکل رفع بشه براتون یک پروسیجر نوشتم که کافیه اون رو در دیتابیستون ران کنید.
این استور پروسیجر رو ران کنید و سپس در یک نیو کوئری بنویسید:
Exec ChangeCodePage

همین!

سوالی بود در خدمتم.

----------


## سوداگر

سلام
این سوال رو چندبار توی تالار سی شارپ مطرح کردن و این مشکل رو با کدنویسی حل کردن. میخواستم بدونم توی ویژوال استدیو چطور از این فایل استفاده کنیم؟

----------


## یوسف زالی

این فایل در اس کیو ال ران می شه.
در ویژوال استودیو می تونید با اجرا کردن کامند Exec ChangeCodePage کاراکتر های تمام جداول رو اصلاح کنید.
دقت کنید که این روش درمان هست نه پیشگیری. برای از این به بعدتون باید هنگام اینسرت مدیریت کنید که کدوم کاراکتر ها جایگزین بشند.

----------


## محمدجواد67

> سلام خدمت دوستان.
> برای اینکه یک بار برای همیشه این مشکل رفع بشه براتون یک پروسیجر نوشتم که کافیه اون رو در دیتابیستون ران کنید.
> این استور پروسیجر رو ران کنید و سپس در یک نیو کوئری بنویسید:
> Exec ChangeCodePage
> 
> همین!
> 
> سوالی بود در خدمتم.


 سلام دیگه احتیاجی نیست نام table ها رو عوض کرد

----------


## یوسف زالی

سلام. نمی دونم منظورتون از اصلاح نام جدول چیه، نیازی به کار اضافی نداره.

----------


## محمد سلیم آبادی

سلام،
جناب یوسف من stored procedure اتان را مشاهده کردم. کار خوبی بود. چند نکته به نظرم رسید که میخوام به اطلاع شما برسانم. اگر نقد و بررسی بود در خدمتم.
مساله که وجود داره این هست که شما تمام سطرهای یک جدول را بروز رسانی می کنید یعنی حتی سطرهایی که نیاز به بروز رسانی ندارند را نیز بروز رسانی می کنید. فرض کنید 100 هزار داده داریم که فقط 1 هزار تای آنها نیاز به بروز رسانی دارند در اینجا ما 99 هزار سطر دیگر که لزومی به بروز رسانی نداشته اند را درگیر کردیم.
برای رفع این مساله بایستی WHERE را به دستور UPDATE اضافه کنیم چیزی شبیه به این:
select @x = 
' update [' + TblName + ']   
     set [' + ColName + '] = Replace( Replace( Replace([' + ColName + '], nchar(1603), nchar(1705)), nchar(1610), nchar(1740)), nchar(1609), nchar(1740))
   where charindex(nchar(1603),[' + ColName + '])>0 or charindex(nchar(1610),[' + ColName + '])>0 or charindex(nchar(1609),[' + ColName + '])>0;

'
from 

و سوالی که از شما دارم این است که دلیل خاصی دارد که شما update ها را دانه به دانه اجرا میکنید. مثلا چه error هایی پیش بینی کردین که ممکنه در حین اجرای update رخ دهد؟

پیشنهاد دیگری که دارم این هست که شما اگر به ازای هر جدول فقط یک دستور update داشتید بهتر بود. فرض کنید یک جدول دارای 5 فیلد از نوع رشته ای است طبق روال شما این جدول 5 دفعه بروز رسانی میشه اما میشه کاری کرد که فقط یکبار آن دستور اجرا می شد... البته امکان پیاده سازی این موضوع برمی گرده به سوال قبل.

----------


## یوسف زالی

این پروسیجر برمی گرده به خیلی قبل، احتمال بهینه نبودنش زیاده اما کار راه اندازه.
اون لیست ارور ها رو هم برای بررسی گذاشته بودم ببینم چه ارور هایی احتمال داره بوجود بیاد که براش بعد تر هندلینگ درستی نوشت، وگرنه حرف شما درسته.
می شه خیلی سریعتر کار کرد و بهینه تر نوشت.

----------


## محمد سلیم آبادی

اوه، راست میگین این تاپیک مال سال 90 من فکر میکردم مربوط به تازگی هاست.

----------


## sayanpro

سلام. با اینکه خیلی وقت از این تاپیک میگذره ولی تقاضا دارم که دوستان گرامی آقایان You-See و محمد سلیم آبادی 
نسخه بهینه شده این SP که در گفتگوهاشون مطرح شده، بازنویسی کنند.

با تشکر. :تشویق:  :تشویق:  :تشویق:

----------


## یوسف زالی

نسخه بهینه شده که الان نوشتم:




CREATE PROCEDURE ChangeCodePageNew
  @TableName VARCHAR(100)
AS


DECLARE @ColHolder CHAR(1) = '@'
DECLARE @Replace VARCHAR(4000) = 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(R  EPLACE(REPLACE([' + @ColHolder + '], NCHAR(1571), NCHAR(1575)), NCHAR(1573), NCHAR(1575)), NCHAR(1609), NCHAR(1610)), NCHAR(1746), NCHAR(1610)), NCHAR(1574), NCHAR(1610)), NCHAR(1572), NCHAR(1608)), NCHAR(1729), NCHAR(1607)), NCHAR(1603), NCHAR(1705))'
DECLARE @X VARCHAR(MAX) = ''


;WITH CTE AS (
  SELECT A.name TBL, B.name COL
  FROM sys.tables A
    JOIN sys.columns B ON A.object_id = B.object_id and ISNULL(@TableName, '') IN ('', A.name)
    JOIN sys.types C ON B.system_type_id = C.system_type_id AND C.name IN ('char', 'nchar', 'varchar', 'nvarchar')
)


SELECT @X +=
  'update ' + TBL + CHAR(13)
  + 'set' + CHAR(13)
  + SUBSTRING(
   (
     SELECT ',  ' + COL + ' = ' + REPLACE(@Replace, @ColHolder, COL)
     FROM CTE Y
     WHERE X.TBL = Y.TBL
     FOR XML PATH('')
    ), 2, 1000000) + CHAR(13)
  + CHAR(13)
FROM CTE X
GROUP BY TBL


EXEC(@X)




هرجا توضیح لازم بود بگید، اضافه کنم که به نظرم چک کردن وجود فیلدی که باید آپدیت بشه خودش به اندازه جایگزینی زمان بره، و بهینه سازی در اون حد از نظرم بی فایده اومد.
موفق باشید.

پ.ن:
ویرایشگر نادون این سایت بعضی جاها فاصله می ندازه، در هنگام کپی، حواستون باشه!

----------


## sayanpro

از زحمات شما تشکر می کنم.

----------


## rahmatipoor

تشکر از آقای زالی عزیز  :قلب: 
بسیار عالی 

این کد شما به بهترین شکل ممکن مشکل ما رو حل کرد

قبلا باید توی سی شارپ کلی کد می نوشتیم و برای هر جدول هم جدا جدا کد می نوشتیم که زمانبر هم بود.

با این کد با یک کلیک همه دیتابیس اصلاح میشه.

فقط نسخه جدیدی که تهیه کردید برای ما کار نکرد و به مشکل برخورد و ما از همونی که توی پست اول گذاشتید استفاده کردیم.

البته از جهاتی همون استور پروسیبجر اولی بهتره چون برای همه جداول اعمال میشه ولی دومی پارامتر ورودی داره و باید تک تک روی همه جداول اجرا بشه.

باز هم ممنون

----------


## rahmatipoor

با اجازه از استاد زالی عزیز با استفاده از آموزش خیلی خوبشون یک پروژه سی شارپ تهیه کردم که به صورت اتوماتیک و با یک کلیک استور پروسیجر موردنظر رو روی دیتابیس موردنظر  ایجاد میکنه ، بعدش اجرا میشه و در نهایت  اون رو حذف میکنه.

فقط باید توی کلاس clsAccessData توی خط اول ( رشته ConStr ) رشته اتصال خودتون رو جایگزین کنید.

string ConStr = @"Data Source=.\InstanceName; database = DataBaseName ; Integrated Security=True";





[/CSHARP]


از دات نت بار 2 هم استفاده شده که dll اون توی مسیر bin توی پروژه هست و توی پروژه های خودتون باید به رفرنسهاتون اضافه بشه.

لینک دانلود پروژه

----------


## rahmatipoor

--------------------------------------

----------


## danialafshari

> با اجازه از استاد زالی عزیز با استفاده از آموزش خیلی خوبشون یک پروژه سی شارپ تهیه کردم که به صورت اتوماتیک و با یک کلیک استور پروسیجر موردنظر رو روی دیتابیس موردنظر  ایجاد میکنه ، بعدش اجرا میشه و در نهایت  اون رو حذف میکنه.
> 
> فقط باید توی کلاس clsAccessData توی خط اول ( رشته ConStr ) رشته اتصال خودتون رو جایگزین کنید.
> 
> string ConStr = @"Data Source=.\InstanceName; database = DataBaseName ; Integrated Security=True";
> 
> 
> 
> 
> ...


با سلام
کار خوب و جالبی انجام دادید هر چند که ندیدمش ولی طبق توضیحات خوبه
برای بهتر شدن برنامتون میتونید لینک Connection یا نام دیتابیس و سرور رو از کاربر بگیرید و تبدیل رو انجام بدید اینطور نیازی نیست که کاربر وارد سورس بشه (ویژوال داشته باشه) 
اگر وقت شد شاید خودم اصلاحش کنم
موفق باشید

----------


## rahmatipoor

ممنون شما لطف دارید

بله قطعا اگه اینطوری باشه خیلی بهتره

----------

