بهترین شیوه برای استفاده از SUMMARIZE و ADDCOLUMNS
این مقاله بهترین شیوهها برای استفاده از توابع ADDCOLUMNS و SUMMARIZE را ارائه میدهد؛ دو تابعی که میتوان آنها را در هر عبارت DAX، از جمله معیارها (measures)، به کار برد.
تقریباً تمام کسانی که از DAX استفاده میکنند، با زبان کوئرینویسی SQL آشنایی دارند. به دلیل شباهتهای بین مدلسازی داده در قالب جدولی (Tabular) و مدلسازی رابطهای، انتظار میرود که بتوان همان عملیات موجود در SQL را نیز در اینجا انجام داد. با این حال، در پیادهسازی فعلی، DAX اجازه انجام تمام عملیات قابل انجام در SQL را نمیدهد. این مقاله چگونگی استفاده از توابع ADDCOLUMNS و SUMMARIZE را توضیح میدهد، که میتوان آنها را در هر عبارت DAX، از جمله در معیارها، استفاده کرد.
برای کوئریهای DAX، پیشنهاد میشود که از تابع SUMMARIZECOLUMNS استفاده کنید، و برای شروع میتوانید مقاله “معرفی SUMMARIZECOLUMNS” را بخوانید. همچنین برای درک بهتر عملکرد داخلی تابع SUMMARIZE میتوانید مقاله “تمام اسرار SUMMARIZE” را مطالعه کنید.
ستونهای افزودهشده (Extension Columns)
ستونهای افزودهشده، ستونهایی هستند که به جداول موجود اضافه میشوند. شما میتوانید این نوع ستونها را با استفاده از هر دو تابع ADDCOLUMNS و SUMMARIZE به دست آورید. برای مثال، کوئری زیر ستونی با عنوان “Open Year” به ردیفهای بازگرداندهشده از جدول Store اضافه میکند.

همچنین میتوانید با استفاده از تابع SUMMARIZE یک ستون افزودهشده ایجاد کنید. برای مثال، میتوانید با استفاده از کوئری زیر تعداد فروشگاهها را برای هر کشور بشمارید (لطفاً توجه داشته باشید که این کوئری بهترین شیوه نیست – در ادامه مقاله دلیل آن را خواهید دید).

در عمل، یک ستون افزودهشده در واقع یک ستون محاسباتی است که درون کوئری ایجاد میشود.
پرتاب کوئری (Query Projection)
در یک عبارت SELECT در SQL، میتوانید ستونی که در نتیجه نمایش داده میشود را انتخاب کنید، در حالی که در DAX فقط میتوانید با ایجاد ستونهای افزودهشده، ستونهایی به جدول اضافه کنید. تنها راهحل موجود برای این موضوع، استفاده از تابع SUMMARIZE است تا جدول را بر اساس ستونهایی که میخواهید در خروجی داشته باشید، گروهبندی کنید. تا زمانی که نیازی به مشاهده ردیفهای تکراری در نتیجه نداشته باشید، این راهحل مشکل خاصی ایجاد نمیکند.
برای مثال، اگر بخواهید فقط فهرست نام فروشگاهها و تاریخ بازگشایی متناظر آنها را به دست آورید، میتوانید کوئری زیر را بنویسید.

هر زمان که بتوانید یک ستون افزودهشده را با استفاده از هر دو تابع ADDCOLUMNS و SUMMARIZE ایجاد کنید، همیشه باید به دلایل مربوط به عملکرد (performance) تابع ADDCOLUMNS را ترجیح دهید.
برای مثال، میتوانید سال بازگشایی را با استفاده از یکی از دو تکنیک زیر اضافه کنید. ابتدا، میتوانید فقط از SUMMARIZE استفاده کنید.

میتوانید از تابع ADDCOLUMNS استفاده کنید و ستون Year Production را به نتیجه حاصل از SUMMARIZE اضافه نمایید.

هر دو کوئری نتیجه یکسانی تولید میکنند.
با این حال، همیشه باید نسخهای را که از تابع ADDCOLUMNS استفاده میکند، ترجیح دهید. قاعده کلی این است که هرگز نباید از SUMMARIZE برای افزودن ستونهای افزودهشده استفاده کنید، مگر اینکه به دلیل دستکم یکی از شرایط زیر مجبور باشید:
میخواهید از تابع ROLLUP روی یک یا چند ستون گروهبندی استفاده کنید تا زیرجمعها (subtotals) را بهدست آورید.
از عبارات جدولی غیرساده (non-trivial table expressions) در ستون افزودهشده استفاده میکنید، همانطور که در بخش «Context فیلتر در SUMMARIZE و ADDCOLUMNS» در ادامه این مقاله خواهید دید.
بهترین شیوه این است که، هر زمان ممکن باشد، به جای نوشتن:

تابع CALCULATE که در قالب بهترین شیوه در بالا مشاهده کردید، همیشه الزامی نیست، اما هر زمان که <expression>
شامل یک تابع تجمیعی (aggregation function) باشد، به آن نیاز دارید. دلیل این موضوع آن است که تابع ADDCOLUMNS در یک row context اجرا میشود که بهطور خودکار به filter context منتقل نمیشود. در حالی که همان <expression>
درون تابع SUMMARIZE در یک filter context اجرا میشود که با مقادیر ستونهای گروهبندیشده مطابقت دارد.
در مثالهای قبلی، از یک عبارت اسکالر (scalar) بر روی ستونی استفاده شده بود که در خروجی SUMMARIZE گنجانده شده بود، بنابراین ارجاع به مقدار ستون درون row context معتبر بود. حالا، کوئری زیر را در نظر بگیرید که پیشتر در ابتدای این مقاله دیدهاید.

