SSAS Last Year MTD Calculation Irregular Calnedar - ssas

I have a sales calendar where the calendars for a month change year to year. The example is that September 2015 is defined as September 1 - September 30 but last year it ran from September 3 - September 30.
So when I want to compare this year MTD on 9/1/2015 should be compared to 9/3/2014. I have all the dates in the time dimension, like LAST MTD Start and LAST MTD End, and put them in a hierarchy, DATE with LAST MTD START and LAST MTD END, and tried ancestor functions, like
WITH
MEMBER [Measures].LMTD AS
SUM(
ANCESTOR(
[Time].[LYMD_START].CURRENTMEMBER
,1
)
,[Measures].[Volume]
)
SELECT
[Measures].LMTD on 0
FROM [myCUBE]
WHERE [Time].[DATE].&[2015-09-01T00:00:00];
But I only get back the current month's aggregated volume.

Assuming you have a dimension with date, sales month, and sales year, the following should work. If you filter to 2015-09-01 (which is the first day of the 9th sales month) the this will step back one sales year and then find the first day of the 9th sales month (2014-09-03):
ParallelPeriod(
[Date].[Sales Calendar].[Sales Year],
1,
[Date].[Sales Calendar].CurrentMember
)
Then you want to sum up the days in that sales month through 2014-09-03:
Sum(
PeriodsToDate(
[Date].[Sales Calendar].[Sales Month],
ParallelPeriod(
[Date].[Sales Calendar].[Sales Year],
1,
[Date].[Sales Calendar].CurrentMember
)
),
[Measures].[Volume]
)
So the hard work is in building the dimension with the right sales months. The MDX can just navigate that hierarchy.

Related

Remove Duplicates and show Total sales by year and month

i am trying to work with this query to produce a list of all 11 years and 12 months within the years with the sales data for each month. Any suggestions? this is my query so far.
SELECT
distinct(extract(year from date)) as year
, sum(sale_dollars) as year_sales
from `project-1-349215.Dataset.sales`
group by date
it just creates a long list of over 2000 results when i am expecting 132 max one for each month in the years.
You should change your group by statement if you have more results than you expected.
You can try:
group by YEAR(date), MONTH(date)
or
group by EXTRACT(YEAR_MONTH FROM date)
A Grouping function is for takes a subsection of the date in your case year and moth and collect all rows that fit, and sum it up,
So a sĀ“GROUp BY date makes no sense, what so ever as you don't want the sum of every day
So make this
SELECT
extract(year from date) as year
,extract(MONTH from date) as month
, sum(sale_dollars) as year_sales
from `project-1-349215.Dataset.sales`
group by 1,2
Or you can combine both year and month
SELECT
extract(YEAR_MONTH from date) as year
, sum(sale_dollars) as year_sales
from `project-1-349215.Dataset.sales`
group by 1

Pivot 12 Months dynamically backwards from current month

I have a table that looks like this:
CustName
Date
Hours
First
01/01/2021
12
Second
01/01/2021
10
Second
05/02/2021
1
Second
10/11/2021
14
I am trying to do a sum of hours per month per customer.
I figured out how to do this using a Pivot such as:
SELECT
CustName AS [Customer], ISNULL([January],0) AS [January], ISNULL([February],0) AS [February], ISNULL([March],0) AS [March]
FROM
(
SELECT
CustName,
DATENAME(MONTH, Date) AS [Month],
RegHrs
FROM TimeEntrySimpleList
) AS Src
PIVOT
(
SUM(Hours)
FOR [Month] IN ([January], [February], [March])
) AS Pvt
select* from TimeEntry
This works fine if I want to report say January - December in a static way, only ever showing the months I assign.
But what I want to do is have the last month column (March in my example), and show 12 months from the current backwards in the columns.
I'm guessing I would have to set the current month as a variable? And use it in the pivot .. but I'm not sure how / what to do. Use some sort of calc [month]*12 (reverse)?
Any tips would be appreciated!

Get quarter on quarter growth with SQL for current quarter

