Recientemente hemos creado un modelo tabular SSAS para que nuestros usuarios puedan acceder a él a través de PowerView. Tenemos una medida en una de nuestras tablas de hechos para TotalActiveItems
usar una fórmula:
TotalActive:=COUNTAX(FILTER('Stats', ISBLANK([DeactDate]) = TRUE), 1)
Esto funciona muy bien según sea necesario, pero ahora tenemos una solicitud para obtener los 10 mejores padres para cada mes en el TotalActive
.
Como referencia, aquí es parte de nuestro modelo:
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 tablas y datos de muestra.
La factStats
tabla tiene al FKs DevID
, CustID
, BillDateTimeID
, y ParentID
. La solicitud que tenemos es calcular o almacenar Top 10 Parents
cada uno en BillDateTimeID
función del TotalActive
AND e incluir todo lo que no esté en el Top 10 en una categoría acumulada similar a la siguiente:
+----------------+------------+------+
| BillDateTimeID | Parent | Rank |
+----------------+------------+------+
| 20140801 | Jim | 1 |
| 20140801 | Bob | 2 |
| 20140801 | All Others | 3 |
+----------------+------------+------+
Puedo lograr esto fácilmente en SQL usando las funciones de ventanas, pero tratar de reproducir esto para SSAS ha sido difícil. En SQL, obtendríamos el resultado 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;
He intentado varias formas diferentes de obtener el resultado, pero cada una ha tenido un problema. Mis intentos están abajo.
Inicialmente, pude obtener los datos utilizando una consulta MDX, pero luego no tenía idea de cómo incorporar esto en nuestro modelo tabular. La consulta MDX para referencia es:
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]};
Por supuesto, esto también solo me dio el resultado para un solo mes, no todos los meses.
Cuando me di cuenta de que la consulta MDX no funcionaría, comencé alterando nuestra factStats
tabla para incluir una nueva columna para marcar los elementos en el Top 10 y en el valor acumulado.
alter table factStats
add Top10ParentID INT NOT NULL
constraint DF_factStats default (0);
La restricción predeterminada hace referencia a nuestro valor "enrollado" para los 10 principales.
Intento n. ° 1: creé una nueva tabla Top 10 para almacenar el ParentID, el nombre y el Rango:
create table dimTop10Parent
(
Top10ParentID INT NOT NULL PRIMARY KEY,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL
);
Esta tabla se completará cada vez que refresquemos nuestro modelo con los nuevos 10 padres principales en función de los elementos activos totales que tengan. La Parent_Rank
columna se oculta en nuestro modelo tabular y se usa exclusivamente para ordenar. Esto funciona muy bien, excepto que históricamente no tenemos la capacidad de obtener el Top 10 ya que no se basa en una base mensual.
Intento n. ° 2: cree una nueva tabla para almacenar los 10 principales, pero la CLAVE PRIMARIA incluirá tanto el Top10ParentID como el BillingDateTimeID.
create table dimTop10Parent
(
Top10ParentID INT NOT NULL,
ParentName varchar(100) NOT NULL,
Parent_Rank INT NOT NULL,
BillDateTimeID BIGINT NOT NULL
);
El problema con esto es que no podemos crear una relación entre el factStats FK único con la PK de dos partes en dimTop10Parent en el modelo tabular.
Intento n. ° 3: cree la nueva tabla pero use una identidad como 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
tabla almacenará el Top10ID
valor que será único para cada fila. Pensé que esto resolvería mi problema, pero no lo hizo porque ya no podemos ordenar por Parent_Rank
en el modelo, arroja un error:
No se puede ordenar ParentName por Parent_Rank porque al menos un valor en ParentName tiene varios valores distintos en Parent_Rank. Por ejemplo, puede ordenar [Ciudad] por [Región] porque solo hay una región para cada ciudad, pero no puede ordenar [Región] por [Ciudad] porque hay varias ciudades para cada región.
Usando los datos de la muestra, el resultado final debe ser similar a (esto muestra el Top 2 con un 3er enrollado):
| 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 |
En este punto, no sé cómo obtener este resultado final. Puedo alterar las tablas según sea necesario para obtenerlo, puedo alterar el modelo usando una fórmula, medida, etc. He leído sobre la clasificación usando las fórmulas DAX 1 , 2 , 3 pero parece que no puedo entenderlo. lo suficiente como para poder obtener el resultado con precisión.
¿Cómo puedo calcular / almacenar este Top 10 para cualquier mes y aún así poder empalmar los datos según sea necesario en nuestro modelo tabular?
fuente