Custom Aggregation/Column Concatenation Within an MDX Query - ssas

I have a date dimension and a time dimension and a measure called [Count - Sales]. I would like to run a query that would give me the count of sales over a range of time on a given date, and also concatenate the date and time values and show me the start and end date-time. So the end results I am expecting would look something like this:
StartDateTime | EndDateTime | Count - Sales
------------------------------------------------
20130901 12 | 20130901 16 | 4000
20130902 12 | 20130902 16 | 4123
I have come up with a way to concatenate the date and time values, but I haven't been able to figure out a way to have the two columns StartDateTime and EndDateTime. The query I have right now gives me the [Count - Sales] for every hour:
WITH MEMBER Measures.DateTime AS
[Date].[Date].CurrentMember.Name + " " + [Time].[Hour 24].CurrentMember.Name + ":00"
SELECT
{{[Date].[Date].&[20131101]:[Date].[Date].&[20131101]}*{[Time].[Hour 24].&[10]:[Time].[Hour 24].&[14]},
{[Date].[Date].&[20131102]:[Date].[Date].&[20131102]}*{[Time].[Hour 24].&[10]:[Time].[Hour 24].&[14]} } ON ROWS,
{Measures.DateTime,
[Measures].[Count - Sales] } ON COLUMNS
FROM Sales
And the result is:
Date Time DateTime Count - Sales
20131101 10 20131101 10 206
20131101 11 20131101 11 251
20131101 12 20131101 12 318
20131101 13 20131101 13 304
20131101 14 20131101 14 300
20131102 10 20131102 10 194
20131102 11 20131102 11 251
20131102 12 20131102 12 298
20131102 13 20131102 13 329
20131102 14 20131102 14 345
Any help/guidance would be appreciated.

WITH SET [Time Range Set] AS
[Time].[Hour 24].&[10] : [Time].[Hour 24].&[14]
MEMBER [Time].[Hour 24].TimeRange AS
Aggregate([Time Range Set])
MEMBER Measures.StartDateTime AS
[Date].[Date].CurrentMember.Name + " "
+ [Time Range Set].Item(0).Item(0).Name + ":00"
MEMBER Measures.EndDateTime AS
[Date].[Date].CurrentMember.Name + " "
+ Tail([Time Range Set]).Item(0).Item(0).Name + ":59"
SELECT
{ Measures.StartDateTime, Measures.EndDateTime, [Measures].[Count - Sales] }
ON COLUMNS,
{[Date].[Date].&[20131101]:[Date].[Date].&[20131102]}
*
{[Time].[Hour 24].TimeRange}
ON ROWS
FROM Sales
On the rows, you only want to show two days, and the time range member for each one. The .Item(0).Item(0) construct gets the first member of the first tuple of a set. Hence, we can use it directly for the StartDateTime, but need to apply Tail, which returns a set containing the last tuple of the set to which it is applied.
Please note that specifying ROWS before COLUMNS violates the MDX specification (but Analysis Services is tolerant and interprets it correctly).

Related

(SQL)How to Get absence "day" from date under 1-31 column using PIVOT

I have a table abs_details that give data like follows -
PERSON_NUMBER ABS_DATE ABS_TYPE_NAME ABS_DAYS
1010 01-01-2022 PTO 1
1010 06-01-2022 PTO 0.52
1010 02-02-2022 VACATION 1
1010 03-02-2022 VACATION 0.2
1010 01-12-2021 PTO 1
1010 02-12-2021 sick 1
1010 30-12-2021 sick 1
1010 30-01-2022 SICK 1
I want this data to be displayed in the following way:
PERSON_NUMBER ABS_TYPE_NAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
1010 PTO 2 0.52
1010 VACATION 1 0.2
1010 SICK 1 2
For the days, 1-31 should should come in the header, if there is any absence taken on say 01st of the month or quarter passed then the value should go under 1 , if there is no value for date of the month, say no value is there from 07th-11th in the above case, then output should display the numbers but no value should be provided under it.
Is this feasible in SQL? I have an idea we can use pivot, but how to fix 1-31 header and give values underneath each day.
Any suggestions?
If I pass multiple quarter that is Q1(JAN-MAR), Q2(APR-JUN) it should sum up the values between the dates between those two quarters. if Just q1 then only q1 result
If I pass multiple month then it should display the sum of the values for an absence type in those multiple months.
I will be passing the year in the parameter and the above two should consider the year I pass.
Create a column which has all the dates, and pivot up using pivot function in oracle.
SELECT *
FROM
(
SELECT PERSON_NUMBER,
EXTRACT(DAY FROM TO_DATE(ABS_DATE)) AS DAY_X,
ABS_TYPE_NAME,
ABS_DAYS
FROM TABLE
-- Add additional filter here which you want
)
PIVOT(SUM(ABS_DAYS)
FOR DAY_X IN (0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31))
Db fiddle - https://dbfiddle.uk/?rdbms=oracle_21&fiddle=ad3af639235f7a6db415ec714a3ee0d9