I'm trying to get the quarter on quarter revenue growth for only the current quarter from a dataset. I currently have a query that looks something like this
Select
x.Year,
x.quarter,
x.product,
x.company_id,
y.company,
SUM(x.revenue)
FROM
company_directory y
LEFT JOIN (
SELECT
DATEPART(YEAR, #date) year,
DATEPART(QUARTER, #date) quarter,
product,
SUM(revenue)
FROM sales
WHERE year => 2018 ) x
ON y.company_id = x.company_id
The data I get is in this format
Year Quarter Product company_id company revenue
2020 Q2 Banana 1092 companyX $100
What I'm trying to do is get quarter on quarter growth for revenue if it's reporting the current quarter. So for example, in the above data, because we're in Q2-2020, I want an extra column to say QoQ is x% which will compare Q2 vs Q1 revenue. If the row is reporting Q1-2020 or Q2-2019 QoQ will be empty because neither of those are the current quarter based on today's date.
Expected result
Year Quarter Product company_id company revenue QoQ
2020 Q2 Banana 1092 companyX $100 20%
2020 Q1 Pear 1002 companyX $23 NULL
I'm not entirely sure how to go about this, haven't had much luck searching. Any idea how I can implement?
You can use window functions.
select
s.yr,
s.qt,
s.product,
s.company_id,
cd.company,
s.revenue,
1.0 * (
s.revenue
- lag(s.revenue) over(partition by s.product, s.company_id order by s.yr, s.qt)
) / lag(s.revenue) over(partition by s.product, s.company_id order by s.yr, s.qt) as QoQ
from company_directory cd
inner join (
select
datepart(year, sales_date) yr,
datepart(quarter, sales_date) qt,
product,
company_id,
sum(revenue) revenue
from sales
where sales_date >= '2018-01-01'
group by
datepart(year, sales_date) year,
datepart(quarter, sales_date) quarter,
product,
company_id
) s on s.company_id = cd.company_id
Notes:
your code is not valid MySQL; I assume that you are running SQL Server instead of MySQL
the use of a variable in the subquery does not make sense - I assume that you have a column called sales_date in table sales that holds the sales date
your group by clauses are inconsistent with your select clauses - I assume that you want the quarter to quarter sales growth per company and per product
you might need to ajust the QoQ computation to your actual definition of the quarter to quarter growth
I don't see the point for a left join, so I used inner join instead
You need analytical window function LAG
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=40a7ba897df766f913ebd99e2f2a0f4e

Running Total for Current & Previous Year on weekly basis

This query provides Year to date numbers for both Price and Square Feet of the current year and the previous year to date. This is more like the Running Total of the current Year and the Previous year with respect to the weeks in this case from 1 through 7 and so on..... (week 7th of 2017 ended on 02/19/2017) of the current year and the previous year(week 7th of 2016 ended on 02/22/2016). The reason why I am using subqueries is because this is the only way I know to get around this situation. And of course if you think there is a shorter, viable alternative of executing this query, please advice.
Actual_Sale_Date holds data on all of the seven days of the week but we cut off on Sunday that is why 2/22/2016 (Sunday ending 7th week of 2016) and 2/19/2017 (Sunday ending 7th week of 2017).
I tried "Actual_Sale_Date" = date_trunc('week', now())::date - 1 this function only returns the previous week data ending on the passed Sunday. I took a look at interval since dateadd does not exist in postgresql but could not get my ways around with it.
My query:
select (money(Sum("Price") / COUNT("Price"))) as "Avg_Value YTD",
Round(Avg("Price"/"Sq_Ft"),+2) as "Avg_PPSF YTD",
(select
(money(Sum("Price") / COUNT("Price"))) from allsalesdata
where "Actual_Sale_Date" >= '01/01/2016' AND "Actual_Sale_Date" < '02/22/2016'
and "Work_ID" = 'SO') AS "Last Year at this time Avg_Value",
(select Round(Avg("Price"/"Sq_Ft"),+2)
from allsalesdata
where "Actual_Sale_Date" >= '01/01/2016' AND "Actual_Sale_Date" < '02/22/2016'
and "Work_ID" = 'SO') AS "Last Year at this time Avg_PPSF"
from allsalesdata
where "Actual_Sale_Date" >= '01/01/2017' AND "Actual_Sale_Date" <'02/20/2017'
and "Work_ID" = 'SO'
Sample Data:
Price Sq_Ft Actual_Sale_Date Work_ID
45871 3583 01/15/2016 SO
55874 4457 02/05/2016 SO
88745 4788 02/20/2016 SO
58745 1459 01/10/2016 SO
88749 2145 01/25/2017 SO
74856 1478 01/25/2017 SO
74586 4587 01/31/2017 ABC
74745 1142 02/10/2017 SO
74589 2214 02/19/2017 SO
This should be what you need (assuming you have a recent version of PG):
SELECT DISTINCT wk AS "Week",
sum("Price")::money FILTER (WHERE yr = 2017) OVER w /
count("Price") FILTER (WHERE yr = 2017) OVER w AS "Avg_Value YTD",
sum("Price")::money FILTER (WHERE yr = 2017) OVER w /
sum("Sq_Ft") FILTER (WHERE yr = 2017) OVER w AS "Avg_PPSF YTD",
sum("Price")::money FILTER (WHERE yr = 2016) OVER w /
count("Price") FILTER (WHERE yr = 2016) OVER w AS "Last Year this time Avg_Value",
sum("Price")::money FILTER (WHERE yr = 2016) OVER w /
sum("Sq_Ft") FILTER (WHERE yr = 2016) OVER w AS "Last Year this time Avg_PPSF",
FROM (
SELECT extract(isoyear from "Actual_Sale_Date")::integer AS yr,
extract(week from "Actual_Sale_Date")::integer AS wk,
"Price", "Sq_Ft"
FROM allsalesdata
WHERE "Work_ID" = 'SO') sub
-- optional, show only completed weeks in this year:
WHERE wk <= extract(week from CURRENT_DATE)::integer - 1
WINDOW w AS (ORDER BY wk)
ORDER BY wk;
In the inner query the year and week of the sale date are extracted for every sale. The week starts on Monday, as per your requirement.
In the main query these rows are processed as a single partition frame, i.e. from the start of the partition (= first row) to the last peer of the current row. Since the window definition orders the rows by wk, all rows from the start (week = 1) to the current week are included in the summarization. This will give you the running total. The sum() and count() functions filter by the year in question and the DISTINCT clause ensures that you get only a single row per week.

MDX YTD Calculated Member for current and parallel period

Trying to build a calculated member using our date hierarchy for use in Tableau.
Hierarchy is as follows:
Fiscal Year
Fiscal Season
Fiscal Quarter
Fiscal Month
Fiscal Week
Date
To help our users with their analysis on dashboards, we're looking to build a Tableau set including the following members for them to toggle through:
Yesterday, Week to Date, Month to Date, Season to Date, and Year to Date.
We need to be able to show Sales $ and Sales $ LY(measure is defined as parallel period) together and be able to toggle through the different "to date" values. The this year portion is fine, but creating a calculated member that works appropriately for the LY measure too has been problematic. We need to be able to pivot between the periods for dashboards rather than create individual measures for each period TY and LY.
Here are the current definitions we have out there:
Yesterday: [DATE].[Time].defaultmember
WTD: [DATE].[Time].defaultmember.parent
MTD: [DATE].[Time].defaultmember.parent.parent
STD: [DATE].[Time].defaultmember.parent.parent.parent
YTD: [DATE].[Time].defaultmember.parent.parent.parent.parent
Any thoughts on how to modify these so that the LY measure reflects the same "to date" period rather than the full period last year?
Count the number of days completed this year and then use the Head function to get the same set of dates from the previous year - aggregate that set together.
Here is an illustration against the AdvWrks cube:
WITH
SET [DaysThisYear] AS
Descendants
(
[Date].[Calendar].[Calendar Year].&[2007]
,[Date].[Calendar].[Date]
)
MEMBER [Measures].[posOfCurrentDate] AS
Rank
(
[Date].[Calendar].CurrentMember
,Descendants
(
[Date].[Calendar].Parent.Parent.Parent.Parent
,[Date].[Calendar].[Date]
)
)
MEMBER [Measures].[prevEquivMTD] AS
Sum
(
Head
(
Descendants
(
[Date].[Calendar].Parent.Parent.Parent.Parent.PrevMember
,[Date].[Calendar].[Date]
)
,[Measures].[posOfCurrentDate]
)
,[Measures].[Internet Sales Amount]
)
MEMBER [Measures].[posCurrentYear] AS
[Date].[Calendar].Parent.Parent.Parent.Parent.Member_Caption
SELECT
{
[Measures].[posCurrentYear]
,[Measures].[posOfCurrentDate]
,[Measures].[Internet Sales Amount]
,[Measures].[prevEquivMTD]
} ON 0
,
[Date].[Calendar].[Date].&[20050111]
:
[Date].[Calendar].[Date].&[20080611] ON 1
FROM [Adventure Works];
This is the above as a single measure:
WITH
MEMBER [Measures].[Internet Sales Amount prevEquivMTD] AS
Sum
(
Head
(
Descendants
(
[Date].[Calendar].Parent.Parent.Parent.Parent.PrevMember //previous year
,[Date].[Calendar].[Date]
)
,Rank
(
[Date].[Calendar].CurrentMember
,Descendants
(
[Date].[Calendar].Parent.Parent.Parent.Parent //current year
,[Date].[Calendar].[Date]
)
)
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[Internet Sales Amount prevEquivMTD]
} ON 0
,
[Date].[Calendar].[Date].&[20050111]
:
[Date].[Calendar].[Date].&[20080611] ON 1
FROM [Adventure Works];
Unfortunately it is tied to the measure Internet Sales Amount so not very generic. Generic calcs such as prev equiv mtd or Year on Year growth are usually added to a helper Time Caculation helper dimension that is independent from the Date dimension.