اگر این کوئری را بازنویسی کنید و صرفاً ستون افزودهشدهی Stores را از داخل SUMMARIZE به تابع ADDCOLUMNS منتقل کنید، به کوئریای میرسید که نتیجه نادرستی تولید میکند.
دلیل آن این است که این کوئری بهجای اینکه تعداد فروشگاهها را برای هر کشور بازگرداند، تعداد کل ردیفهای جدول Store را برای هر ردیف از نتیجه نشان میدهد.

برای اینکه به نتیجه مورد نظر برسید، باید عبارت مربوط به ستون افزودهشدهی Stores را درون یک عبارت CALCULATE قرار دهید.
به این ترتیب، row context مربوط به Store[Country]
به filter context تبدیل میشود و تابع COUNTROWS
فقط فروشگاههایی را در نظر میگیرد که به کشور مربوط به ردیف جاری تعلق دارند.

بنابراین، بهعنوان یک قاعده کلی، هرگاه که یک ستون افزودهشده را از داخل SUMMARIZE به عبارت ADDCOLUMNS منتقل میکنید، باید هر عبارت مربوط به ستون افزودهشده را درون یک تابع CALCULATE قرار دهید. فقط به نکات هشداردهنده در بخش بعدی توجه داشته باشید!
Context فیلتر در SUMMARIZE و ADDCOLUMNS
با توصیف الگوی ایجاد ستونهای افزودهشده با استفاده از ADDCOLUMNS به جای SUMMARIZE، اشاره کردیم که در برخی شرایط نمیتوان این جایگزینی را انجام داد – زیرا نتیجه نادرست خواهد بود. برای مثال، زمانی که فیلترهایی بر روی ستونهایی که در گروهبندی قرار ندارند اعمال میکنید و سپس عبارت ستون افزودهشده را با استفاده از دادههای آمده از جداول مرتبط محاسبه میکنید، filter context بین SUMMARIZE و ADDCOLUMNS متفاوت خواهد بود.
کوئری زیر، بر اساس دستهبندی محصول و کشور مشتری، سود حاصل از دو مشتری برتر برای هر محصول را باز میگرداند. بنابراین، یک دستهبندی ممکن است چندین مشتری داشته باشد، اما نه بیشتر از دو مشتری برای هر محصول:

در این حالت، استفاده از الگوی انتقال ستونهای افزودهشده از داخل SUMMARIZE به ADDCOLUMNS کار نمیکند، زیرا تابع GENERATE که بهعنوان پارامتر SUMMARIZE استفاده شده، فقط تعداد کمی از محصولات و مشتریان را بازمیگرداند – در حالی که SUMMARIZE تنها فروشهای مرتبط با این ترکیبهای محصول و مشتری را در نظر میگیرد.
کوئری زیر و نتیجه آن را در نظر بگیرید:

همانطور که مشاهده میکنید، نتایج متفاوت هستند، زیرا Margin بیشتر از نتیجه اولیه است. دلیل این موضوع این است که این کوئری اندازهگیری Margin را در یک filter context محاسبه میکند که فقط Product[Category] و Customer[Country] را فیلتر میکند، و فیلتر مشتریان برتر ۲ که در آرگومان جدول SUMMARIZE استفاده شده بود را نادیده میگیرد. در حالی که نتیجه GENERATE تمام ستونهای مربوط به Product و Customer را شامل میشود، اما فقط برای ۲ مشتری برتر از هر کشور. تنها این مشتریان در محاسبه Margin داخل SUMMARIZE در نظر گرفته شدند، زیرا SUMMARIZE فقط از مشتریانی که توسط TOPN فیلتر شده بودند، استفاده میکرد.
اگر SUMMARIZE را درون ADD COLUMNS قرار دهید، ستونهای افزودهشده ایجاد شده در ADD COLUMNS روی یک filter context که توسط Product[Category] و Customer[Country] تعریف شده، کار میکنند و فروشهای بیشتری را نسبت به آنچه که در ابتدا توسط کوئری اولیه استفاده میشد، در نظر میگیرند. بنابراین، برای تولید نتیجه معادل با استفاده از ADD COLUMNS، ضروری است که همان فیلتر حاصل از GENERATE را در ارزیابی اندازهگیری Margin بیاورید. ما میتوانیم این کار را با ذخیره کردن نتیجه GENERATE در متغیر ProductsCustomers که در SUMMARIZE ارجاع میدهیم، انجام دهیم و آن را بهعنوان یک آرگومان فیلتر به CALCULATE برای ارزیابی اندازهگیری Margin در ADD COLUMNS منتقل کنیم. استفاده از KEEPFILTERS برای حفظ نتیجه context transition و فیلتر کردن توسط Product[Category] و Customer[Country] در فیلتر ذخیرهشده در ProductsCustomers بسیار مهم است.
این هم معادل کوئری DAX با استفاده از ADD COLUMNS برای تولید ستون افزودهشده:

نتیجهگیری این است که ستونهای افزودهشده در یک عبارت SUMMARIZE نباید به ADD COLUMNS منتقل شوند اگر جدولی که در SUMMARIZE استفاده شده فیلترهای خاصی دارد و عبارت ستون افزودهشده از ستونهایی استفاده میکند که بخشی از خروجی نیستند. اگرچه میتوانید یک کوئری معادل ADD COLUMNS ایجاد کنید، نتیجه پیچیدهتر خواهد بود و هیچ منفعتی از نظر عملکرد در این بازسازی وجود ندارد. کوئری پیچیدهتر همان عملکرد (نه خیلی خوب) را دارد که کوئری SUMMARIZE دارد – هر دو کوئری در این بخش تقریباً ۱۰ ثانیه زمان نیاز دارند تا روی پایگاه داده نمونه Contoso اجرا شوند.
دیدگاهتان را بنویسید