آموزش تابع STRING_AGG در SQL Server؛ از مقدماتی تا پیشرفته

آموزش کامل تابع STRING_AGG در SQL Server با مثال‌های کاربردی

توسط admin | گروه SQL Server | 1405/04/26

نظرات 0

آموزش کامل تابع STRING_AGG در SQL Server با مثال‌های کاربردی

مقدمه

تابع STRING_AGG یکی از توابع تجمعی مهم در Microsoft SQL Server است که چند مقدار متنی را از چند ردیف دریافت می‌کند و آن‌ها را در یک رشته واحد کنار هم قرار می‌دهد. پیش از معرفی این تابع، توسعه‌دهندگان معمولاً برای ساخت فهرست‌های متنی از روش‌هایی مانند FOR XML PATH، متغیرهای حلقه‌ای یا کدنویسی سمت برنامه استفاده می‌کردند. این روش‌ها در بسیاری از پروژه‌ها پیچیده، سخت‌خوان و مستعد خطا بودند. STRING_AGG کد را کوتاه‌تر می‌کند و برای ساخت فهرست نام کاربران، برچسب‌های یک مقاله، محصولات یک سفارش، نقش‌های یک کاربر و گزارش‌های گروه‌بندی‌شده بسیار مناسب است.

این تابع از SQL Server 2017 در دسترس است. برای استفاده حرفه‌ای باید علاوه بر نحو ساده، رفتار آن در برابر NULL، نوع داده خروجی، ترتیب مقادیر و تأثیر حجم داده بر حافظه و زمان اجرا را بدانید. در این مقاله از سطح مقدماتی شروع می‌کنیم و سپس به مثال‌های پیشرفته و نکات بهینه‌سازی می‌رسیم.

تعریف تابع STRING_AGG

STRING_AGG مقادیر یک عبارت را برای تمام ردیف‌های یک گروه دریافت می‌کند، بین آن‌ها جداکننده قرار می‌دهد و یک رشته واحد برمی‌گرداند. این تابع مانند SUM و COUNT یک تابع تجمعی است، با این تفاوت که به جای جمع عددها یا شمارش ردیف‌ها، متن‌ها را ترکیب می‌کند.

نحو

STRING_AGG ( expression, separator )
[ WITHIN GROUP ( ORDER BY order_expression [ ASC | DESC ] ) ]

پارامترها

  • expression: عبارت یا ستونی که مقادیر آن باید به متن تبدیل و ترکیب شوند.
  • separator: جداکننده بین مقادیر مانند ویرگول، خط تیره یا کاراکتر رفتن به خط بعد.
  • WITHIN GROUP: بخش اختیاری برای تعیین ترتیب قرارگیری مقادیر در رشته نهایی.

نوع خروجی

نوع خروجی به نوع expression وابسته است. اگر ورودی nvarchar باشد خروجی نیز معمولاً nvarchar خواهد بود. برای جلوگیری از محدودیت طول در فهرست‌های بزرگ، بهتر است ورودی را به nvarchar(max) تبدیل کنید. اگر خروجی از ظرفیت نوع داده عبور کند، امکان بروز خطای طول وجود دارد.

اولین مثال عملی

DECLARE @Employees TABLE
(
    EmployeeID int,
    FullName nvarchar(100),
    DepartmentName nvarchar(100)
);

INSERT INTO @Employees VALUES
(1, N'علی رضایی', N'فروش'),
(2, N'مریم کریمی', N'فروش'),
(3, N'حسن محمدی', N'فنی');

SELECT STRING_AGG(FullName, N'، ') AS EmployeeNames
FROM @Employees;
EmployeeNames
علی رضایی، مریم کریمی، حسن محمدی

در این مثال، سه ردیف به یک رشته تبدیل شده‌اند. جداکننده تنها بین مقادیر قرار می‌گیرد و در ابتدای یا انتهای رشته اضافه نمی‌شود.

گروه‌بندی همراه با STRING_AGG

SELECT
    DepartmentName,
    STRING_AGG(CONVERT(nvarchar(max), FullName), N'، ')
        WITHIN GROUP (ORDER BY FullName) AS EmployeeNames
FROM @Employees
GROUP BY DepartmentName;
DepartmentNameEmployeeNames
فروشعلی رضایی، مریم کریمی
فنیحسن محمدی

GROUP BY تعیین می‌کند برای هر واحد سازمانی یک خروجی جدا ساخته شود. WITHIN GROUP نیز باعث می‌شود نام‌ها بر اساس FullName مرتب شوند. بدون ORDER BY نباید به ترتیب ظاهری نتیجه تکیه کنید، زیرا موتور SQL Server می‌تواند بر اساس طرح اجرا ترتیب متفاوتی تولید کند.

رفتار تابع در برابر NULL

STRING_AGG مقادیر NULL را نادیده می‌گیرد و برای آن‌ها جداکننده ایجاد نمی‌کند. اگر لازم است به جای NULL عبارت مشخصی دیده شود، از ISNULL یا COALESCE استفاده کنید.

DECLARE @Contacts TABLE
(
    CustomerName nvarchar(100),
    Mobile nvarchar(20)
);

INSERT INTO @Contacts VALUES
(N'شرکت آریا', N'09120000001'),
(N'شرکت بهار', NULL),
(N'شرکت پارس', N'09120000003');

SELECT STRING_AGG(
           CONCAT(CustomerName, N': ', ISNULL(Mobile, N'بدون شماره')),
           N' | '
       ) AS ContactList
