Eu tenho uma dimensão de data do calendário apoiada por uma tabela física de datas (originalmente criada no SQL Server 2000, portanto, a data e a hora em vez da data):
CREATE TABLE [dbo].[PostDate_Dimension](
[post_date] [datetime] NOT NULL PRIMARY KEY,
[day_of_year] [int] NOT NULL,
[day_of_month] [int] NOT NULL,
[month_of_year] [int] NOT NULL,
[post_year] AS (datepart(year,[post_date])),
[post_month] AS (datepart(month,[post_date])),
[post_day] AS (datepart(day,[post_date]))
)
A dimensão Post Date tem quatro atributos (com colunas de chave de membro listadas, algumas das quais são calculadas no DSV):
- Dia (chave de dimensão) - post_date
- Mês - pós_ano, pós_mês
- Trimestre - pós_ano, pós_trimestre =
DatePart(quarter, "post_date"))
- Ano - post_year
Não é nada muito chique, obviamente. Também tenho algumas medidas calculadas que usam o ParallelPeriod para calcular os valores acumulados no ano do ano anterior, para comparação rápida lado a lado sem exigir que o usuário escolha uma fatia específica de datas. Basta escolher o ano atual e ele encontrará a data mais recente com vendas e comparará com o mesmo intervalo do ano anterior.
Encontrar a data apropriada no ano anterior normalmente se resume a isso:
ParallelPeriod(
[Post Date].[Post Date].[Year],
1,
Tail(
NonEmpty(
Descendants(
[Post Date].CurrentMember,
,
Leaves
),
Measures.[Total Price]
),
1
).Item(0)
)
A chamada Tail é onde encontra a data mais recente abaixo do membro Post Date atualmente selecionado (normalmente o ano atual). Isso funciona bem. Mas se isso retornar 29 de fevereiro, significando que a última venda para uma combinação específica de membros da dimensão ocorreu em 29 de fevereiro, ele passará 29 de fevereiro para a função ParallelPeriod, que subsequentemente retornará nulo. E então a medida YTD do ano anterior também retorna nulo.
Portanto, em poucas palavras: com base nesse esquema específico, existe uma maneira simples de fazer com que o ParallelPeriod se comporte bem para as entradas de 29 de fevereiro? Se retornar apenas em 28 de fevereiro do ano anterior, tudo bem.
EDITAR :
Algumas coisas que tentei:
- Usando esta expressão para ajustar o membro Post Date:
Iif(MONTH([Post Date].[Post Date].CurrentMember.Member_Caption) = 2 And DAY([Post Date].[Post Date].CurrentMember.Member_Caption) = 29, [Post Date].[Post Date].CurrentMember.PREVMEMBER, [Post Date].[Post Date].CurrentMember)
Isso funciona, mas o código seria terrível, pois eu teria que substituir all[Post Date].[Post Date].CurrentMember
porTail(NonEmpty(Descendants([Post Date].CurrentMember,, Leaves), Measures.[Total Price]), 1).Item(0))
. - Usando Except para remover todas as datas de 29 de fevereiro dos resultados de
NonEmpty(Descendants([Post Date].CurrentMember,, Leaves), Measures.[Total Price])
. Não consigo descobrir a sintaxe adequada (se houver) para obter um conjunto de todos os 29 de fevereiro da dimensão. - Criar um assembly .NET com uma função definida pelo usuário que usa um membro como parâmetro e retorna o membro anterior se for 29 de fevereiro. Parece que as classes em Microsoft.AnalysisServices.AdomdServer são extremamente limitadas e nem mesmo permitir esta tarefa básica (nem mesmo recuperar a chave do membro como um valor de data).
Tudo bem, acho que tenho uma solução alternativa com a qual posso viver. Primeiro, criei um conjunto nomeado no cubo, chamado Feb29:
Em seguida, alterei a parte do cálculo que procura a última data de venda (observe o
- Feb29
):Assim, quando procurar a última data de venda em, digamos, 2012, ele ignorará 29 de fevereiro e comparará com as vendas do ano anterior de 1º de janeiro a 28 de fevereiro. Ainda estou aberto a sugestões se houver uma maneira melhor de fazer isso (particularmente aquela terrível expressão de filtro que usei).
Outra opção seria usar uma união para obter períodos paralelos para o membro atual e anterior. Em seguida, extraia o primeiro item disso, que sempre será o membro atual (exceto no caso de 29 de fevereiro, em que deve retornar ao membro anterior).
Ou seja, coalescer efetivamente com o período paralelo do membro anterior conforme abaixo: