MDX Add Condition to filter for the first 6 month of the year - mdx

I would like to find the top 10 most profitable customers in the first six months of the year 2021 (January through June) sorted by profit in descending order.
The following filter for all criteria except the months:
SELECT [measures].[Profit] ON 0,
TopCount(
[Customer.FullName].members,
10,
[measures].[Profit]
) ON 1
FROM [bike_sales]
WHERE ([OrderDate].[Year].[2021])
I tried extending the WHERE clause with [OrderDate].[Month].[1]:[OrderDate].[Month].[6], however the query results were not correct.
How can the above-mentioned query be adjusted to also filter for the first 6 month of 2021?

I ended up combining the month and year:
SELECT [measures].[Profit] ON 0,
TopCount(
[Customer.FullName].members,
10,
[measures].[Profit]
) ON 1
FROM [bike_sales]
WHERE ( [OrderDate.Days].[2021].[1].[1] : [OrderDate.Days].[2021].[6].[30] )

Related

To calculate the average of Latest 12 weeks

I figured out how to calculate the average of latest 12 weeks volume in my data. But lets say the current year does not have 12 weeks, it only has 8 weeks then I want to take the remaining 4 weeks from the previous year to make it 12?
This is how my avg mdx query looks like:
Avg(
LastPeriods(
12,
Tail(
NonEmpty(
[Time].[Week].[Week].Members,
[Measures].[Vol ( Cases)]
),
1
).Item(0)
),
[Measures].[Vol ( Cases)]
)
I'm wondering if you could simplify and use the following within your measure?:
...
...
Tail(
NonEmpty(
[Time].[Week].[Week].Members,
[Measures].[Vol ( Cases)]
),
12
)
...
...

Calculate average and standard deviation for pre defined number of values substituting missing rows with zeros

I have a simple table that contains a record of products and their total sales per day over a year (just 3 columns - Product, Date, Sales). So, for example, if product A is sold every single day, it'll have 365 records. Similarly, if product B is sold for only 50 days, the table will have just 50 rows for that product - one for each day of sale.
I need to calculate the daily average sales and standard deviation for the entire year, which means that, for product B, I need to have additional 365-50=315 entries with zero sales to be able to calculate the daily average and standard deviation for the year correctly.
Is there a way to do this efficiently and dynamically in SQL?
Thanks
We can generate 366 rows and join the sales data to it:
WITH rg(rn) AS (
SELECT 1 AS rn
UNION ALL
SELECT a.rn + 1 AS rn
FROM rg a
WHERE a.rn <= 366
)
SELECT
*
FROM
rg
LEFT JOIN (
SELECT YEAR(saledate) as yr, DATEPART(dayofyear, saledate) as doy, count(*) as numsales
FROM sales
GROUP BY YEAR(saledate), DATEPART(dayofyear, saledate)
) s ON rg.rn = s.doy
OPTION (MAXRECURSION 370);
You can replace the nulls (where there is no sale data for that day) with e.g. AVG(COALESCE(numsales, 0)). You'll probably also need a WHERE clause to eliminate the 366th day on non leap years (such as MODULO the year by 4 and only do 366 rows if it's 0).
If you're only doing a single year, you can use a where clause in the sales subquery to give only the relevant records; most efficient is to use a range like WHERE salesdate >= DATEFROMPARTS(YEAR(GetDate()), 1, 1) AND salesdate < DATEFROMPARTS(YEAR(GetDate()) + 1, 1, 1) rather than calling a function on every sales date to extract the year from it to compare to a constant. You can also drop the YEAR(salesdate) from the select/group by if there is only a single year
If you're doing multiple years, you could make the rg generate more rows, or (perhaps simpler) cross join it to a list of years so you get 366 rows multiplied by e.g. VALUES (2015),(2016),(2017),(2018),(2019),(2020) (and make the year from the sales part of the join too)
find the first and last day of the year and then use datediff() to find number of days in that year.
After that don't use AVG on sales, but SUM(Sales) / days_in_year
select *,
days_in_year = datediff(day, first_of_year, last_of_year) + 1
from (values (2019), (2020)) v(year)
cross apply
(
select first_of_year = dateadd(year, year - 1900, 0),
last_of_year = dateadd(year, year - 1900 + 1, -1)
) d
There's a different way to look at it - don't try to add additional empty rows, just divide by the number of days in a year. While the number of days a year isn't constant (a leap year will have 366 days), it can be calculated easily since the first day of the year is always January 1st and the last is always December 31st:
SELECT YEAR(date),
product,
SUM(sales) / DATEPART(dy, DATEFROMPARTS(YEAR(date)), 12, 31))
FROM sales_table
GROUP BY YEAR(date), product

SQL Server - Cumulative Sum over Last 12 Months, but starting from the Last Month (SQL Server 18)

I need to run a cumulative sum of a value over the Last 12 Months. So far, my cumulative calculation are working, but starting from the Current Month.
I need the total of Last 12 Months, starting from the Last Month.
Currently, I'm using OVER clause on SQL, starting to running the cumulative total from the current row/month.
Please, refer below my code example:
SELECT *,
SUM(Amount) OVER (PARTITION BY ID ORDER BY Date_Month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS TwelveMoTtl
FROM (
SELECT DISTINCT
CAST(DATEADD(MONTH, DATEDIFF(MONTH, 0, TransactionDt), 0) AS DATE) AS Date_Month,
ID,
SUM(Amount) AS Amount
FROM MyTable
WHERE TransactionDt >= '2019-01-01'
GROUP BY
ID,
CAST(DATEADD(MONTH, DATEDIFF(MONTH, 0, TransactionDt), 0) AS DATE)
Here is my results (using only one ID to simplify the example):
As my example, the calculation are starting from the current row, and running over the last 12 months.
If we take the February row for example, I need the cumulative sum from Jan, 2020 to February, 2019.
Any suggestions how could I do it?
Thanks,
You seem to understand window functions pretty well. You just have to adjust the window frame:
SUM(Amount) OVER (PARTITION BY ID
ORDER BY Date_Month
ROWS BETWEEN 12 PRECEDING AND 1 PRECEDING
)
I forgot that I may have NULL rows in my table. So, the solution as to do a cumulative sum, even if there's missing dates. For example:
I need to running over the last 12 calendar months whether there are amount in those months or not.
Any ideas?
Thanks,
Rafael

SQL Server / SSRS: Calculating monthly average based on grouping and historical values

I need to calculate an average based on historical data for a graph in SSRS:
Current Month
Previous Month
2 Months ago
6 Months ago
This query returns the average for each month:
SELECT
avg_val1, month, year
FROM
(SELECT
(sum_val1 / count) as avg_val1, month, year
FROM
(SELECT
SUM(val1) AS sum_val1, SUM(count) AS count, month, year
FROM
(SELECT
COUNT(val1) AS count, SUM(val1) AS val1,
MONTH([SnapshotDate]) AS month,
YEAR([SnapshotDate]) AS year
FROM
[DC].[dbo].[KPI_Values]
WHERE
[SnapshotKey] = 'Some text here'
AND No = '001'
AND Channel = '999'
GROUP BY
[SnapshotDate]) AS sub3
GROUP BY
month, year, count) AS sub2
GROUP BY sum_val1, count, month, year) AS sub1
ORDER BY
year, month ASC
When I add the following WHERE clause I get the average for March (2 months ago):
WHERE month = MONTH(GETDATE())-2
AND year = YEAR(GETDATE())
Now the problem is when I want to retrieve data from 6 months ago; MONTH(GETDATE()) - 6 will output -1 instead of 12. I also have an issue with the fact that the year changes to 2016 and I am a bit unsure of how to implement the logic in my query.
I think I might be going about this wrong... Any suggestions?
Subtract the months from the date using the DATEADD function before you do your comparison. Ex:
WHERE SnapshotDate BETWEEN DATEADD(month, -6, GETDATE()) AND GETDATE()
MONTH(GETDATE()) returns an int so you can go to 0 or negative values. you need a user scalar function managing this, adding 12 when <= 0

Filtered DistinctCount Measure and MDX Not Delivering Same Results as SQL

I have the following two queries, one SQL, one MDX:
SQL:
SELECT t.term_report_year, COUNT(*)
FROM(
SELECT DISTINCT de.term_report_year, fe.student_id
FROM warehouse.FactEnrolments fe
INNER JOIN warehouse.DimDate dd
ON fe.term_record_creation_fk = dd.DateKey
INNER JOIN warehouse.DimTermEnrolments de
ON fe.term_enrolments_fk = de.term_enrolments_pk
WHERE dd.ISOWeekNumberOfYear <= 8 OR dd.ISOYearCode < de.term_report_year
) t
GROUP BY t.term_report_year
ORDER BY term_report_year
MDX:
SELECT
NON EMPTY
Measures.[Enrolments] ON COLUMNS
,NON EMPTY
Filter
(
[Term Enrolments].[Term Year].Children *
[Term Record Creation].[ISO Year Code].children *
[Term Record Creation].[ISO Week Number Of Year].children
,
Cint([Term Record Creation].[ISO Week Number Of Year].CurrentMember.Member_Key) <= 8
OR
Cint([Term Record Creation].[ISO Year Code].CurrentMember.Member_key) < Cint([Term Enrolments].[Term Year].CurrentMember.Member_key)
) ON ROWS
FROM [Enrolments];
I am trying to express the idea in both, "count the number of students in a year who enrolled for that year before or during the 8th week of that year" where year = term_year.
In my SSAS cube the Enrolments measure is a DistinctCount on student_id. In the SQL query, term_report_year is equivalent to Term Year in the MDX.
Could someone please explain why the two queries are not delivering the same numbers e.g. the SQL for 2016 gives 2803 and the MDX 2948?
I think it has something to do with the MDX double counting across the weeks, but I can't work out how to fix it.
Try this. I am hopeful it will filter the year total to just weeks <= 8
SELECT
NON EMPTY
Measures.[Enrolments] ON COLUMNS
,NON EMPTY [Term Enrolments].[Term Year].Children ON ROWS
FROM (
SELECT
Filter
(
[Term Enrolments].[Term Year].Children *
[Term Record Creation].[ISO Year Code].children *
[Term Record Creation].[ISO Week Number Of Year].children
,
Cint([Term Record Creation].[ISO Week Number Of Year].CurrentMember.Member_Key) <= 8
OR
Cint([Term Record Creation].[ISO Year Code].CurrentMember.Member_key) < Cint([Term Enrolments].[Term Year].CurrentMember.Member_key)
) ON COLUMNS
FROM [Enrolments]
);