مدیریت کاراکترهای یونیکد در SQL Server: راهنمای کامل NCHAR, NVARCHAR و توابع رشتهای
در هنگام کار با SQL Server، حتماً با انواع دادهها و توابع مختلفی برای ذخیره و دستکاری دادهها مواجه خواهید شد. انواع دادههای رشتهای از رایجترین مواردی هستند که روزانه با آنها سروکار داریم.
پیش از ظهور یونیکد، اکثر سیستمها و برنامهها برای نمایش کاراکترها به ASCII متکی بودند. ASCII مجموعه کاراکتر محدودی است که عمدتاً کاراکترهای انگلیسی، اعداد و نمادهای رایج را پوشش میدهد. با گسترش جهانی وب و نیاز به پشتیبانی از زبانهای مختلف، استاندارد یونیکد معرفی شد.
یونیکد (Unicode) یک استاندارد جهانی کدگذاری کاراکتر است که برای نمایش تمامی کاراکترها در اکثر زبانهای نوشتاری جهان طراحی شده است. یونیکد هر کاراکتر را با یک کد منحصر به فرد (کد پوینت) شناسایی میکند. این استاندارد مشکل ناسازگاری مجموعه کاراکترها را حل کرده و امکان ذخیره و نمایش متون چندزبانه را در SQL Server فراهم میآورد. این مقاله به بررسی چگونگی کار با کاراکترهای یونیکد در SQL Server، انواع دادههای مرتبط و توابع کاربردی میپردازد.
هنگام کار با دادههای یونیکد در SQL Server، باید صراحتاً اعلام کنید که یک مقدار رشتهای، یونیکد است. این کار با پیشوند ‘N’ در ابتدای رشته انجام میشود.
مثال:
SELECT N'این یک رشته یونیکد است.' AS UnicodeString;
این پیشوند ‘N’ به SQL Server اطلاع میدهد که رشته مورد نظر باید به عنوان داده یونیکد پردازش و ذخیره شود. اگر از این پیشوند استفاده نکنید، ممکن است کاراکترهای غیرلاتین به درستی ذخیره نشوند یا به علامت سوال تبدیل گردند.
SQL Server از سه نوع داده یونیکد پشتیبانی میکند: NCHAR، NVARCHAR و NTEXT.
-
NCHAR(n): این نوع داده برای ذخیره رشتههای یونیکد با طول ثابت استفاده میشود. ‘n’ تعداد کاراکترها را مشخص میکند و میتواند مقداری بین 1 تا 4000 باشد. اگر رشتهای کمتر از ‘n’ کاراکتر باشد، با فضاهای خالی تا طول ‘n’ پر میشود. هر کاراکتر در NCHAR دو بایت فضا اشغال میکند. به عنوان مثال، `NCHAR(10)` همیشه 20 بایت فضا میگیرد، حتی اگر فقط یک کاراکتر در آن ذخیره شده باشد.
-
NVARCHAR(n | MAX): این نوع داده برای ذخیره رشتههای یونیکد با طول متغیر استفاده میشود. ‘n’ تعداد کاراکترها را مشخص میکند و میتواند مقداری بین 1 تا 4000 باشد. در صورت استفاده از `MAX`، رشته میتواند تا 2 گیگابایت (1,073,741,823 کاراکتر) را ذخیره کند. NVARCHAR فقط به اندازه طول رشته واقعی به علاوه 2 بایت برای نگهداری اطلاعات طول، فضا اشغال میکند. این نوع داده برای اکثر سناریوهای ذخیرهسازی متن یونیکد ترجیح داده میشود، زیرا انعطافپذیری بالایی دارد و بهینه است.
-
NTEXT: این نوع داده قدیمیتر و منسوخ شده است (deprecated). برای ذخیره دادههای یونیکد با حجم بسیار زیاد استفاده میشد، اما توصیه میشود که به جای آن از `NVARCHAR(MAX)` استفاده شود. NTEXT به دلایل عملکردی و مدیریت حافظه در نسخههای جدید SQL Server به ندرت به کار میرود و ممکن است در نسخههای آینده کاملاً حذف شود.
Collation (قواعد مرتبسازی و مقایسه) نیز نقش مهمی در کار با دادههای یونیکد ایفا میکند. Collation قوانین مرتبسازی، مقایسه و حساسیت به حروف کوچک و بزرگ را برای دادههای کاراکتری مشخص میکند. برای دادههای یونیکد، از Collationهایی استفاده میشود که با `_BIN` یا `_SC` (Supplementary Character) یا `_UTF8` (در نسخههای جدیدتر) به پایان میرسند و معمولاً نامهایی مانند `SQL_Latin1_General_CP1_CI_AS` برای دادههای غیر یونیکد و `Latin1_General_100_CI_AS_SC` یا `Latin1_General_BIN2` برای دادههای یونیکد دارند. انتخاب Collation مناسب برای اطمینان از صحت عملیات مقایسه و مرتبسازی دادههای چندزبانه حیاتی است.
تابع UNICODE() مقدار عددی (کد پوینت) اولین کاراکتر رشته ورودی را برمیگرداند. این مقدار میتواند بین 0 تا 65535 باشد (برای UCS-2) یا تا 1,114,111 (برای UTF-16). این تابع برای درک نمایش عددی یک کاراکتر یونیکد مفید است.
سینتکس این تابع به صورت زیر است:
UNICODE (character_expression)
مثالهایی از کاربرد آن:
SELECT UNICODE('A') AS UnicodeOfA;
SELECT UNICODE(N'ع') AS UnicodeOfArabicAin;
SELECT UNICODE(N'€') AS UnicodeOfEuroSign;
خروجی نشان میدهد که ‘A’ دارای کد پوینت 65، ‘ع’ دارای کد پوینت 1591 و ‘€’ دارای کد پوینت 8364 است.
تابع NCHAR() کاراکتر یونیکد مربوط به یک مقدار عددی (کد پوینت) مشخص را برمیگرداند. این تابع عمل برعکس تابع UNICODE() را انجام میدهد و برای تبدیل یک مقدار عددی به کاراکتر یونیکد آن استفاده میشود.
سینتکس این تابع به صورت زیر است:
NCHAR (integer_expression)
مثالهایی از کاربرد آن:
SELECT NCHAR(65) AS CharFrom65;
SELECT NCHAR(1591) AS CharFrom1591;
SELECT NCHAR(8364) AS CharFrom8364;
خروجی این مثالها به ترتیب ‘A’، ‘ع’ و ‘€’ خواهد بود.
تابع ASCII() مقدار ASCII (عددی) اولین کاراکتر رشته ورودی را برمیگرداند. این تابع فقط برای کاراکترهایی که در مجموعه کاراکتر ASCII (0-255) قرار دارند، مقادیر معتبری را تولید میکند. برای کاراکترهای یونیکد خارج از این محدوده، رفتار آن ممکن است غیرمنتظره باشد یا مقدار نادرستی بدهد.
سینتکس این تابع به صورت زیر است:
ASCII (character_expression)
مثالهایی از کاربرد آن:
SELECT ASCII('A') AS AsciiOfA;
SELECT ASCII('a') AS AsciiOfSmallA;
SELECT ASCII('1') AS AsciiOfOne;
خروجی این مثالها به ترتیب 65، 97 و 49 خواهد بود. توجه داشته باشید که این تابع برای کاراکترهای یونیکد مانند فارسی یا عربی کاربرد ندارد و ممکن است خروجی 63 (کد ASCII برای علامت سوال) را برای آنها برگرداند.
تابع CHAR() کاراکتر مربوط به یک مقدار عددی ASCII مشخص را برمیگرداند. این تابع نیز مانند ASCII()، محدود به کاراکترهای ASCII است و برای کاراکترهای یونیکد گسترده مناسب نیست. این تابع عمل برعکس ASCII() را انجام میدهد.
سینتکس این تابع به صورت زیر است:
CHAR (integer_expression)
مثالهایی از کاربرد آن:
SELECT CHAR(65) AS CharFrom65;
SELECT CHAR(97) AS CharFrom97;
SELECT CHAR(49) AS CharFrom49;
خروجی این مثالها به ترتیب ‘A’، ‘a’ و ‘1’ خواهد بود.
در هنگام کار با رشتهها، به ویژه دادههای یونیکد، درک تفاوت بین توابع LEN() و DATALENGTH() بسیار مهم است.
-
LEN(string_expression): تابع LEN() تعداد کاراکترهای موجود در یک رشته را برمیگرداند. این تابع فضاهای خالی انتهایی (trailing blanks) را نادیده میگیرد. برای دادههای یونیکد (مانند NVARCHAR)، هر کاراکتر به عنوان یک واحد شمرده میشود، بدون توجه به اینکه چند بایت فضا اشغال کرده است. یعنی، LEN(N’سلام’) 4 را برمیگرداند.
-
DATALENGTH(expression): تابع DATALENGTH() تعداد بایتهای واقعی استفاده شده برای ذخیرهسازی یک عبارت را برمیگرداند. این تابع شامل تمام بایتها، از جمله فضاهای خالی انتهایی و فضاهای اضافی مورد استفاده توسط انواع دادهای مانند NVARCHAR (که هر کاراکتر 2 بایت است)، میشود. برای یک رشته NVARCHAR، DATALENGTH دو برابر LEN خواهد بود.
مثال مقایسهای:
DECLARE @UnicodeString NVARCHAR(50) = N'Hello World';
DECLARE @NonUnicodeString VARCHAR(50) = 'Hello World';
DECLARE @PersianUnicode NVARCHAR(50) = N'تست فارسی';
SELECT
LEN(@UnicodeString) AS LengthUnicode,
DATALENGTH(@UnicodeString) AS DataLengthUnicode,
LEN(@NonUnicodeString) AS LengthNonUnicode,
DATALENGTH(@NonUnicodeString) AS DataLengthNonUnicode,
LEN(@PersianUnicode) AS LengthPersianUnicode,
DATALENGTH(@PersianUnicode) AS DataLengthPersianUnicode;
در این مثال، برای `N’Hello World’` تابع `LEN()` مقدار 11 (تعداد کاراکترها) را برمیگرداند، در حالی که `DATALENGTH()` مقدار 22 (11 کاراکتر * 2 بایت در هر کاراکتر) را نشان میدهد. برای رشتههای `VARCHAR`، `LEN()` و `DATALENGTH()` معمولاً مقدار یکسانی را برمیگردانند (به شرطی که هر کاراکتر 1 بایت فضا اشغال کند). این تفاوت در محاسبه تعداد کاراکتر در مقابل تعداد بایت، هنگام تخصیص فضا و بهینهسازی ذخیرهسازی در SQL Server بسیار مهم است.