是否可以编写 "last x days of days of week" 格式的 MDX 查询?

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

这是一份大量手动维护的报告,我正在尝试自动执行 SSAS 多维数据集的位视图。

该报告包含每日销售额,除此之外,还有一个名为 "last 4 's" 的度量。例如,对于 10 月 16 日星期五,衡量指标是过去 4 个星期五的平均销售额。

有没有一种方法可以在 MDX 中以可以放置在 SSAS 多维数据集中的计算度量中的方式构建它?


ps--针对whytheq的问题,是的,日期维度包括星期几,它是一个整数,其中Sun = 1,Mon = 2等等到Sat = 7。


我看我上面说的有点含糊。上面的 "last 4 Fridays" 是指 10 月 16 日之前的 4 个星期五,而不是最近的 4 个星期五。

同意 whytheq,更多信息可能有助于我们创建最佳解决方案。不管怎样:

如果您只有平日层次结构,则已解决:

+All
-2015/01/01
-2015/01/02
...
-2015/12/31
...

逻辑可能是这样的:

  1. 全天排名

  2. 按周拆分

  3. 计算每天类型的最后 4 个

  4. 显示每个选定成员的结果

平面层次结构示例[报告日期].[报告日期].[日]计算:

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]

结果(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

如果你有周层次结构或一些属性(不是计算天数),会更容易。

UPDATE(存在每周属性):

这是几周的脚本,但请先创建 weekday->day 层级,例如:

All
+1
-2015/01/01
-2015/01/08
...
+2
-2015/01/02
-2015/01/09
...

代码中有代码技巧,我将进一步解释:

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测量仅供查看结果,计算时不需要。

要计算的确切代码非常简单:sum({[Report Date].[Week Day].CurrentMember.Lag(3):[Report Date].[Week Day].CurrentMember},[Measures].[Count]))

但是您可能没有空虚或无意义的日子,而这对于此计算是必需的!因为它使用 .lag(3),一旦我们尝试计算非常第一、第二或第三周,它将需要前一个工作日的最后一个成员,例如计算有史以来第二个星期三的 .lag(3)(在日期维度的开头),需要第二个星期三、第一个星期三、最后一个星期二、最后一个星期二之前,这是不可接受的,所以我增加了递减延迟- 通过检查父级名称(因为父级是我们已经创建的层次结构中的工作日编号)。

没问题,您将使用 AVG 而不是 SUM。我使用 SUM 来简化检查答案。它是动态的,不仅仅针对最后一个成员。这取决于当前成员。

如果您在日期维度中有一个指示星期几的层次结构,那么您应该在这种问题的情况下使用它。

通过AdvWrks我写了以下内容:

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];

给出符合要求的如下: