Top X of Top Y with RestOf member where X and Y are hierarchies from different dimensions

对着背影说爱祢 提交于 2019-11-30 09:58:25

问题


This works fine:

WITH 
  SET [AllCountries] AS [Country].[Country].MEMBERS 
  SET [AllStates]    AS [State-Province].[State-Province].MEMBERS 
  SET [Top2States] AS 
    Generate
    (
      [AllCountries]
     ,TopCount
      (
        (EXISTING 
          [AllStates])
       ,3
       ,[Measures].[Internet Order Count]
      )
    ) 
  MEMBER [State-Province].[All].[RestOfCountry] AS 
    Aggregate({(EXISTING {[AllStates]} - [Top2States])}) 
SELECT 
  {[Measures].[Internet Order Count]} ON COLUMNS
 ,{
      [AllCountries]
    * 
      {
        [State-Province].[All]
       ,[Top2States]
       ,[State-Province].[All].[RestOfCountry]
      }
  } ON ROWS
FROM [Adventure Works];

The EXISTING keyword helps a lot .

If the two hierarchies ON ROWS are not from the same dimension, in the way that countries and states are in the above, then we have something like the following:

WITH 
  SET [AllCountries] AS [Country].[Country].MEMBERS 
  SET [AllCats]      AS [Product].[Category].[Category].MEMBERS 
  SET [Top5Cats] AS 
    Generate
    (
      [AllCountries]
     ,TopCount
      (
        (EXISTING 
          [AllCats])
       ,5
       ,[Measures].[Internet Order Count]
      )
    ) 
  MEMBER [Product].[Category].[All].[RestOfProds] AS 
    Aggregate({(EXISTING {[AllCats]} - [Top5Cats])}) 
SELECT 
  {[Measures].[Internet Order Count]} ON COLUMNS
 ,{
      [AllCountries]
    * 
      {
        [Product].[Category].[All]
       ,[Top5Cats]
       ,[Product].[Category].[All].[RestOfCountry]

      }
  } ON ROWS
FROM [Adventure Works];

You can see in the results of the above that the same set of categories are repeated against each country, in the same order i.e. the engine is not finding the topCount per country. EXISTING is now redundant.

How can we adapt the second script above so that it has similar functionality as the top script?


Edit

A better example is the following using Product. It is as if the engine is finding the TopCount for All countries and then putting the same set against each country. I'd like the TopCount for each country:

WITH 
  SET [AllCountries] AS 
    [Country].[Country].MEMBERS 
  SET [AllProds] AS 
    [Product].[Product].[Product].MEMBERS 
  SET [Top5Prods] AS 
    Generate
    (
      [AllCountries]
     ,TopCount
      (
        (EXISTING 
          [AllProds])
       ,5
       ,[Measures].[Internet Order Count]
      )
    ) 
  MEMBER [Product].[Product].[All].[RestOfProds] AS 
    Aggregate({(EXISTING {[AllProds]} - [Top5Prods])}) 
SELECT 
  {[Measures].[Internet Order Count]} ON COLUMNS
 ,NON EMPTY 
    {
        [AllCountries]
      * 
        {
          [Product].[Product].[All]
         ,[Top5Prods]
         ,[Product].[Product].[All].[RestOfProds]
        }
    } ON ROWS
FROM [Adventure Works];

Edit2

This is the latest version via Sourav's ideas - unfortunately the RestOfProds members are not functioning correctly:

WITH 
  SET [AllCountries] AS 
    [Country].[Country].MEMBERS 
  SET [AllProds] AS 
    [Product].[Product].[Product].MEMBERS 
  SET [Top5Prods] AS 
    Generate
    (
      [AllCountries] AS a
     ,
        {
            (
              a.Current
             ,[Product].[Product].[All]
            )
          + 
            //The top x prods
            TopCount
            (
              NonEmpty
              (
                a.Current * [AllProds]
               ,[Measures].[Internet Sales Amount]
              )
             ,5
             ,[Measures].[Internet Sales Amount]
            )
        }
    ) 
  SET [RestOfProds] AS 
    Extract
    (
      {[AllCountries] * [AllProds]} - [Top5Prods]
     ,[Product].[Product]
    ) 
  MEMBER [Product].[Product].[All].[RestOfProds] AS 
    Aggregate([RestOfProds]) 
