OLAP Cube Calculation for Last Year Comparison on Week Day - MDX - mdx

I want to compare actual sales values with sales values of last year. The difficulty in this comparison is the compliance of the week days and thereby of the leap-year.
Example on day level:
2016-02-04 (thursday): actual sales: 580,- last year sales: 1.008,-
comparison with
2015-02-05 (thursday): actual sales: 1.008,-
So i want to compare the same week days in the month and not only the same dates.
Example on month level:
2016: (leap-year)
01.02.2016 - 29.02.2019 (february 2016) actual Sales: 19.300,- : last year Sales value: 19.000,-
comparison with
2015: (no leap year)
02.02.2015 - 02.03.2015 (february 2015 on week day logic) actual sales value: 19.000,-
I want not only compare February 2016 with february 2015 rather exactly the week day sales values summed.
I tried to write this calculation with an date calculation dimension and it works but only on the day level. Name of the calculation dimension: Date Calculations Week Day name of the member: ComparisonWD
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= ( [Date Calculations Week Day].[ComparisonWD].DefaultMember,
ParallelPeriod( [Date].[Year - Quarter - Month - Date].[Date],
364,
[Date].[Year - Quarter - Month - Date].CurrentMember ) );
END SCOPE;
Result 2015:
Result 2016:
It works on day level, but as you seen not on the month and not onthe year level.
How can I achieve this?

I got the solution:
Cube Calculation Code for this problem:
// ------------------------------------------------------------------------
//
// Comparison Week Day - Date.Calendar
//
// ------------------------------------------------------------------------
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
///////////////////////////////////////////////////////////////////////////////////////
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= SUM({ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date]).item(0)) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date]).item((Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date])).Count - 1))}, [Date Calculations Week Day].[ComparisonWD].DefaultMember );
END SCOPE;
SCOPE ([Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year]);
THIS = IIF( IsEmpty( [Date Calculations Week Day].[ComparisonWD].DefaultMember )
OR IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Previous Year] ),
NULL,
[Date Calculations Week Day].[ComparisonWD].DefaultMember
- [Date Calculations Week Day].[ComparisonWD].[Previous Year] );
NON_EMPTY_BEHAVIOR(THIS) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
FORE_COLOR(THIS) = IIF( [Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year] < 0, 255, 0); // 255 = RED
END SCOPE;
SCOPE ([Date Calculations Week Day].[ComparisonWD].[Diff. % Over Previous Year]);
THIS = IIF( IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year] )
OR IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Previous Year] ),
NULL,
[Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year]
/ [Date Calculations Week Day].[ComparisonWD].[Previous Year] );
NON_EMPTY_BEHAVIOR(THIS) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
FORMAT_STRING(THIS) = 'Percent';
FORE_COLOR(THIS) = IIF( [Date Calculations Week Day].[ComparisonWD].[Diff. % Over Previous Year] < 0, 255, 0); // 255 = RED
END SCOPE;
///////////////
// Tuple (All years, All Months) is the default number (keeps compatibility with OWC11)
( [Date].[Year].[All], [Date].[MonthYear].[All],
Except( [Date Calculations Week Day].[ComparisonWD].[ComparisonWD].MEMBERS, [Date Calculations Week Day].[ComparisonWD].DefaultMember ) ) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
Now with summed values on every level:
With this Date Calculations Week Day Dimension you can show for every Measure the Prev Year Values on Week day logic.

Not exactly answering the question but in the following context PARALLELPERIOD seems quite generic:
1.
At the Month level:
WITH
MEMBER [Measures].[PY Internet Sales Amount] AS
(
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[Date].[Calendar].CurrentMember
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[PY Internet Sales Amount]
} ON 0
,{
//[Date].[Calendar].[Date].&[20130101]:[Date].[Calendar].[Date].&[20130601]
[Date].[Calendar].[Month].[January 2012]:[Date].[Calendar].[Month].[December 2013]
} ON 1
FROM [Adventure Works];
Gives this:
2.
Changing to the Date level but leaving the PARALLELPERIOD calculation the same:
WITH
MEMBER [Measures].[PY Internet Sales Amount] AS
(
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[Date].[Calendar].CurrentMember
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[PY Internet Sales Amount]
} ON 0
,{
[Date].[Calendar].[Date].&[20130101]:[Date].[Calendar].[Date].&[20130601]
//[Date].[Calendar].[Month].[January 2012]:[Date].[Calendar].[Month].[December 2013]
} ON 1
FROM [Adventure Works];
Gives these results (no NULLS):

