Nous avons récemment créé un modèle tabulaire SSAS afin que nos utilisateurs puissent y accéder via PowerView. Nous avons une mesure sur l'une de nos tables de faits pour obtenir l' TotalActiveItems
aide d'une formule:
TotalActive:=COUNTAX(FILTER('Stats', ISBLANK([DeactDate]) = TRUE), 1)
Cela fonctionne très bien au besoin, mais nous avons maintenant une demande pour obtenir les 10 meilleurs parents pour chaque mois dans le TotalActive
.
Pour référence, voici une partie de notre modèle:
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 avec des tables et des exemples de données.
La factStats
table a FKs au DevID
, CustID
, BillDateTimeID
et ParentID
. La demande que nous avons est de calculer ou de stocker le Top 10 Parents
pour chacun en BillDateTimeID
fonction du TotalActive
ET et d' inclure tout ce qui n'est pas dans le Top 10 dans une catégorie cumulée similaire à la suivante:
+----------------+------------+------+
| BillDateTimeID | Parent | Rank |
+----------------+------------+------+
| 20140801 | Jim | 1 |
| 20140801 | Bob | 2 |
| 20140801 | All Others | 3 |
+----------------+------------+------+
Je peux facilement accomplir cela en SQL en utilisant des fonctions de fenêtrage mais essayer de reproduire cela pour SSAS a été difficile. En SQL, nous obtenions le résultat en utilisant:
;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;
J'ai essayé plusieurs façons d'obtenir le résultat, mais chacune a eu un problème. Mes tentatives sont ci-dessous.
Initialement, j'ai pu obtenir un peu les données à l'aide d'une requête MDX, mais je n'avais aucune idée de la façon de l'incorporer dans notre modèle tabulaire. La requête MDX pour référence est:
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]};
Bien sûr, cela ne m'a également donné le résultat que pour un seul mois, pas tous les mois.
Quand j'ai réalisé que la requête MDX ne fonctionnerait pas, j'ai commencé par modifier notre factStats
table pour inclure une nouvelle colonne pour marquer les éléments dans le Top 10 et dans la valeur cumulée.
alter table factStats
add Top10ParentID INT NOT NULL
constraint DF_factStats default (0);
La contrainte par défaut fait référence à notre valeur "Rolled Up" pour le Top 10.
Tentative n ° 1: j'ai créé une nouvelle table Top 10 pour stocker le ParentID, le nom et le rang:
create table dimTop10Parent
(
Top10ParentID INT NOT NULL PRIMARY KEY,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL
);
Ce tableau sera ensuite rempli chaque fois que nous actualiserons notre modèle avec les nouveaux 10 meilleurs parents en fonction du nombre total d'éléments actifs dont ils disposent. La Parent_Rank
colonne est ensuite masquée dans notre modèle tabulaire et utilisée exclusivement pour le tri. Cela fonctionne très bien, sauf que nous n'avons pas la possibilité d'obtenir historiquement le Top 10 car il n'est pas basé sur un mois en mois.
Tentative n ° 2: créez une nouvelle table pour stocker le Top 10, mais la PRIMARY KEY inclura à la fois le Top10ParentID et le BillingDateTimeID.
create table dimTop10Parent
(
Top10ParentID INT NOT NULL,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL,
BillDateTimeID BIGINT NOT NULL
);
Le problème avec cela est que nous ne pouvons pas créer une relation entre le FK unique factStats et le PK en deux parties dans le dimTop10Parent dans le modèle tabulaire.
Tentative n ° 3: créez la nouvelle table mais utilisez une identité comme 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
);
Le factStats
tableau stockera la Top10ID
valeur qui sera unique pour chaque ligne. Je pensais que cela résoudrait mon problème, mais ce n'est pas le cas car nous ne pouvons plus trier par Parent_Rank
dans le modèle, cela génère une erreur:
Impossible de trier ParentName par Parent_Rank car au moins une valeur dans ParentName a plusieurs valeurs distinctes dans Parent_Rank. Par exemple, vous pouvez trier [Ville] par [Région] car il n'y a qu'une seule région pour chaque ville, mais vous ne pouvez pas trier [Région] par [Ville] car il y a plusieurs villes pour chaque région.
En utilisant les données de l'échantillon, le résultat final devrait être similaire à (cela montre le Top 2 avec un 3e enroulé):
| 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 |
À ce stade, je ne sais pas comment obtenir ce résultat final. Je peux modifier les tables au besoin pour l' obtenir, je peux modifier le modèle en utilisant une formule, mesure, etc. J'ai lu sur le classement à l' aide DAX formules 1 , 2 , 3 , mais je ne peux pas sembler ma tête envelopper suffisamment pour pouvoir obtenir le résultat avec précision.
Comment puis-je calculer / stocker ce Top 10 pour n'importe quel mois et être toujours en mesure d'épisser les données selon les besoins dans notre modèle tabulaire?