تفاوتهای بین DATEADD و PARALLELPERIOD در DAX
در DAX چندین تابع مرتبط با هوش زمانی (Time Intelligence) وجود دارد که در واقع نوعی (syntax sugar) محسوب میشوند؛ یعنی فقط نوشتن تابعهای پایه را با پارامترهای بیشتر، سادهتر میکنند. استفاده از این تابعهای سادهتر بسیار راحت و کاربردی است، اما درک اینکه در پشتصحنه چه اتفاقی میافتد، ایده خوبی است تا بتوانید کنترل بهتری بر رفتار معیارهایی (measures) که مینویسید داشته باشید.
معرفی DATEADD و PARALLELPERIOD
بسیاری از توابع هوش زمانی در DAX که بازهای از تاریخها را «جابهجا» میکنند (shift)، بر پایهی دو تابع طراحی شدهاند: DATEADD
و PARALLELPERIOD
. در نگاه اول، این دو تابع مشابه به نظر میرسند، چرا که اگر یک سال انتخاب شده باشد، هر دوی این توابع تاریخهای سال قبل را بازمیگردانند.

این دو معیار (Measure) برای هر سال مقدار یکسانی را بازمیگردانند.

با این حال، به محض اینکه به سطح ماه وارد شویم (drill down کنیم)، میتوانیم تفاوتها را مشاهده کنیم.

سطح ماه اعداد متفاوتی را نشان میدهد: برای DATEADD
، مقدار مربوط به همان ماه در سال قبل را دریافت میکنیم، در حالی که برای PARALLELPERIOD
، همواره مجموع کل سال گذشته بازگردانده میشود، بدون توجه به اینکه کدام ماه انتخاب شده است.
توضیح دربارهی مقدار کل (Total): این مقدار برای DATEADD
و PARALLELPERIOD
یکسان است، زیرا تابع کل سالها به جز آخرین سال موجود در جدول تاریخ را بازمیگرداند. سطری که مربوط به جمع کل است، فاقد زمینهی فیلتر (filter context) است؛ یعنی کل محتوای جدول تاریخ (از ۲۰۱۷ تا ۲۰۲۰) به توابع هوش زمانی منتقل میشود، که در نتیجه بازهی سالهای ۲۰۱۷ تا ۲۰۱۹ را بازمیگردانند (چرا که سال ۲۰۱۶ در جدول تاریخ وجود ندارد).

بنابراین، به نظر میرسد که DATEADD
و PARALLELPERIOD
زمانی رفتار مشابهی دارند که از یک سطح یکسان برای آرگومان بازه (interval) استفاده کنیم (مثلاً سال در مثالها)، و زمانی رفتار متفاوتی از خود نشان میدهند که سطحی جزئیتر از سطح تعیینشده در آرگومان بازه در نظر گرفته شود، مانند ماه.
در واقع، چند جزئیات دیگر نیز وجود دارد که دانستن آنها ارزشمند است.
درک تابع DATEADD
الگوریتمی که در DATEADD
پیادهسازی شده است، ماههای تقویمیای را که در آرگومان اول مشخص شدهاند، تحلیل میکند.
اگر بازه (interval) برابر با
DAY
باشد، هر مقدار در ستونDate[Date]
به تعداد بازههای مشخصشده جابهجا میشود. اگر روز مورد نظر در ماه جدید وجود نداشته باشد، آخرین روز آن ماه بازگردانده میشود (مثلاً اگر 31ام انتخاب شود و به ماهی منتقل شویم که 31 روز ندارد، روز 30ام یا 28ام بازمیگردد).اگر بازه برابر با
MONTH
،QUARTER
یاYEAR
باشد، آنگاه برای هر ماه:اگر تمام روزهای آن ماه انتخاب شده باشند، کل ماه به اندازه تعداد بازههای مشخصشده جابهجا میشود.
اگر همهی روزهای ماه انتخاب نشده باشند، آنگاه هر روز به صورت جداگانه به تعداد بازههای مشخصشده جابهجا میشود.
یادت باشد که در مورد توابع هوش زمانی در DAX، وقتی میگوییم «کل یک ماه انتخاب شده»، یعنی تمام مقادیر مربوط به آن ماه در جدول تاریخ (Date table) در context فیلتر قابل مشاهده هستند. این الگوریتم لازم است تا مثلاً در صورتی که فوریه (که فقط 28 یا 29 روز دارد) انتخاب شده باشد، همچنان 31 روز ژانویه را بازگرداند.
در واقع تنها ستونی که توسط توابع هوش زمانی استفاده میشود، ستون Date[Date]
است؛ سایر ستونهای جدول تاریخ برای این توابع ناشناخته هستند.
برای مثال، کوئری زیر روزهای ماه فوریه را یک روز به عقب جابهجا میکند:

نتیجه همچنان شامل ۲۸ روز است، از تاریخ ۳۱ ژانویه ۲۰۱۹ تا ۲۷ فوریه ۲۰۱۹. اگر جابهجایی به اندازه یک ماه انجام شود، نتیجه شامل تعداد متفاوتی از روزها خواهد بود:

نتیجه حالا شامل ۳۱ روز است، که تعداد روزهای ماه ژانویه است: DATEADD
۲۸ روز دریافت کرده و ۳۱ روز بازگردانده است. اگر یک ماه کامل و چند روز از ماه دیگری را شامل کنیم، آنگاه DATEADD
دو قانون متفاوت را بسته به ماه اعمال میکند. برای مثال، اگر بازه زمانی از ۱ فوریه تا ۱۰ مارس را ارائه دهیم، ورودی شامل ۳۸ روز خواهد بود:

نتیجه ۴۱ روز است: ۳۱ روز از ژانویه ۲۰۱۹ به علاوه ۱۰ روز اول از فوریه ۲۰۱۹.DATEADD
همچنین الگوریتم مبتنی بر ماه را زمانی که بازه برابر با QUARTER
یا YEAR
باشد، اعمال میکند. بدین ترتیب، DATEADD
به تعداد متفاوت روزها در ماهها و سهماههها احترام میگذارد، مانند اضافه شدن یک روز در سالهای کبیسه.
درک تابع PARALLELPERIOD
الگوریتم پیادهسازیشده در PARALLELPERIOD
بر اساس بازهای است که در آرگومان سوم مشخص شده است. برای هر بازهای که حداقل یک مقدار در ستون Date[Date]
وجود داشته باشد، این تابع کل بازه را به تعداد بازههای مشخصشده جابهجا میکند. PARALLELPERIOD
میتواند از YEAR
، QUARTER
و MONTH
استفاده کند و از بازه DAY
پشتیبانی نمیکند.
برای مثال، میتوانیم بازهای از تاریخها بین ۱ فوریه و ۱۰ مارس را ارائه دهیم، یا فقط یک روز از فوریه و یک روز از مارس را مشخص کنیم: نتیجه برای YEAR
، QUARTER
و MONTH
یکسان خواهد بود. با تعیین مقدار ۰ در آرگومان دوم، نتیجه بازه فعلی را برای تاریخهای مشخصشده در آرگومان اول باز میگرداند:

با استفاده از یک عدد منفی، PARALLELPERIOD
بازهها را به عقب در زمان باز میگرداند. برای مثال، با استفاده از -1
، PARALLELPERIOD
بازههای قبلی را برای هر یک از بازههایی که در ورودی شناسایی شدهاند، بازمیگرداند:

ما در ورودی همان بازه یا مجموعهای از تاریخها را در فوریه و مارس برای مثالی که دوره جاری را بازمیگرداند، استفاده کردیم. در این حالت، نتایج به شرح زیر است:
کل سال ۲۰۱۸ برای
YEAR
؛سهماهه چهارم ۲۰۱۸ برای
QUARTER
(تاریخهای ورودی ما در سهماهه اول ۲۰۱۹ هستند)؛ژانویه و فوریه ۲۰۱۹ برای
MONTH
(تاریخهای ورودی ما در فوریه و مارس ۲۰۱۹ هستند).
توابعی که از DATEADD
یا PARALLELPERIOD
استفاده میکنند
تابع SAMEPERIODLASTYEAR
تنها تابعی است که بهطور داخلی از DATEADD
استفاده میکند. در واقع، زمانی که شما بنویسید:

