Come calcolare / memorizzare i primi 10 in un modello tabulare?


23

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' TotalActiveItemsutilizzo 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 factStatstavolo ha FKS alla DevID, CustID, BillDateTimeID, e ParentID. La richiesta che abbiamo è di calcolare o archiviare il Top 10 Parentsper ciascuno in BillDateTimeIDbase 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;

Demo di SQL Fiddle .

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 factStatstabella 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_Rankcolonna 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 factStatstabella memorizzerà il Top10IDvalore 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_Rankin 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?

Risposte:


1

Ho avuto uno scenario simile e ho usato la seguente query DAX ...

Innanzitutto, per semplificare, ho definito una misura da utilizzare all'interno del DAX, quindi non devo ripetere la formula. Quindi ho usato il comando generate per ripetere la formula 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

Con quanto sopra, dovresti avere uno dei 10 ParentID principali e la misura di ogni mese. sostituisci semplicemente "TableInTabular" con il nome della tabella tabulare in cui hai i dati e "DatesTableName" con il nome della tabella delle date.

Per favore fatemi sapere se ho frainteso la vostra domanda e spero che aiuti ...


1
Grazie per la risposta, ci sono ancora alcuni problemi con questo. In primo luogo, posso utilizzarlo all'interno di SSMS ma questo viene distribuito nel nostro modello tabulare in modo che i nostri utenti possano accedervi tramite PowerView - non scriveranno alcuna query - deve solo essere disponibile. In secondo luogo, a meno che non stia facendo qualcosa di sbagliato, non esiste una valutazione o un ordine consentiti nel modello tabulare tramite Visual Studio - nessuna opzione per questo come funzione. In terzo luogo, questa query restituisce solo la Top 10, ho anche bisogno dei dati arrotolati o in qualche modo per ottenerlo. Continuerò a giocarci comunque.
Taryn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.