Wie berechne / speichere ich Top 10 in einem tabellarischen Modell?

23

Wir haben kürzlich ein tabellarisches SSAS-Modell erstellt, damit unsere Benutzer über PowerView darauf zugreifen können. Wir haben ein Maß für eine unserer Faktentabellen, um die TotalActiveItemsVerwendung einer Formel zu ermitteln:

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

Das funktioniert nach Bedarf sehr gut, aber jetzt haben wir die Bitte, die Top 10 Eltern für jeden Monat in der Liste zu bekommen TotalActive.

Als referenz, hier ist teil unseres modells:

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 Fiddle mit Tabellen und Beispieldaten.

Die factStatsTabelle hat FKs auf die DevID, CustID, BillDateTimeID, und ParentID. Die Anforderung, die wir haben, besteht darin, die Werte Top 10 Parentsfür jedes ElementBillDateTimeID basierend auf dem TotalActive UND zu berechnen oder zu speichern. Dies umfasst alles, was nicht in den Top 10 enthalten ist, in einer zusammengefassten Kategorie, die der folgenden ähnelt:

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

Ich kann dies in SQL leicht mit Hilfe von Fensterfunktionen erreichen, aber der Versuch, dies für SSAS zu reproduzieren, war schwierig. In SQL erhalten wir das Ergebnis mit:

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

Ich habe verschiedene Wege ausprobiert, um das Ergebnis zu erhalten, aber jeder hatte ein Problem. Meine Versuche sind unten.

Anfangs konnte ich die Daten mit einer MDX-Abfrage etwas abrufen, hatte dann aber keine Ahnung, wie ich sie in unser Tabellenmodell integrieren sollte. Die MDX-Abfrage als Referenz lautet:

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

Natürlich gab mir dies auch nur das Ergebnis für einen einzigen Monat, nicht jeden Monat.

Als ich feststellte, dass die MDX-Abfrage nicht funktionieren würde, änderte ich zunächst unsere factStatsTabelle, um eine neue Spalte einzuschließen, in der die Elemente in den Top 10 und im zusammengefassten Wert gekennzeichnet werden.

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

Die Standardbedingung bezieht sich auf unseren "Aufgerollten" Wert für die Top 10.

Versuch Nr. 1: Ich habe eine neue Top 10-Tabelle erstellt, um die ParentID, den Namen und den Rang zu speichern:

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

Diese Tabelle wird dann jedes Mal ausgefüllt, wenn wir unser Modell mit den neuen Top-10-Eltern aktualisieren, basierend auf den insgesamt aktiven Elementen, die sie haben. Die Parent_RankSpalte wird dann in unserem Tabellenmodell ausgeblendet und ausschließlich zum Sortieren verwendet. Dies funktioniert hervorragend, es sei denn, wir haben nicht die Möglichkeit, die Top 10 in der Vergangenheit zu erreichen, da dies nicht auf monatlicher Basis erfolgt.

Versuch Nr. 2: Erstellen Sie eine neue Tabelle zum Speichern der Top 10, aber der Primärschlüssel enthält sowohl die Top10ParentID als auch eine BillingDateTimeID.

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

Das Problem dabei ist, dass wir im dimTop10Parent im tabellarischen Modell keine Beziehung zwischen den factStats single FK und der zweiteiligen PK erstellen können.

Versuch 3: Erstellen Sie die neue Tabelle, verwenden Sie jedoch eine Identität als 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
);

In der factStatsTabelle wird der Top10IDWert gespeichert, der für jede Zeile eindeutig ist. Ich dachte, dies würde mein Problem lösen, aber es war nicht so, weil wir nicht mehr nach dem Parent_Rankim Modell sortieren können , es wirft einen Fehler auf:

ParentName kann nicht nach Parent_Rank sortiert werden, da mindestens ein Wert in ParentName mehrere unterschiedliche Werte in Parent_Rank enthält. Beispielsweise können Sie [Stadt] nach [Region] sortieren, da es nur eine Region für jede Stadt gibt, Sie können [Region] jedoch nicht nach [Stadt] sortieren, da es für jede Region mehrere Städte gibt.

Unter Verwendung der Beispieldaten sollte das Endresultat ähnlich sein (dies zeigt Top 2 mit einem 3. Rollup):

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

Zu diesem Zeitpunkt bin ich nicht sicher, wie ich dieses Endergebnis erzielen soll. Ich kann die Tabellen nach Bedarf ändern, ich kann das Modell mithilfe einer Formel, eines Maßes usw. ändern. Ich habe gelesen, wie man mit den DAX-Formeln 1 , 2 , 3 rangiert , aber ich kann meinen Kopf nicht umklammern sie genug, um das Ergebnis genau zu erhalten.

Wie kann ich diese Top 10 für einen Monat berechnen / speichern und trotzdem in der Lage sein, die Daten nach Bedarf in unserem tabellarischen Modell zusammenzufügen?

Taryn
quelle

Antworten:

1

Ich hatte ein ähnliches Szenario und habe die folgende DAX-Abfrage verwendet ...

Um es einfach zu machen, habe ich zunächst eine Kennzahl definiert, die im DAX verwendet werden soll, damit ich die Formel nicht wiederholen muss. Dann habe ich den Befehl generate verwendet, um die TOPN-Formel zu durchlaufen:

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

Mit den obigen Angaben sollten Sie bis zu jedem Monat eine Top 10 ParentID und die Kennzahl haben. Ersetzen Sie einfach "TableInTabular" durch Ihren tabellarischen Tabellennamen, in dem Sie die Daten haben, und "DatesTableName" durch den Namen der Datumstabelle.

Bitte lassen Sie mich wissen, wenn ich Ihre Frage falsch verstanden habe und hoffe, dass es hilft ...

Alejandro Pelc
quelle
1
Danke für die Antwort, es gibt noch einige Probleme damit. Erstens kann ich dies in SSMS verwenden, aber dies wird in unserem Tabellenmodell bereitgestellt, damit unsere Benutzer über PowerView darauf zugreifen können - sie schreiben keine Abfragen - dies muss nur verfügbar sein. Zweitens: Sofern ich nichts falsch mache, ist im tabellarischen Modell über Visual Studio keine Bewertung oder Reihenfolge durch zulässig - keine Option für diese Funktion. Drittens gibt diese Abfrage nur die Top 10 zurück. Ich benötige auch die zusammengefassten Daten oder einen Weg, um sie abzurufen. Ich werde trotzdem weiter damit herumspielen.
Taryn