How to sum with specific range of records

I have table
tax number yearmonth(int)
100 45 202105
2 45 202104
35 45 202102
47 45 202012
58 45 202005
I try to aggregate sum for every number by last 12 month
For instance 202105 - I need sum month between (202012 - 202001)
Main problem -> not every number has all 12 months
I tried over clause but it sums all 12 preceding records. It does not take into account missing year records.
case when yearmonth-lag(yearmonth,1) OVER ( order by number, yearmonth) <> (0) then
sum([tax]) OVER (
PARTITION BY [number]
ORDER BY yearmonth
Rows BETWEEN 11 PRECEDING AND CURRENT ROW ) end

Extract 30 minutes from timestamp and group it by 30 mins time interval -PGSQL

In PostgreSQL I am extracting hour from the timestamp using below query.
select count(*) as logged_users, EXTRACT(hour from login_time::timestamp) as Hour
from loginhistory
where login_time::date = '2021-04-21'
group by Hour order by Hour;
And the output is as follows
logged_users | hour
--------------+------
27 | 7
82 | 8
229 | 9
1620 | 10
1264 | 11
1990 | 12
1027 | 13
1273 | 14
1794 | 15
1733 | 16
878 | 17
126 | 18
21 | 19
5 | 20
3 | 21
1 | 22
I want the same output for same SQL for 30 mins. Please suggest
SELECT to_timestamp((extract(epoch FROM login_time::timestamp)::bigint / 1800) * 1800)::timestamp AS interval_30_min
, count(*) AS logged_users
FROM loginhistory
WHERE login_time::date = '2021-04-21' -- inefficient!
GROUP BY 1
ORDER BY 1;
Extracting the epoch gets the number of seconds since the epoch. Integer division truncates. Multiplying back effectively rounds down, achieving the same as date_trunc() for arbitrary time intervals.
1800 because 30 minutes contain 1800 seconds.
Detailed explanation:
Truncate timestamp to arbitrary intervals
The cast to timestamp makes me wonder about the actual data type of login_time? If it's timestamptz, the cast depends on your current time zone setting and sets you up for surprises if that setting changes. See:
How do I match an entire day to a datetime field?
Subtract hours from the now() function
Ignoring time zones altogether in Rails and PostgreSQL
Depending on the actual data type, and exact definition of your date boundaries, there is a more efficient way to phrase your WHERE clause.
You can change the column on which you're aggregating to use the minute too:
select
count(*) as logged_users,
CONCAT(EXTRACT(hour from login_time::timestamp), '-', CASE WHEN EXTRACT(minute from login_time::timestamp) < 30 THEN 0 ELSE 30 END) as HalfHour
from loginhistory
where login_time::date = '2021-04-21'
group by HalfHour
order by HalfHour;

Custom sorting by month name in SQL Server