Just tried to imitate the problem as a mdx query in ssms and it works. How can i apply on my cube calculation:
with
set [DateRange] as ( { ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date],
364,
Descendants( [Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date]).item(0)
) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date],
364,
Descendants( [Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date]).item((Descendants(
[Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date])).Count - 1))})
Select {
[Measures].[Turnover]
} on Columns,
non empty
(
[DateRange]
) on Rows
from [Sales Cube]
Following result:
Turnover Net
03.01.2012 642
04.01.2012 665
05.01.2012 633
06.01.2012 730
07.01.2012 761
08.01.2012 531
09.01.2012 422
10.01.2012 488
11.01.2012 518
.
.
.
23.12.2012 618
24.12.2012 174
25.12.2012 137
26.12.2012 536
27.12.2012 981
28.12.2012 1.052
29.12.2012 1.006
30.12.2012 847
31.12.2012 695
01.01.2013 572
So you see, the date range is correct 2012-01-03 - 2013-01-01
In the query i take the date and descendant it to the lowest level (day) and then generate a date range. First date of range - 364 days and the last date of range -364 days to get the correct date range. Unfortunately i doesn't works in the cube calculation:
// ------------------------------------------------------------------------
//
// Comparison Week Day - Date.Calendar
//
// ------------------------------------------------------------------------
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
///////////////////////////////////////////////////////////////////////////////////////
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= SUM( [Date Calculations Week Day].[ComparisonWD].DefaultMember,
{ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date]).item(0)) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date]).item((Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date])).Count - 1))} );
END SCOPE;

Related

Group by start and end of the week date

I have the below promotion dates:
Group: Ambient
Start Date: 03/11/2020 End Date: 09/11/2020
Start Date: 10/11/2020 End Date: 16/11/2020
Group: Chilled
Start Date: 04/11/2020 End Date: 10/11/2020
Start Date: 11/11/2020 End Date: 17/11/2020
etc
My data consists of the below columns:
Dates (Daily), Group (Ambient/Chilled), Net Sales, Volume Sold
I want to group the data like the below:
Weekly Date, Group, Net Sales, Volume Sold
The Weekly date I want the week to start from Tuesday and ending on Monday based on the type of group it is. If the product is chilled I want the week to start from Wednesday and end on Tuesday. I want to do this and include a historical view to compare previous weeks to promotional weeks Example
Week Date Group Net Sales Volume
Row 1 - 27/10/2020 Ambient £900 30
Row 2 - 03/11/2020 Ambient £1000 50
Row 3 - 04/11/2020 Chilled £2000 40
Row 4 - 11/11/2020 Chilled £1000 30
What is the SQL query for changing the week dates?
There might be other ways to do this, but I would it first creating some functions that return me the DOW (Day Of Week) as I wanted (for Tuesday 0, ... Monday 6) and then another function FDOW (First Day Of Week) that use DOW. ie:
-- Tuesday = 0...Monday = 6
CREATE FUNCTION [dbo].[DOW]
(
#date DATETIME
)
RETURNS INT
AS
BEGIN
-- Add the T-SQL statements to compute the return value here
RETURN (##DATEFIRST + DATEPART(dw, #date) - 1 - 2) % 7;
END;
CREATE FUNCTION [dbo].[FDOW]
(
#date DATETIME
)
RETURNS DATETIME
AS
BEGIN
RETURN DATEADD(d, -dbo.DOW(#date), CAST(#date AS DATE));
END;
Having such functions it is easy to group on "WeekStart" which is our FDOW function:
Select dbo.FDOW(Dates) as WeekOf, [Group],
sum([Net Sales]) [Net Sales],
sum([Volume Sold]) [Volume]
from myTable
group by dbo.FDOW(Dates) as WeekOf, [Group];

Bigquery YTD WORKDAYS calculation

I use the below calc to calculate workdays in a month.
i.e for calendar date = 28-05-2021 , i get 23 days ( monday to friday)
(select count(*) from unnest(generate_date_array(date_trunc(CALENDAR_DATE, month), last_day(CALENDAR_DATE, month ))) day
where not extract(dayofweek from day) in (1, 7)) as Workdays_Month,
I would like to calculate YTD Workdays based on the Calendar Date
i.e
if calendar date = 28-05-2021 then YTD workdays would be sum of workdays in months ( Jul 20 to May 21) financial year.
Assuming your financial year starts in July - you can use below
select count(*)
from unnest([struct(extract(year from current_date) as year, extract(month from current_date) as month)]),
unnest(generate_date_array(if(month < 7, date(year - 1, 7, 1), date(year, 7, 1)), last_day(date(year, month, 1)))) day
where not extract(dayofweek from day) in (1, 7)

How to calculate the number of months and days between two dates, without returning negative values in SQL Server

I have this SQL block working in most situations but am returning a negative "day" value when the the month/day of the end date is > than the month/day of the start date. Not quite sure how to prevent negative day results from happening other than wrapping this in a case when to catch the exceptions when end month/day is > start month/day.
For example, if the start date is 2017 - 06 -05 and the end date is 2019 - 06 - 04, the output is "24 months and -1 days".
CONVERT ( VARCHAR ( MAX ),
DATEDIFF ( month , [Participant - Birthday] , [Event - Event Date] ) )
+ ' months and ' +
CONVERT ( VARCHAR ( MAX ) ,
DATEDIFF ( day , DATEADD ( month , DATEDIFF ( month , [Participant - Birthday] , [Event - Event Date] ) , [Participant - Birthday] ) , [Event - Event Date] ) )
+ ' days'
Expected out put using the above start and end date should be "23 months and 30 days".
Here is an alternative way of expressing the logic:
select s, e, v.num_months, datediff(day, dateadd(month, num_months, s), e)
from (values (convert(date, '2017-06-05'), convert(date, '2019-06-04')),
(convert(date, '2017-06-05'), convert(date, '2019-06-05')),
(convert(date, '2017-06-05'), convert(date, '2019-06-06'))
) t(s, e) cross apply
(values (case when day(s) <= day(e) then datediff(month, s, e) else datediff(month, s, e) - 1 end)) v(num_months);
This calculates the number of months difference -- up to or before the end date. It then calculates the day difference between the end date and the start date plus that number of months.

Syntax error to get the 6th Business day after 25th of the month plus 5 business days

Im working on a report that needs to show the exact date to determine who incurred late submission of charges. I added 3 queries and the last one to find the business day after the 25th of the month is giving me "An error occurred while performing operation 'sqlPrepareWithOptions' status = '239'
Can you help me please? The data item is 5 BUSINESS DAYS AFTER 25 and here's the query below:
CASE WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 5 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 6 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 7 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 5 ) ) BETWEEN 6 AND 7
THEN '0'
ELSE '0'
END
These are the 2 other queries that are working just fine:
LAST DAY OF LAST MONTH
_add_days (_first_of_month (CURRENT_DATE), -1)
FIND 25TH DAY OF MONTH
CASE
WHEN EXTRACT( DAY , _add_days([LAST DAY OF LAST MONTH] , - 2) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 2)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 3) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 3)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 4) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 4)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 5) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 5)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 6) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 6)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 7) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 7)
ELSE CURRENT_DATE
END

is it possible to Sum values grouped by month?

I have an SQL Server table structured as follows :
Table name : calendar.
Columns :
Calendar Date (smalldatetime)
Working Day (bit)
Calendar date has all dates, structured in the format yyyy-mm-dd.
Working day means that I have work if it is a 1, and if it is a weekend or a holiday it is marked as a 0.
What I want to retrieve :
Month No Working Days Year
------------------------------------
January 22 2011
February 20 2011
March 22 2011
...
December 10 2011
January 15 2012
All of the information is there, but I am just not sure how to write a query like this, but I assume it would be structured something similar to this with some fancy datetime functions thrown in. Does
SELECT Sum(Working Day)
GROUP BY (Not a clue)
Presumably you are interested in finding the working days in each month in each year and report which month the number of days is for. This will give you that:
SELECT YEAR([Calendar Date]) As [YEAR],
Month([Calendar Date]) As [Month],
SUM([Working Day] As [Working Days]
FROM [Calendar]
GROUP BY YEAR([Calendar Date]),
Month([Calendar Date])
Your query should look something like this:
SELECT Sum(Working Day)
WHERE Working Day = 1
GROUP BY MONTH(calenderDate)
This will group by month as you asked.
For more datetime functions your could check out this link
Something like this should work:
SELECT DATENAME(month, [Calendar Date]) 'Month',
COUNT(1) 'No Working Days',
YEAR([Calendar Date]) 'Year'
FROM YourTable
WHERE [Working Day] = 1
GROUP BY DATENAME(month, [Calendar Date]), YEAR([Calendar Date])
Depending your data and your desired results, if a month doesn't have any working days, this query won't return any results for that month. Instead, you could use something like this with CASE removing the WHERE criteria:
SELECT DATENAME(month, [Calendar Date]) 'Month',
COUNT(CASE WHEN [Working Day] = 1 THEN 1 END) 'No Working Days',
YEAR([Calendar Date]) 'Year'
FROM YourTable
GROUP BY DATENAME(month, [Calendar Date]), YEAR([Calendar Date])
You may not need the case statement at all -- depends on whether your table allows NULL for your bit field. If it doesn't allow NULLs, you can just use SUM([Working Day]) as it will sum 0s and 1s.
SQL Fiddle Demos
Try this one… it’s pretty much the same as most answers above with the addition of order by
SELECT YEAR(calendar_date) As [Year],
MONTH(calendar_date) As [Month],
SUM(working_day) As Working_Days
FROM [calendar]
GROUP BY YEAR(calendar_date) MONTH(calendar_date])
ORDER BY [Year], [Month]