FROM @Contacts;

نتیجه شامل هر سه مشتری است و برای مشتری دوم عبارت «بدون شماره» نمایش داده می‌شود.

مثال واقعی: ساخت برچسب‌های هر مقاله

SELECT
    NewsID,
    STRING_AGG(CONVERT(nvarchar(max), TagDescription), N'، ')
        WITHIN GROUP (ORDER BY TagDescription) AS Tags
FROM dbo.tblTags
GROUP BY NewsID;

این کوئری برای هر NewsID تمام برچسب‌ها را در یک ستون بازمی‌گرداند. اگر تعداد تگ‌ها زیاد است، تبدیل TagDescription به nvarchar(max) مانع محدود شدن خروجی به طول ثابت می‌شود.

اشتباهات رایج

  • انتظار داشتن ترتیب ثابت بدون استفاده از WITHIN GROUP و ORDER BY.
  • ترکیب مستقیم ستون‌های عددی بدون تبدیل روشن به نوع متنی.
  • استفاده از varchar برای متن فارسی و از دست رفتن کاراکترهای یونیکد.
  • نادیده گرفتن NULL و تصور اینکه برای آن مقدار خالی تولید می‌شود.
  • ساخت رشته بسیار بزرگ بدون در نظر گرفتن حافظه، مرتب‌سازی و نوع داده max.
  • استفاده از DISTINCT به شکل مستقیم داخل STRING_AGG؛ در بسیاری از نسخه‌ها باید ابتدا مقادیر یکتا را در زیرکوئری تهیه کرد.

حذف مقادیر تکراری

SELECT STRING_AGG(CONVERT(nvarchar(max), TagDescription), N'، ')
FROM
(
    SELECT DISTINCT TagDescription
    FROM dbo.tblTags
    WHERE NewsID = 1
) AS UniqueTags;

نکات کارایی

STRING_AGG معمولاً از راه‌حل‌های مبتنی بر حلقه سریع‌تر و خواناتر است، اما مرتب‌سازی در WITHIN GROUP می‌تواند هزینه ایجاد کند. اگر کوئری بر اساس NewsID گروه‌بندی و بر اساس TagDescription مرتب می‌شود، ایندکس مناسب روی این ستون‌ها می‌تواند تعداد عملیات Sort را کاهش دهد. از SELECT کردن ستون‌های غیرضروری خودداری کنید و پیش از تجمع، داده‌ها را با WHERE محدود کنید. در گزارش‌های بسیار بزرگ، طرح اجرا، Memory Grant و احتمال Spill به tempdb را بررسی کنید.

برای داده‌های فارسی، ورودی و جداکننده را nvarchar در نظر بگیرید و رشته‌ها را با پیشوند N بنویسید.

بهترین روش‌ها

  1. برای ترتیب قابل پیش‌بینی از WITHIN GROUP استفاده کنید.
  2. برای خروجی‌های طولانی expression را به nvarchar(max) تبدیل کنید.
  3. NULL را آگاهانه با ISNULL یا COALESCE مدیریت کنید.
  4. پیش از تجمع، ردیف‌های غیرضروری را فیلتر کنید.
  5. برای گروه‌بندی‌های پرتکرار ایندکس ترکیبی مناسب طراحی کنید.
  6. خروجی را برای نمایش در HTML یا JSON بدون Escape مناسب مستقیماً استفاده نکنید.

سؤالات متداول

آیا STRING_AGG مقادیر NULL را نمایش می‌دهد؟

خیر. مقدار NULL حذف می‌شود. برای جایگزینی آن از ISNULL یا COALESCE استفاده کنید.

چگونه خروجی را مرتب کنیم؟

از WITHIN GROUP و ORDER BY استفاده کنید. ORDER BY نهایی SELECT ترتیب ردیف‌ها را تعیین می‌کند، نه ترتیب اجزای داخل رشته را.

چگونه مقدارهای تکراری را حذف کنیم؟

ابتدا در یک زیرکوئری SELECT DISTINCT اجرا کنید و سپس نتیجه را به STRING_AGG بدهید.

سؤالات رایج مصاحبه

  • تفاوت STRING_AGG با CONCAT چیست؟ CONCAT ستون‌ها یا عبارت‌های یک ردیف را ترکیب می‌کند، اما STRING_AGG چند ردیف را تجمیع می‌کند.
  • چرا WITHIN GROUP مهم است؟ چون ترتیب اجزای رشته را به صورت صریح مشخص می‌کند.
  • چرا تبدیل به nvarchar(max) مفید است؟ برای کاهش خطر محدودیت طول خروجی در مجموعه‌های بزرگ.

چک‌لیست نهایی

  • نوع داده یونیکد انتخاب شده است.
  • ترتیب خروجی مشخص شده است.
  • NULL مدیریت شده است.
  • طول احتمالی خروجی بررسی شده است.
  • فیلتر و ایندکس مناسب وجود دارد.

جمع‌بندی

STRING_AGG روش استاندارد و خوانای SQL Server برای تبدیل چند مقدار متنی به یک رشته است. استفاده درست از GROUP BY، WITHIN GROUP، nvarchar(max) و مدیریت NULL باعث می‌شود این تابع در گزارش‌گیری، تولید فهرست برچسب‌ها و نمایش داده‌های گروه‌بندی‌شده قابل اعتماد و سریع باشد.

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

حرف 500 حداکثر