ما این را (syntax sugar) مینامیم: SAMEPERIODLASTYEAR
فقط یک روش دیگر برای فراخوانی DATEADD
است بدون اینکه آرگومانهای دوم و سوم را مشخص کنیم، که همیشه برابر با -1
و YEAR
هستند. این توابع نوشتن کد را سادهتر میکنند و آن را قابلخواندنتر میسازند – با این حال، هیچ تفاوتی بین استفاده از این نحوه نوشتار و نحوه دیگر وجود ندارد.
هشت تابع دیگر نیز وجود دارند که “شکر نحوی” برای DATEADD
یا PARALLELPERIOD
هستند، اما آنها همیشه یک بازه واحد بازمیگردانند، حتی اگر ورودی دارای بازههای متعدد باشد:
PREVIOUSDAY
: روز قبل از اولین روز تاریخهای انتخابشده را بازمیگرداند.PREVIOUSMONTH
: کل ماه قبل از اولین روز تاریخهای انتخابشده را بازمیگرداند.PREVIOUSQUARTER
: کل سهماهه قبل از اولین روز تاریخهای انتخابشده را بازمیگرداند.PREVIOUSYEAR
: کل سال قبل از اولین روز تاریخهای انتخابشده را بازمیگرداند.NEXTDAY
: روز بعد از آخرین روز تاریخهای انتخابشده را بازمیگرداند.NEXTMONTH
: کل ماه بعد از آخرین روز تاریخهای انتخابشده را بازمیگرداند.NEXTQUARTER
: کل سهماهه بعد از آخرین روز تاریخهای انتخابشده را بازمیگرداند.NEXTYEAR
: کل سال بعد از آخرین روز تاریخهای انتخابشده را بازمیگرداند.
در مثالهای آخر PARALLELPERIOD
، از نامهای متغیری مانند _PreviousMonth
، _PreviousQuarter
و _PreviousYear
استفاده کردیم. با این حال، توابع DAX مربوطه رفتار کمی متفاوتی دارند: آنها فقط از اولین تاریخ انتخابشده استفاده میکنند، بنابراین نتیجه بیش از یک بازه (روز، ماه، سهماهه یا سال) نخواهد داشت. PREVIOUSMONTH
، PREVIOUSQUARTER
و PREVIOUSYEAR
بهطور داخلی از PARALLELPERIOD
با FIRSTDATE
استفاده میکنند، در حالی که PREVIOUSDAY
از DATEADD
با FIRSTDATE
استفاده میکند. توابعی که پیشوند NEXT
دارند، همان تکنیک را استفاده میکنند و بهجای FIRSTDATE
از LASTDATE
بهعنوان ورودی و یک عدد مثبت از بازهها استفاده میکنند.
کد زیر، برای هر تابع PREVIOUS*/NEXT*
، نحوه نوشتار مربوطه با استفاده از DATEADD/PARALLELPERIOD
را در خط بعدی نشان میدهد:
PREVIOUSYEAR (Selection)PARALLELPERIOD ( FIRSTDATE ( Selection ), -1, YEAR )
PREVIOUSQUARTER (Selection)PARALLELPERIOD ( FIRSTDATE ( Selection ), -1, QUARTER )
PREVIOUSMONTH (Selection)PARALLELPERIOD ( FIRSTDATE ( Selection ), -1, MONTH )
PREVIOUSDAY (Selection)DATEADD ( FIRSTDATE ( Selection ), -1, DAY )
NEXTYEAR (Selection)PARALLELPERIOD ( LASTDATE ( Selection ), 1, YEAR )
NEXTQUARTER (Selection)PARALLELPERIOD ( LASTDATE ( Selection ), 1, QUARTER )
NEXTMONTH (Selection)PARALLELPERIOD ( LASTDATE ( Selection ), 1, MONTH )
NEXTDAY (Selection)DATEADD ( LASTDATE ( Selection ), 1, DAY )
مثال زیر نشان میدهد که توابع PREVIOUS*
بر اساس اولین تاریخ در تاریخهای ورودی عمل میکنند، در حالی که توابع NEXT*
بر اساس آخرین تاریخ در تاریخهای ورودی عمل میکنند:


تفاوت اصلی بین استفاده از توابع PREVIOUS*/NEXT*
به جای PARALLELPERIOD
در رفتار آنها زمانی است که چندین بازه انتخاب شده باشد. این تفاوت بهویژه در مجموعها قابل مشاهده است:PREVIOUSYEAR
همان رفتار PARALLELPERIOD
را زمانی که یک سال یا ماه واحد انتخاب میشود، نشان میدهد، اما وقتی که چندین سال در context فیلتر موجود باشد، مانند زمانی که مجموعها محاسبه میشوند، PREVIOUSYEAR
مقدار خالی (blank) برمیگرداند.

مقدار فروش PREVIOUSYEAR
در ردیف مجموع خالی (blank) برمیگرداند زیرا تلاش میکند تا سال ۲۰۱۶ را بازگرداند، سال قبل از اولین سال موجود در جدول تاریخ (۲۰۱۷). نتیجه خالی است زیرا هیچ تاریخی در جدول تاریخ قبل از سال ۲۰۱۷ وجود ندارد.
در مقابل، اندازهگیری Sales Amount -1 PARALLELPERIOD
مجموع کل سالهای جدول تاریخ به جز آخرین سال (۲۰۲۰) را باز میگرداند.

بنابراین، PARALLELPERIOD
توسط توابع هوش زمانی PREVIOUS*/NEXT*
به همراه توابع FIRSTDATE
و LASTDATE
استفاده میشود تا انتخابها را به یک بازه واحد کاهش دهد – که این تفاوت رفتارهایی را که در مثالهای آخر مشاهده کردیم توضیح میدهد.
توابع هوش زمانی در DAX اغلب یک میانبر برای فراخوانی یک نحو طولانیتر هستند. DATEADD
و PARALLELPERIOD
نیز از این قاعده مستثنی نیستند: این توابع زمانی که برای مقایسه یکی از بازههای مشخصشده در آرگومان استفاده میشوند مشابه هستند، اما زمانی که در دقتهای مختلف استفاده میشوند و چندین بازه درگیر هستند، تفاوتهایی دارند. این رفتار بر توابع مشتقشده از آنها تأثیر میگذارد: توابعی مانند SAMEPERIODLASTYEAR
، FIRSTDAY
، FIRSTMONTH
، FIRSTQUARTER
، FIRSTYEAR
، LASTDAY
، LASTMONTH
، LASTQUARTER
و LASTYEAR
بهطور داخلی از DATEADD
، PARALLELPERIOD
، FIRSTDATE
و LASTDATE
استفاده میکنند. اطمینان حاصل کنید که با توجه به نحو گسترشیافته، رفتار اندازهگیریهای خود را کنترل کرده و قبل از انتخاب تابع هوش زمانی، از آن آگاهی داشته باشید.
دیدگاهتان را بنویسید