MDX: How to get the previous period based on top count? - ssas

I must calculate the top 10 brands for this year and then get the same figures for last year... but I found it a little bit tricky.
I have the following set for the top 10 brands over year to date measure.
My date is a parameter (Month-Year) and everything is ok so far.
filter(TopCount(
([10 - Brand].[Brand].Allmembers) * {STRTOMEMBER(#DATE)}
,10,
[Measures].[Act YTD]
), [Measures].[Act YTD] <> null)
But now I have to use this set and get the previous year.
The expected results is get the top 10 this year and after, last year figures in the same query:
Year | Quarter | Month | Brand | Act YTD
2019 | 20193 | Aug 2019 | BR01 | 150
2019 | 20193 | Aug 2019 | BR02 | 250
2019 | 20193 | Aug 2019 | BR03 | 350
2019 | 20193 | Aug 2019 | BR04 | 450
2019 | 20193 | Aug 2019 | BR05 | 550
2019 | 20193 | Aug 2019 | BR06 | 650
2019 | 20193 | Aug 2019 | BR07 | 750
2019 | 20193 | Aug 2019 | BR08 | 850
2019 | 20193 | Aug 2019 | BR09 | 950
2019 | 20193 | Aug 2019 | BR10 | 1150
2018 | 20183 | Aug 2018 | BR01 | 100
2018 | 20183 | Aug 2018 | BR02 | 200
2018 | 20183 | Aug 2018 | BR03 | 300
2018 | 20183 | Aug 2018 | BR04 | 400
2018 | 20183 | Aug 2018 | BR05 | 500
2018 | 20183 | Aug 2018 | BR06 | 600
2018 | 20183 | Aug 2018 | BR07 | 700
2018 | 20183 | Aug 2018 | BR08 | 800
2018 | 20183 | Aug 2018 | BR09 | 900
2018 | 20183 | Aug 2018 | BR10 | 1000
I need guidance :)

I found the solution.
Instead of displaying the results in rows, now I am displaying them as columns.
And I had to redesign the report due to row groupings and column groupings.
This way I can create the top 10 set based on this year's date and get the Y-1 measures.
Year | Quarter | Month | Brand | Act YTD | Act YTD -1 |
2019 | 20193 | Aug 2019 | BR01 | 150 | 100 |
2019 | 20193 | Aug 2019 | BR02 | 250 | 200 |
2019 | 20193 | Aug 2019 | BR03 | 350 | 300 |
2019 | 20193 | Aug 2019 | BR04 | 450 | 400 |
2019 | 20193 | Aug 2019 | BR05 | 550 | 500 |
2019 | 20193 | Aug 2019 | BR06 | 650 | 600 |
2019 | 20193 | Aug 2019 | BR07 | 750 | 700 |
2019 | 20193 | Aug 2019 | BR08 | 850 | 800 |
2019 | 20193 | Aug 2019 | BR09 | 950 | 900 |
2019 | 20193 | Aug 2019 | BR10 | 1150 | 1000 |

You could try to use Union and Parallelperiod functions, something like this, depending on the name of you date dimension, hierarchy and level:
Union(filter(TopCount(
([10 - Brand].[Brand].Allmembers) * {STRTOMEMBER(#DATE)}
,10,
[Measures].[Act YTD]
), [Measures].[Act YTD] <> null)
,
filter(TopCount(
([10 - Brand].[Brand].Allmembers) * {PARALLELPERIOD([Date].[Calendar Year].[Calendar Year], 1, STRTOMEMBER(#DATE))}
,10,
[Measures].[Act YTD]
), [Measures].[Act YTD] <> null))

Related

How to refer to other columns using a condition when creating a calculated column?

Suppose I have a SQL table as shown below where Min Spend is the minimum spend for each year and is a calculated column created using SQL-Window Function
|------------|-------|--------|----------|
| Year |Month | Spend |Min Spend |
|------------|-------|--------|----------|
| 2018 | Jan | 10 | 10 |
| 2018 | Feb | 20 | 10 |
| 2018 | Oct | 25 | 10 |
| 2019 | Jan | 90 | 45 |
| 2019 | Aug | 60 | 45 |
| 2019 | Nov | 45 | 45 |
|------------|-------|--------|----------|
I would like to create a new column as a calculated field in the table that gives me the month corresponding the the 'Min Spend' for that year as shown below
|------------|-------|--------|----------|---------------|
| Year |Month | Spend |Min Spend |Min Spend Month|
|------------|-------|--------|----------|---------------|
| 2018 | Jan | 10 | 10 | Jan |
| 2018 | Feb | 20 | 10 | Jan |
| 2018 | Oct | 25 | 10 | Jan |
| 2019 | Jan | 90 | 45 | Nov |
| 2019 | Aug | 60 | 45 | Nov |
| 2019 | Nov | 45 | 45 | Nov |
|------------|-------|--------|----------|---------------|
Can anybody suggest how to approach this?
You can use window functions like this:
select t.*,
min(spend) over (partition by year) as min_spend,
first_value(month) over (partition by year order by spend) as min_spend_month
from t;

How can I select from multiple rows of a child/join table into a single row in the resultset based on a sequence?

tbl_vacations
vac_id | vac_name
1 | American vacation
2 | European vacation
tbl_vacation_stops
stop_id | vac_id | stop_sequence | stop_name | stop_strt_day | stop_end_day
1 | 1 | 1 | New York | may 1 2018 | may 3 2018
2 | 1 | 2 | Boston | may 4 2018 | may 6 2018
3 | 1 | 3 | Chicago | may 7 2018 | may 9 2018
4 | 2 | 1 | Paris | jun 10 2018 | jun 15 2018
5 | 2 | 2 | Berlin | jun 16 2018 | jun 19 2018
select
v.vac_id as vac_id,
v.vac_name as vac_name,
vs.stop_strt_day as vac_strt_day
from tbl_vacations v
join tbl_vacation_stops vs
where v.vac_id=vs.vac_id and vs.stop_sequence='1'
vac_id | vac_name | vac_strt_day | vac_end_day
1 | American vacation | may 1 2018 | may 9 2018
2 | European vacation | jun 10 2018 | jun 19 2018
If there are a different number of stops in each vacation, how do I figure out the vac_end_day based on max stop sequence?
this would do the trick:
select
v.vac_id as vac_id,
v.vac_name as vac_name,
(select stop_strt_day from tbl_vacation_stops where vac_id = v.vac_id
and stop_sequence = (select min(stop_sequence) from tbl_vacation_stops where vac_id =
v.vac_id)
) as vac_strt_day,
(select stop_end_day from tbl_vacation_stops where vac_id = v.vac_id
and stop_sequence = (select max(stop_sequence) from tbl_vacation_stops where vac_id =
v.vac_id)
) as vac_end_day
from tbl_vacations v

Group By Different Values

I would like to group by the first day and then the rest of the month, I have data that spans years.
I have data like below:
--------------------------------------
DAY MONTH YEAR VISITOR_COUNT
--------------------------------------
1 | 12 | 2014 | 16260
2 | 12 | 2014 | 15119
3 | 12 | 2014 | 14464
4 | 12 | 2014 | 13746
5 | 12 | 2014 | 13286
6 | 12 | 2014 | 14352
7 | 12 | 2014 | 19293
8 | 12 | 2014 | 13338
9 | 12 | 2014 | 13961
10 | 12 | 2014 | 9519
11 | 12 | 2014 | 10204
12 | 12 | 2014 | 9380
13 | 12 | 2014 | 11611
14 | 12 | 2014 | 14839
15 | 12 | 2014 | 10051
16 | 12 | 2014 | 8983
17 | 12 | 2014 | 7348
18 | 12 | 2014 | 7258
19 | 12 | 2014 | 7205
20 | 12 | 2014 | 6113
21 | 12 | 2014 | 5316
22 | 12 | 2014 | 6914
23 | 12 | 2014 | 6880
24 | 12 | 2014 | 6289
25 | 12 | 2014 | 6000
26 | 12 | 2014 | 13328
27 | 12 | 2014 | 10367
28 | 12 | 2014 | 7946
29 | 12 | 2014 | 9042
30 | 12 | 2014 | 9408
31 | 12 | 2014 | 8411
1 | 1 | 2015 | 9965
2 | 1 | 2015 | 10560
3 | 1 | 2015 | 9662
4 | 1 | 2015 | 8735
5 | 1 | 2015 | 12817
6 | 1 | 2015 | 13516
7 | 1 | 2015 | 9800
8 | 1 | 2015 | 10629
9 | 1 | 2015 | 12325
10 | 1 | 2015 | 11899
11 | 1 | 2015 | 11049
12 | 1 | 2015 | 13934
13 | 1 | 2015 | 16833
14 | 1 | 2015 | 13434
15 | 1 | 2015 | 13128
16 | 1 | 2015 | 14660
17 | 1 | 2015 | 11951
18 | 1 | 2015 | 10916
19 | 1 | 2015 | 14126
20 | 1 | 2015 | 16909
21 | 1 | 2015 | 16555
22 | 1 | 2015 | 14726
23 | 1 | 2015 | 14642
24 | 1 | 2015 | 13067
25 | 1 | 2015 | 11738
26 | 1 | 2015 | 15353
27 | 1 | 2015 | 17935
28 | 1 | 2015 | 14448
29 | 1 | 2015 | 15372
30 | 1 | 2015 | 16694
31 | 1 | 2015 | 16763
I would like to be able to group it like below:
--------------------------------------
DAY MONTH YEAR VISITOR_COUNT
--------------------------------------
1 | 12 | 2014 | 16260
2-31| 12 | 2014 | 309971
1 | 1 | 2015 | 9965
2-31| 1 | 2015 | 404176
Microsoft SQL Server 2016. Compatibility level: SQL Server 2005 (90)
Just use case:
select (case when min(day) = 1 then '1'
else concat(min(day), '-', max(day))
end) as day, month, year,
sum(visitor_count)
from t
group by year, month,
(case when day = 1 then 1 else 2 end);
Okay, this is a little tricky. The case in the group by and the case in the select are different. The group by just puts the days into two categories, 1 and others. The select chooses the minimum and maximum days in the month, to construct the range string.
EDIT:
Oy, SQL Server 2005 ???
Of course, you can do the same thing with + and type conversion, or using replace():
select (case when min(day) = 1 then '1'
else replace(replace('#min-#max', '#min', min(day)), '#max', max(day))
end) as day, month, year,
sum(visitor_count)
from t
group by year, month,
(case when day = 1 then 1 else 2 end);

SQL Query Average last 3 days in a table

Thank you for help in advance. Can anyone please help me with sql query for
I have daily table like
> Date | Sales_Rep_ID| Product ID | Zone | Sales
> 31 Jan 2015 | 001 | P01| EMEA | 10
> 31 Jan 2015 | 002 | P02| EMEA | 10
> 31 Jan 2015 | 003 | P02| EMEA | 10
> 30 Jan 2015 | 001 | P01| EMEA | 8
> 30 Jan 2015 | 002 | P02| EMEA | 7
> 30 Jan 2015 | 003 | P02| EMEA | 2
and wanted a average of last n days in last column depending upon date , rep id , product id
Date | Sales_Rep_ID| Product ID | Zone | Sales | AVG_3_DAYS
31 Jan 2015 | 001 | P01 | EMEA | 10 | 9
31 Jan 2015 | 002 | P02 | EMEA | 10 | 8.5
31 Jan 2015 | 003 | P02 | EMEA | 10 | 6
30 Jan 2015 | 001 | P01 | EMEA | 8 | .
30 Jan 2015 | 002 | P02 | EMEA | 7 | .
30 Jan 2015 | 003 | P02 | EMEA | 2 | .
For example
for row 1 date is 31 jan and we need average for 31,30, 29 jan for sales rep 001 and product id 002
and for row 4 date is 30 jan and we need average for 30 ,29, 38 jan for sales rep 001 and product id 002
In SQL Server, you can use apply for this purpose:
select t.*, tt.avgsales
from t outer apply
(select avg(sales) as avgsales
from t t2
where t2.rep_id = t.rep_id and
t2.product_id = t.product_id
t2.date <= t.date and
t2.date > dateadd(day, -3, t.date)
) tt;

SSAS MDX for SUM (DISTINCT Customer's (MAX (Date's Weight)))

To the MDX gurus,
I have been beating my head against this one for a week and I am nowhere close to solving it. Can it be solved?
Here's the challenge:
To create a Calculated Member Expression in SSAS BIDs to calculate the Weighted_Members which is described as the following:
"For any date period chosen, we need to calculate the sum of the Weights that is associated with the most recent visit of a unique member."
In pseudo-code: SUM(DISTINCT Member’s (MAX (Date’s Weight)))
NOTES:
* The WEIGHT is given to a member’s visit to a particular location and is applicable for 1 month.
Here is a sample of the fact table showing:
* Two members (membership id: 100 and 103)
* Visiting 3 different locations (location id: 200, 220 and 230)
* At different dates throughout 2014 and 2015.
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
1 | Jan 1, 2014 | 100 | 230 | 3.5 |
2 | Mar 1, 2014 | 100 | 220 | 2.0 |
3 | May 1, 2015 | 100 | 220 | 2.5 |
4 | Apr 1, 2014 | 103 | 200 | 1.0 |
5 | Jul 1, 2014 | 103 | 220 | 1.5 |
6 | Sep 1, 2014 | 103 | 230 | 0.5 |
7 | Nov 1, 2014 | 103 | 220 | 3.0 |
8 | Jan 1, 2015 | 103 | 220 | 1.0 |
9 | Aug 1, 2015 | 103 | 200 | 7.0 |
10 | Sep 1, 2015 | 103 | 230 | 4.5 |
11 | Dec 1, 2015 | 103 | 200 | 1.5 |
Dimensions:
The Visit Date Dimension has the following attributes:
* YEAR
* Quarter
* MONTH
* Date
* Calendar Year->Quarter->Month->Date (calendar_quarter_hierarchy)
* Calendar Year->Month->Date (calendar_month_hierarchy)
The Membership Dimension has the following attributes:
* membership_id (currently visibility set to false (or hidden) as there are >5M records)
* Gender
* Age Cohort
The Location Dimension has the following attributes:
* Location_ID
* Location_Name
* City
* Province
* Province->City->Location_Name (Geographical_hierarchy)
Examples:
Example #1.) The Weighted_Members for the YEAR 2014 would be calculated as follows:
STEP 1: filtering the fact data for activity in YEAR 2014.
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
=============================================================================
1 | Jan 1, 2014 | 100 | 230 | 2.5 |
2 | Mar 1, 2014 | 100 | 220 | 2.0 |
4 | Apr 1, 2014 | 103 | 200 | 1.0 |
5 | Jul 1, 2014 | 103 | 220 | 1.5 |
6 | Sep 1, 2014 | 103 | 230 | 0.5 |
7 | Nov 1, 2014 | 103 | 220 | 3.0 |
STEP 2: taking the data with the most recent date for each unique member from the above:
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
=============================================================================
2 | Mar 1, 2014 | 100 | 220 | 2.0 |
7 | Nov 1, 2014 | 103 | 220 | 3.0 |
STEP 3: sum the Weights to give the Weighted_Members = 2.0 + 3.0 is 5.0
======
Example #2.) If the cube user slices for the time period of 2015, following the same three steps in example #1 above, the Weighted_Members:
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
=============================================================================
3 | May 1, 2015 | 100 | 220 | 2.5 |
11 | Dec 1, 2015 | 103 | 200 | 1.5 |
Weighted_Members = 2.5 + 1.5 is 4.0
======
Example #3.) If the cube user slices for the time period of Mar 2014 to Oct 2014 and is interested in visits to location_id = 220, the Weighted_Members:
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
=============================================================================
2 | Mar 1, 2014 | 100 | 220 | 2.0 |
5 | Jul 1, 2014 | 103 | 220 | 1.5 |
Weighted_Members = 2.0 + 1.5 is 3.5
======
Example #4.) If the cube user slices for the time period of July 2015 to Aug 2015, the Weighted_Members:
Visits_F_ID | Visit_Date | Membership_ID | Location_ID | Weights |
=============================================================================
9 | Aug 1, 2015 | 103 | 200 | 7.0 |
Weighted_Members = 7.0
Based on my understanding - You can give this a try:
WITH MEMBER Measures.YourCalcMember AS
SUM
(
generate
(
Customer.CustomerID.MEMBERS AS S,
s.CURRENT *
TAIL(
NonEmpty
(
[Date].[Date].[Date].MEMBERS, --The last date for the "current" customer
(s.CURRENT, [Measures].[Weight])
)
)
)
,
Measures.[Weight]
)
SELECT Measures.YourCalcMember ON 0,
Location.LocationID.MEMBERS ON 1
FROM
(
SELECT [Date].[Year].&[2014] ON 0 FROM [Your Cube] --The year filter
)
Using the "generate" function, loop thru the customers and obtain a cross-set of customerId and the 'last' date for that customer. Over this set then, obtain the sum of weights.
All said, further details are needed before this question can be attempted correctly.