SELECT 
  {[Measures].[Internet Sales Amount]} ON COLUMNS
 ,{
    [Top5Prods]
   ,
    [AllCountries] * [Product].[Product].[All].[RestOfProds]
  } ON ROWS
FROM [Adventure Works];

Edit3

The following has the correct order so that the member RestOfProds always follows it's respective top 5

WITH 
  SET [AllCountries] AS 
    [Country].[Country].MEMBERS 
  SET [AllProds] AS 
    [Product].[Product].[Product].MEMBERS 
  SET [Top5Prods] AS 
    Generate
    (
      [AllCountries] AS a
     ,{
        //The top x prods
        TopCount
        (
          NonEmpty
          (
            a.Current * [AllProds]
           ,[Measures].[Internet Sales Amount]
          )
         ,5
         ,[Measures].[Internet Sales Amount]
        )
      }
    ) 
  MEMBER [Product].[Product].[All].[RestOfProds] AS 
    Aggregate([Country].CurrentMember * [AllProds] - [Top5Prods]) 
SELECT 
  {[Measures].[Internet Sales Amount]} ON COLUMNS
 ,Generate
  (
    [AllCountries] AS X
   ,
      Order
      (
        Intersect
        (
          X.CurrentMember * [AllProds]
         ,[Top5Prods]
        )
       ,[Measures].[Internet Sales Amount]
       ,bdesc
      )
    + 
      {X.CurrentMember * {[Product].[Product].[All].[RestOfProds]}}
  ) ON ROWS
FROM [Adventure Works];

Edit4

The following has the correct order so that the member RestOfProds always follows it's respective top 5 + I've added a further set on rows:

WITH 
  SET [2months] AS 
    {
      [Date].[Calendar].[Month].&[2007]&[9]
     ,[Date].[Calendar].[Month].&[2007]&[10]
    } 
  SET [AllCountries] AS 
    [Country].[Country].MEMBERS 
  SET [MthsCountries] AS 
    [2months] * [AllCountries] 
  SET [AllProds] AS 
    [Product].[Product].[Product].MEMBERS 
  SET [Top5Prods] AS 
    Generate
    (
      [MthsCountries] AS A
     ,{
        //The top x prods
        TopCount
        (
          NonEmpty
          (
            A.Current * [AllProds]
           ,[Measures].[Internet Sales Amount]
          )
         ,5
         ,[Measures].[Internet Sales Amount]
        )
      }
    ) 
  MEMBER [Product].[Product].[All].[RestOfProds] AS 
    Aggregate
    (
        ([Date].[Calendar].CurrentMember,[Country].CurrentMember) * [AllProds]
      - 
        [Top5Prods]
    ) 
SELECT 
  {[Measures].[Internet Sales Amount]} ON COLUMNS
 ,Generate
  (
    [MthsCountries] AS X
   ,
      Order
      (
        Intersect
        (
          X.Current * [AllProds]
         ,[Top5Prods]
        )
       ,[Measures].[Internet Sales Amount]
       ,bdesc
      )
    + 
      {X.Current * {[Product].[Product].[All].[RestOfProds]}}
  ) ON ROWS
FROM [Adventure Works];

回答1:


EXISTING when used on named sets, doesn't really make a difference since named sets are created before the axes members are laid out. In your case, GENERATE is really just creating static sets and then on the axes everything is just cross joined.

To get the TopCount script working, you need to handle all the cross joins inside one set so that everything is evaluated together. I am not sure, but you might try the below:

WITH 
  SET [AllCountries] AS [Country].[Country].MEMBERS 
  SET [AllCats]    AS [Product].[Category].[Category].MEMBERS 
  SET [Top5Cats] AS 
    Generate
    (
      [AllCountries] as a
     ,
     {
     (a.current , [Product].[Category].[All] ) //The ALL member
     +   
     TopCount  //The top 2 categories
      (
        NonEmpty((a.current * [AllCats] ) , (a.CURRENT, [Measures].[Internet Order Count]))
       ,2
       ,[Measures].[Internet Order Count]      
      ) 
      }
    + 
    { //The rest of the members
    a.current * [AllCats] 
    - 
    a.current *{     
     TopCount
      (
        NonEmpty([AllCats] , (a.CURRENT, [Measures].[Internet Order Count]))
       ,2
       ,[Measures].[Internet Order Count]      
      ) 
      }
      }
    )

  MEMBER [Product].[Category].[All].[RestOfProds] AS 
    Aggregate({(EXISTING {[AllCats]} - [Top5Cats])}) 

SELECT 
  {[Measures].[Internet Order Count]} ON COLUMNS,
[Top5Cats] ON ROWS
FROM [Adventure Works];

EDIT: If you need the RestOfCats member, you can add this code.

SET [RestOfCats] AS
EXTRACT
    (
     {
     [AllCountries] * [AllCats] 
     - 
     [Top5Cats]
     },
     [Product].[Category]
    )

MEMBER [Product].[Category].[All].[RestOfCats] AS
Aggregate([RestOfCats])

EDIT 2

Continuing on your example, removing the 'All' member additionally in the definition.

  SET [RestOfProds] AS 
    Extract
    (
      {[AllCountries] * [AllProds]} - [Top5Prods] - [AllCountries]*[Product].[Product].[All]
     ,[Product].[Product]
    ) 



回答2:


If you are crossjoining multiple hierarchies in the same dimension only valid combinations will be shown. This is called auto-exists and it explains why the first query works like you want.

When crossjoining hierarchies from different dimensions the auto-exists does not happen. I think this explains the odd combinations returned in the second query.

Try adding NON EMPTY at the beginning of your ON ROWS definition. Then it will only return combinations which have an Internet Order Count measure value (whatever measures are on columns). That's the proper way to limit the crossjoin.

If you don't want a NON EMPTY on Internet Order Count then so you need a NonEmpty(, [Measures].[A Different Measure]) on a different measure?

Edit: It looks like the issue is not related to auto-exists but is related to performing a different TopCount per country. So this info may help someone else but isn't the answer to this question.




回答3:


This seems to work ok:

WITH 
  SET [AllCountries] AS 
    [Country].[Country].MEMBERS 
  SET [AllProds] AS 
    [Product].[Product].[Product].MEMBERS 
  SET [Top5Prods] AS 
    Generate
    (
      [AllCountries] AS a
     ,{
          (
            a.CurrentMember
           ,[Product].[Product].[All]
          )
        + 
            //The top x prods
            a.CurrentMember
          * 
            TopCount
            (
              [AllProds]
             ,5
             ,[Measures].[Internet Sales Amount]
            )
      }
    ) 
  MEMBER [Product].[Product].[All].[Other Products] AS 
    Aggregate
    (
        [Country].CurrentMember * [Product].[Product].[Product].MEMBERS
      - 
        [Top5Prods]
    ) 
SELECT 
  {[Measures].[Internet Sales Amount]} ON COLUMNS
 ,Hierarchize(
    {
     [Top5Prods]
    ,[AllCountries] * [Product].[Product].[All].[Other Products]
    }
) ON ROWS
FROM [Adventure Works];


来源:https://stackoverflow.com/questions/33485982/top-x-of-top-y-with-restof-member-where-x-and-y-are-hierarchies-from-different-d

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!