Di recente abbiamo creato un modello tabulare SSAS in modo che i nostri utenti possano accedervi tramite PowerView. Abbiamo una misura su una delle nostre tabelle dei fatti per ottenere l' TotalActiveItems
utilizzo di una formula:
TotalActive:=COUNTAX(FILTER('Stats', ISBLANK([DeactDate]) = TRUE), 1)
Funziona alla grande se necessario, ma ora abbiamo una richiesta per ottenere i primi 10 genitori per ogni mese in TotalActive
.
Per riferimento, qui fa parte del nostro modello:
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 con tabelle e dati di esempio.
Il factStats
tavolo ha FKS alla DevID
, CustID
, BillDateTimeID
, e ParentID
. La richiesta che abbiamo è di calcolare o archiviare il Top 10 Parents
per ciascuno in BillDateTimeID
base al TotalActive
AND incluso tutto ciò che non è tra i primi 10 in una categoria arrotolata simile al seguente:
+----------------+------------+------+
| BillDateTimeID | Parent | Rank |
+----------------+------------+------+
| 20140801 | Jim | 1 |
| 20140801 | Bob | 2 |
| 20140801 | All Others | 3 |
+----------------+------------+------+
Posso facilmente farlo in SQL usando le funzioni di windowing ma provare a riprodurlo per SSAS è stato difficile. In SQL, otterremmo il risultato usando:
;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;
Ho provato diversi modi per ottenere il risultato, ma ognuno ha avuto un problema. I miei tentativi sono al di sotto.
Inizialmente, sono stato in grado di ottenere in qualche modo i dati utilizzando una query MDX, ma poi non avevo idea di come incorporarli nel nostro modello tabulare. La query MDX per riferimento è:
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]};
Naturalmente, anche questo mi ha dato il risultato per un solo mese, non tutti i mesi.
Quando mi sono reso conto che la query MDX non funzionava, ho iniziato modificando la nostra factStats
tabella per includere una nuova colonna per contrassegnare gli elementi nella Top 10 e nel valore arrotolato.
alter table factStats
add Top10ParentID INT NOT NULL
constraint DF_factStats default (0);
Il vincolo predefinito fa riferimento al nostro valore "Arrotolato" per la Top 10.
Tentativo n. 1: ho creato la nuova tabella Top 10 per memorizzare ParentID, nome e classifica:
create table dimTop10Parent
(
Top10ParentID INT NOT NULL PRIMARY KEY,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL
);
Questa tabella verrà quindi popolata ogni volta che aggiorniamo il nostro modello con i nuovi 10 principali genitori in base agli articoli Total Active che hanno. La Parent_Rank
colonna viene quindi nascosta nel nostro modello tabulare e utilizzata esclusivamente per l'ordinamento. Funziona benissimo, tranne per il fatto che non abbiamo la possibilità di ottenere storicamente la Top 10 poiché non si basa su base mensile.
Tentativo n. 2: creare una nuova tabella per archiviare la Top 10 ma PRIMARY KEY includerà sia Top10ParentID che BillingDateTimeID.
create table dimTop10Parent
(
Top10ParentID INT NOT NULL,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL,
BillDateTimeID BIGINT NOT NULL
);
Il problema è che non possiamo creare una relazione tra il singolo FK factStats e il PK in due parti nel dimTop10Parent nel modello tabulare.
Tentativo n. 3: creare la nuova tabella ma utilizzare un'identità come 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
);
La factStats
tabella memorizzerà il Top10ID
valore che sarà unico per ogni riga. Ho pensato che questo avrebbe risolto il mio problema, ma non è stato possibile perché non è più possibile ordinare Parent_Rank
in base al modello, genera un errore:
Impossibile ordinare ParentName per Parent_Rank perché almeno un valore in ParentName ha più valori distinti in Parent_Rank. Ad esempio, è possibile ordinare [Città] per [Regione] perché esiste solo una regione per ogni città, ma non è possibile ordinare [Regione] per [Città] perché ci sono più città per ogni regione.
Utilizzando i dati del campione, il risultato finale dovrebbe essere simile a (questo mostra i primi 2 con un terzo arrotolato):
| 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 |
A questo punto, sono in perdita su come ottenere questo risultato finale. Posso modificare le tabelle in base alle necessità per ottenerlo, posso modificare il modello utilizzando una formula, una misura, ecc. Ho letto della classifica utilizzando le formule DAX 1 , 2 , 3 ma non riesco a avvolgere la testa abbastanza per essere in grado di ottenere il risultato con precisione.
Come posso calcolare / archiviare questa Top 10 per qualsiasi mese ed essere ancora in grado di unire i dati secondo necessità nel nostro modello tabulare?