I have a table where for some dates a certain number of entries are placed. Here is the table structure :
ID EntryName Entries DateOfEntry
1 A 20 2016-01-17
2 B 22 2016-01-29
3 C 23 2016-02-17
4 D 19 2016-02-17
5 E 29 2016-03-17
6 F 30 2016-03-17
7 G 43 2016-04-17
8 H 10 2016-04-17
9 I 5 2016-05-17
10 J 120 2016-05-17
11 K 220 2016-06-17
12 L 210 2016-06-17
13 M 10 2016-07-17
14 N 20 2016-07-17
15 O 15 2016-08-17
16 P 17 2016-08-17
17 Q 19 2016-09-17
18 R 23 2016-09-17
19 S 43 2016-10-17
20 T 56 2016-10-17
21 U 65 2016-11-17
22 V 78 2016-11-17
23 W 12 2016-12-17
24 X 23 2016-12-17
25 Y 43 2016-02-17
26 Z 67 2016-03-17
27 AA 35 2015-01-17
28 AB 23 2015-01-29
29 AC 43 2015-02-17
30 AD 35 2015-02-17
31 AE 45 2015-03-17
32 AF 23 2015-03-17
33 AG 43 2015-04-17
34 AH 19 2015-04-17
35 AI 21 2015-05-17
36 AJ 13 2015-05-17
37 AK 22 2015-06-17
38 AL 45 2015-06-17
39 AM 66 2015-07-17
40 AN 77 2015-07-17
41 AO 89 2015-08-17
42 AP 127 2015-08-17
43 AQ 19 2015-09-17
44 AR 223 2015-09-17
45 AS 143 2015-10-17
46 AT 36 2015-10-17
47 AU 45 2015-11-17
48 AV 28 2015-11-17
49 AW 72 2015-12-17
50 AX 24 2015-12-17
51 AY 46 2015-02-17
52 AZ 62 2015-03-17
The column EntryName is the entry identifier, the column Entries has the total number of entries for the date specified in the column DateOfEntry.
I am trying to formulate a query where the total number of entries are displayed on a month-wise basis. I currently have this query :
SELECT DateName(MONTH, e.DateOfEntry) AS MonthOfEntry,
MONTH(e.DateOfEntry) AS MonthNumber,
SUM(e.Entries) AS TotalEntries
FROM #entry e
GROUP BY MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry)
ORDER BY MONTH(e.DateOfEntry) ASC
which works fine as far as displaying the results are concerned. However, my issue here is that I need to sort the results on a month-wise basis where the starting month would be dynamic i.e. arising from a parameter (supplied by the user).
This means that if the user selects May of 2015 the results should be sorted from May 2015 to April 2016. Similarly, if the user selects October 2015, the results would be displayed from October 2015 to September 2016.
How would I go about getting this condition within the ORDER BY clause ?
You can put an offset into the ORDER BY using modulo arithmetic. For April:
ORDER BY (MONTH(e.DateOfEntry) + 12 - 4) % 12
--------------------------------------^ month number to start with
(The + 12 is simply so I don't have to remember if % returns negative numbers with negative operands.)
If you want the results chronologically, you can instead do:
ORDER BY MIN(e.DateOfEntry)
You could use the belosw in order by
ORDER BY YEAR(e.DATEOFENTRY),
DATEPART(MM,e.DAREOFENTRY)
This will sort the result first for Year and next for month.
Here you need to specify these same columns in Select.
If I understood you correctly
"This means that if the user selects May of 2015 the results should be sorted from May 2015 to April 2016. Similarly, if the user selects October 2015, the results would be displayed from October 2015 to September 2016."
this should work:
SAMPLE DATA:
IF OBJECT_ID('tempdb..#entry') IS NOT NULL
DROP TABLE #entry;
CREATE TABLE #entry(ID INT ,EntryName VARCHAR(10) , Entries INT , DateOfEntry DATE);
INSERT INTO #entry (ID ,EntryName ,Entries ,DateOfEntry)
VALUES
(1 ,'A', 20 ,'2016-01-17'),
(2 ,'B', 22 ,'2016-01-29'),
(3 ,'C', 23 ,'2016-02-17'),
(4 ,'D', 19 ,'2016-02-17'),
(5 ,'E', 29 ,'2016-03-17'),
(6 ,'F', 30 ,'2016-03-17'),
(7 ,'G', 43 ,'2016-04-17'),
(8 ,'H', 10 ,'2016-04-17'),
(9 ,'I', 5 ,'2016-05-17'),
(10,'J', 120 ,'2016-05-17'),
(11,'K', 220 ,'2016-06-17'),
(12,'L', 210 ,'2016-06-17'),
(13,'M', 10 ,'2016-07-17'),
(14,'N', 20 ,'2016-07-17'),
(15,'O', 15 ,'2016-08-17'),
(16,'P', 17 ,'2016-08-17'),
(17,'Q', 19 ,'2016-09-17'),
(18,'R', 23 ,'2016-09-17'),
(19,'S', 43 ,'2016-10-17'),
(20,'T', 56 ,'2016-10-17'),
(21,'U', 65 ,'2016-11-17'),
(22,'V', 78 ,'2016-11-17'),
(23,'W', 12 ,'2016-12-17'),
(24,'X', 23 ,'2016-12-17'),
(25,'Y', 43 ,'2016-02-17'),
(26,'Z', 67 ,'2016-03-17'),
(27,'AA',35 ,'2015-01-17'),
(28,'AB',23 ,'2015-01-29'),
(29,'AC',43 ,'2015-02-17'),
(30,'AD',35 ,'2015-02-17'),
(31,'AE',45 ,'2015-03-17'),
(32,'AF',23 ,'2015-03-17'),
(33,'AG',43 ,'2015-04-17'),
(34,'AH',19 ,'2015-04-17'),
(35,'AI',21 ,'2015-05-17'),
(36,'AJ',13 ,'2015-05-17'),
(37,'AK',22 ,'2015-06-17'),
(38,'AL',45 ,'2015-06-17'),
(39,'AM',66 ,'2015-07-17'),
(40,'AN',77 ,'2015-07-17'),
(41,'AO',89 ,'2015-08-17'),
(42,'AP',127 ,'2015-08-17'),
(43,'AQ',19 ,'2015-09-17'),
(44,'AR',223 ,'2015-09-17'),
(45,'AS',143 ,'2015-10-17'),
(46,'AT',36 ,'2015-10-17'),
(47,'AU',45 ,'2015-11-17'),
(48,'AV',28 ,'2015-11-17'),
(49,'AW',72 ,'2015-12-17'),
(50,'AX',24 ,'2015-12-17'),
(51,'AY',46 ,'2015-02-17'),
(52,'AZ',62 ,'2015-03-17')
QUERY WITH PARAMS:
DECLARE #Month VARCHAR(2) = '05', #Year VARCHAR(4) = '2015'
SELECT DateName(MONTH, e.DateOfEntry) AS MonthOfEntry,
MONTH(e.DateOfEntry) AS MonthNumber,
SUM(e.Entries) AS TotalEntries
FROM #entry e
WHERE CAST(e.DateOfEntry AS DATE) >= CAST( #Year+#Month+'01' AS DATE)
GROUP BY MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry)
ORDER BY MONTH(e.DateOfEntry) ASC
RESULTS:
add a where clause for the query
WHERE MONTH(e.DateOfEntry) < User.Month AND YEAR(e.DateOfEntry) < User.Year AND MONTH(e.DateOfEntry) > (User.Month-1) AND YEAR(e.DateOfEntry) > (User.Year+1)
Assuming your parameter is an Integer called #FirstMonth, you could get the proper month order using:
Case
WHEN MONTH(e.DateOfEntry) < #FirstMonth then MONTH(e.DateOfEntry) + 12
ELSE MONTH(e.DateOfEntry)
END AS MonthNumber
Of all the answers and suggestions I have come across here, I find this way (suggested by xQbert in the question's comments) to be the simplest one :
SELECT DateName(MONTH, e.DateOfEntry) + ' ' + CONVERT(NVARCHAR(100), YEAR(e.DateOfEntry)) AS MonthOfEntry,
MONTH(e.DateOfEntry) AS MonthNumber,
SUM(e.Entries) AS TotalEntries
FROM Entry e
WHERE e.DateOfEntry BETWEEN #StartDate AND (DATEADD(YEAR, 1, #StartDate))
GROUP BY MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry), YEAR(e.DateOfEntry)
ORDER BY YEAR(e.DateOfEntry) ASC, MONTH(e.DateOfEntry) ASC
A fiddle to demonstrate this : http://rextester.com/CJFFP5640
Initially, I was using the following query :
SELECT sortingList.MonthOfEntry,
sortingList.TotalEntries,
sortingList.MonthNumber
FROM (
SELECT DateName(MONTH, DATEADD(MONTH, MONTH(e.DateOfEntry), 0) - 1) + ' ' + CONVERT(nvarchar(20),YEAR(e.DateOfEntry)) AS MonthOfEntry,
SUM(e.Entries) as TotalEntries,
CASE
WHEN ((MONTH(e.DateOfEntry) - MONTH(#StartDate)) > 0)
THEN (MONTH(e.DateOfEntry) - MONTH(#StartDate)) + 1
WHEN ((MONTH(e.DateOfEntry) - MONTH(#StartDate)) = 0)
THEN 1
ELSE
((12 - MONTH(#StartDate)) + (MONTH(e.DateOfEntry))) + 1
END
AS MonthNumber
FROM Entry e
WHERE e.DateOfEntry >= #StartDate AND e.DateOfEntry < DATEADD(YEAR, 1, #StartDate)
GROUP BY DateName(MONTH, DATEADD(MONTH, MONTH(e.DateOfEntry), 0) - 1), YEAR(e.DateOfEntry), MONTH(e.DateOfEntry) - MONTH(#StartDate), MONTH(e.DateOfEntry)
) sortingList
ORDER BY sortingList.MonthNumber ASC
Here's an Fiddle to demonstrate this : http://rextester.com/LEVD30653
Explanation (non TL;DR)
You can see that it's essentially the same WHERE clause. However, the query at the top uses much simpler logic for sorting and is more fluent and readable.
Do note that the second solution (using the CASE statement) sorts the month numbers as per the user-provided month number i.e. if the user provides December 2015, then the second solution will number Dec 2015 as 1, January 2016 as 2, February 2016 as 3 and so on and so forth. This might be more beneficial in cases where you want to work on top of this data.
As far as my use-case is concerned, this makes more sense. However, as far as the scope of the question is concerned, the query at the top is the best one.

Is it possible to write an MDX query of the format "last x days of days of week"?

This is from a heavily manually maintained report that I am trying to automate a bit view an SSAS cube.
The report contains daily sales, and, among other things, a measure called "last 4 's". E.g., For Friday, October 16 the measure was the average sales over the last 4 Fridays.
Is there a way to construct this in MDX in way that can be placed in a calculated measure in an SSAS cube?
ps--In response to whytheq's question, yes, the date dimension includes day of week, which is an integer in which Sun = 1, Mon = 2 and so on to Sat = 7.
I see that I was slightly ambiguous above. By "last 4 Fridays" above I meant the 4 Fridays immediately preceding October 16, not the most recent 4 Fridays.
Agreed with whytheq, that more information may help us to create optimal solution. Anyway:
Solved if you have only flat days hierarchy:
+All
-2015/01/01
-2015/01/02
...
-2015/12/31
...
Logic could be like this:
rank all days
split by weeks
calculate last 4 for every day type
show result for every selected member
Example of flat hierarchy [Report Date].[Report Date].[Day] calculation:
with
member [Measures].[AllDaysRank] as Rank([Report Date].[Report Date].CurrentMember,[Report Date].[Report Date].[Day].Members)
member [Measures].[WeekDay] as ([Measures].[AllDaysRank]-(Int([Measures].[AllDaysRank]/7)*7))
set [Last4Set0] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=0),4,[Measures].[AllDaysRank])
set [Last4Set1] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=1),4,[Measures].[AllDaysRank])
set [Last4Set2] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=2),4,[Measures].[AllDaysRank])
set [Last4Set3] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=3),4,[Measures].[AllDaysRank])
set [Last4Set4] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=4),4,[Measures].[AllDaysRank])
set [Last4Set5] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=5),4,[Measures].[AllDaysRank])
set [Last4Set6] as TopCount(Filter([Report Date].[Report Date].[Day].Members,[Measures].[WeekDay]=6),4,[Measures].[AllDaysRank])
member [Measures].[Last4Measure] as
case [Measures].[WeekDay]
when 0 then sum([Last4Set0],[Measures].[Count])
when 1 then sum([Last4Set1],[Measures].[Count])
when 2 then sum([Last4Set2],[Measures].[Count])
when 3 then sum([Last4Set3],[Measures].[Count])
when 4 then sum([Last4Set4],[Measures].[Count])
when 5 then sum([Last4Set5],[Measures].[Count])
when 6 then sum([Last4Set6],[Measures].[Count])
end
select {[Measures].[Count],[Measures].[AllDaysRank],[Measures].[WeekDay],[Measures].[Last4Measure]} on 0
,[Report Date].[Report Date].[Day].Members on 1
from [DATA]
Result (Count, AllDaysRank, WeekDay, Last4Measure):
20151001 10 740 5 35
20151002 10 741 6 39
20151003 8 742 0 37
20151004 12 743 1 42
20151005 13 744 2 42
20151006 12 745 3 39
20151007 10 746 4 36
20151008 8 747 5 35
20151009 6 748 6 39
20151010 11 749 0 37
20151011 10 750 1 42
20151012 7 751 2 42
20151013 8 752 3 39
20151014 6 753 4 36
20151015 9 754 5 35
20151016 11 755 6 39
20151017 11 756 0 37
20151018 10 757 1 42
20151019 14 758 2 42
20151020 8 759 3 39
20151021 11 760 4 36
20151022 4 761 5 35
20151023 16 762 6 39
20151024 5 763 0 37
20151025 10 764 1 42
20151026 8 765 2 42
20151027 11 766 3 39
20151028 9 767 4 36
20151029 14 768 5 35
20151030 6 769 6 39
20151031 10 770 0 37
If you have week hierarchy or some properties (not to calculate day numbers), it would be easier.
UPDATE (weekly attribute is present):
Here is script for weeks, but please create weekday->day hierarchy first, e.g:
All
+1
-2015/01/01
-2015/01/08
...
+2
-2015/01/02
-2015/01/09
...
Code has code tricks I'll explain further:
with
member [Measures].[Week Day INFO] as [Report Date].[Week Day].Properties( "Report Date Week Day" )
member [Measures].[Last4Measure] as
/* if there are no empty 4 weeks for the first dates with data, take smaller size */
iif([Report Date].[Week Day].CurrentMember.Lag(3).Parent.Member_Key <> [Report Date].[Week Day].CurrentMember.Parent.Member_Key
,iif([Report Date].[Week Day].CurrentMember.Lag(2).Parent.Member_Key <> [Report Date].[Week Day].CurrentMember.Parent.Member_Key
,iif([Report Date].[Week Day].CurrentMember.Lag(1).Parent.Member_Key <> [Report Date].[Week Day].CurrentMember.Parent.Member_Key
,sum({[Report Date].[Week Day].CurrentMember},[Measures].[Count])
,sum({[Report Date].[Week Day].CurrentMember.Lag(1):[Report Date].[Week Day].CurrentMember},[Measures].[Count]))
,sum({[Report Date].[Week Day].CurrentMember.Lag(2):[Report Date].[Week Day].CurrentMember},[Measures].[Count]))
/* end of fixing, which could be necessary */
/* calculation part */
,sum({[Report Date].[Week Day].CurrentMember.Lag(3):[Report Date].[Week Day].CurrentMember},[Measures].[Count]))
select
{[Measures].[Count],[Measures].[Week Day INFO],[Measures].[Last4Measure]} on 0
,[Report Date].[Report Date].[Day].members on 1
from [DATA]
Week Day INFO measure is for result viewing only, not necessary in calculations.
Exact code to calculate is really simple: sum({[Report Date].[Week Day].CurrentMember.Lag(3):[Report Date].[Week Day].CurrentMember},[Measures].[Count]))
But it's possible, that you don't have empty or senseless days, which is necessary for this calculation! Since it uses .lag(3), and once we try to calculate for the VERY first, second or third weeks, it will take last members from the previous weekday, e.g. to calculate .lag(3) for the Second Wednesday ever (at the beginning of your Date dimension), it will take 2nd Wed, 1st Wed, Last Tue, Pre-last Tue, which is unacceptable, so I've added decreasing lag-level by checking Parent name (since Parent is WeekDay number from the hierarchy we've already created).
Sure thing, you'll use AVG instead of SUM. I used SUM to simplify checking an answer. It's dynamical, not for the very last member only. It depends on current member.
If you have a hierarchy within the date dimension that indicates Day of the Week then you should use it in the sort of circumstance of this question.
Via AdvWrks I wrote the following:
WITH
MEMBER [Measures].[Avg4wkDays] AS
Sum
(
Tail
( --<<find just the past 4
Exists
( --<< find all the days from the past 25 days which have the same day of the week as the current date
Tail
( --<< find the last 25 days prior to each date
NULL : [Date].[Calendar].CurrentMember
,25
)
,Exists
( --<< find the Day of the Week for the currentmember
[Date].[Day of Week].[Day of Week].MEMBERS
,[Date].[Calendar].CurrentMember
)
)
,4
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[Avg4wkDays]
} ON 0
,
[Date].[Calendar].[Date] * [Date].[Day of Week].[Day of Week] ON 1
FROM [Adventure Works]
WHERE
[Date].[Calendar Year].&[2007];
It gives the following which agrees with the requirements: