web-dev-qa-db-ja.com

表形式モデルでトップ10を計算/保存する方法は?

ユーザーがPowerView経由でアクセスできるように、最近SSAS表形式モデルを作成しました。数式を使用してTotalActiveItemsを取得するために、ファクトテーブルの1つにメジャーがあります。

_TotalActive:=COUNTAX(FILTER('Stats', ISBLANK([DeactDate]) = TRUE), 1)
_

これは必要に応じて適切に機能しますが、TotalActiveで毎月の上位10親を取得するように要求されます。

参考までに、ここにモデルの一部を示します。

_create table factStats
(
    StatsID INT IDENTITY NOT NULL PRIMARY KEY,
    DevID INT NOT NULL,
    DeactDate DATETIME NULL,
    BillDateTimeID BIGINT NOT NULL,
    CustID INT NOT NULL,
    ParentID INT NOT NULL
);

create table dimCust
(
    CustID INT NOT NULL PRIMARY KEY,
    CustName varchar(150) NOT NULL
);

create table dimParent
(
    ParentID INT NOT NULL PRIMARY KEY,
    ParentName varchar(100) NOT NULL
);

create table dimDateTime
(
    DateTimeID BIGINT NOT NULL PRIMARY KEY
);
_

SQLフィドル テーブルとサンプルデータ。

factStatsテーブルには、DevIDCustIDBillDateTimeID、およびParentIDへのFKがあります。私たちが持っている要求は、BillDateTimeIDに基づいて各TotalActiveの_Top 10 Parents_を計算または保存することです[〜#〜]および[〜#〜]次のようなロールアップカテゴリのトップ10に含まれます。

_+----------------+------------+------+
| BillDateTimeID |   Parent   | Rank |
+----------------+------------+------+
|       20140801 | Jim        |    1 |
|       20140801 | Bob        |    2 |
|       20140801 | All Others |    3 |
+----------------+------------+------+
_

ウィンドウ関数を使用してSQLでこれを簡単に実現できますが、SSASでこれを再現するのは困難でした。 SQLでは、次を使用して結果を取得します。

_;with Total as
(
  select 
    ParentID,
    BillDateTimeID,
    sum(case when DeactDate is null then 1 else 0 end) TotalActive
  from factStats
  group by ParentID, BillDateTimeID
),
PRank as
(
  select 
    ParentID,
    BillDateTimeID,
    TotalActive,
    row_number() over(partition by BillDateTimeID 
                      order by TotalActive desc) pr
  from total
)
select 
  parentid,
  BillDateTimeID,
  TotalActive,
  pr
from prank
where pr <= 2
union all
select 
  0,
  BillDateTimeID,
  sum(TotalActive) TotalActive,
  3
from prank
where pr > 2
group by BillDateTimeID
order by BillDateTimeID desc, pr;
_

SQL Fiddle Demo

結果を得るためにいくつかの方法を試しましたが、それぞれに問題がありました。私の試みは以下です。

最初は、MDXクエリを使用してデータをいくらか取得できましたが、これを表形式モデルに組み込む方法がわかりませんでした。参照用のMDXクエリは次のとおりです。

_with 
set [Top10Parent] AS
(
    (TOPCOUNT({ORDER(({[Parent].[Parent Name].[Parent Name]}),
        ([Measures].[Total Count]), BDESC)}, 10))
)
MEMBER [Parent].[Parent Name].[Others] AS
(
    AGGREGATE(EXCEPT([Parent].[Parent Name].[Parent Name], [Top10Parent]))
)
select 
    [Measures].[Total Count] on columns,
    {[Top10Parent]}+ {[Parent].[Parent Name].[Others]} on Rows
from [OurModel]
where {[Date and Time].[Month and Year].[Month and Year].[Jul 2014]};
_

もちろん、これにより、毎月ではなく、1か月分の結果しか得られませんでした。

MDXクエリが機能しないことに気付いたとき、最初にfactStatsテーブルを変更して、新しい列を含め、上位10件とロールアップされた値のアイテムにフラグを立てることから始めました。

_alter table factStats
    add Top10ParentID INT NOT NULL
    constraint DF_factStats default (0);
_

デフォルトの制約は、トップ10の「ロールアップ」値を参照します。

試行#1:ParentID、名前、およびランクを保存するために、新しいトップ10テーブルを作成しました。

_create table dimTop10Parent
(
    Top10ParentID INT NOT NULL PRIMARY KEY,
    ParentName varchar(100) NOT NULL,
    Parent_Rank INT NOT NULL
);
_

その後、このテーブルは、アクティブなアイテムの総数に基づいて新しい上位10の親でモデルを更新するたびに入力されます。その後、_Parent_Rank_列が表モデルで非表示になり、並べ替え専用に使用されます。これは非常に効果的ですが、月ごとに基づいていないため、過去にトップ10に到達する能力がないことを除けば。

試行#2:トップ10を格納する新しいテーブルを作成しますが、PRIMARY KEYにはTop10ParentIDとBillingDateTimeIDの両方が含まれます。

_create table dimTop10Parent
(
    Top10ParentID INT NOT NULL,
    ParentName varchar(100) NOT NULL,
    Parent_Rank INT NOT NULL,
    BillDateTimeID BIGINT NOT NULL
);
_

この問題は、テーブルモデルのdimTop10Parentで、factStats単一FKと2つの部分PKの間に関係を作成できないことです。

試行#3:新しいテーブルを作成しますが、IDをPKとして使用します。

_create table dimTop10Parent
(
    Top10ID INT IDENTITY NOT NULL PRIMARY KEY,
    Top10ParentID INT NOT NULL,
    ParentName varchar(100) NOT NULL,
    Parent_Rank INT NOT NULL,
    BillDateTimeID BIGINT NOT NULL
);
_

factStatsテーブルには、各行で一意の_Top10ID_値が格納されます。これで問題が解決すると思っていましたが、モデルの_Parent_Rank_で並べ替えることができなくなったため、エラーは発生しませんでした。

ParentNameの少なくとも1つの値がParent_Rankに複数の異なる値を持つため、ParentNameをParent_Rankで並べ替えることはできません。たとえば、各都市には1つの地域しかないため、[City]を[Region]で並べ替えることができますが、各地域に複数の都市があるため、[Region]を[City]で並べ替えることはできません。

サンプルデータを使用すると、最終結果は次のようになります(これは、トップ3がロールアップされたトップ2を示しています)。

_| PARENTNAME | BILLDATETIMEID | TOTALACTIVE | PR |
|------------|----------------|-------------|----|
|     FDN    |   201408010000 |          11 |  1 |
|     FDO    |   201408010000 |           3 |  2 |
| All Others |   201408010000 |           5 |  3 |
|     FDN    |   201407010000 |          12 |  1 |
|     EVOD   |   201407010000 |           2 |  2 |
| All Others |   201407010000 |           5 |  3 |
_

この時点で、私はこの最終結果を得る方法に途方に暮れています。必要に応じてテーブルを変更したり、数式やメジャーを使用してモデルを変更したりできます。DAX数式を使用したランキングについて読みました 12 しかし、私は正確に結果を得ることができるほど頭を彼らの周りに巻きつけるようには見えません。

このトップ10を任意の月で計算/保存し、必要に応じて表形式モデルでデータをつなぎ合わせるにはどうすればよいですか?

23
Taryn

同様のシナリオがあり、次のDAXクエリを使用しました...

まず、簡単にするために、DAX内で使用するメジャーを定義したので、数式を繰り返す必要がありません。次に、generateを使用してTOPN数式を反復処理します。

define measure TableInTabular[NameOfTheMeasure] = COUNTAX(FILTER('Stats', ISBLANK([DeactDate]) = TRUE), 1)
evaluate
 (
  addcolumns
   (  
    filter
     (  
      generate
        (  
         VALUES(DatesTableName[Month]),  
         TOPN (10, VALUES(TableInTabular[ParentID]),TableInTabular[NameOfTheMeasure],0)
        ),
        TableInTabular[NameOfTheMeasure]>0
      ),
      "ActiveCount (or how you want to call this Column)",
      TableInTabular[NameOfTheMeasure]  
    )  
 )  
order by DatesTableName[Month] asc, 
TableInTabular[NameOfTheMeasure] desc

上記の場合、毎月の上位10のParentIDとメジャーが必要です。 "TableInTabular"をデータがある表形式のテーブル名に、 "DatesTableName"を日付テーブルの名前に置き換えてください。

私があなたの質問を誤解しているかどうか教えてください、それが役に立てば幸いです...

1
Alejandro Pelc