Guia Avançado · Parte 2 de 2

Set Analysis Avançado

Comparações de período (YTD, LY, Rolling 12M), Set Analysis indireto via variáveis, aninhamento e os padrões mais complexos usados em dashboards enterprise.

YTD, LY, Rolling 12M - tudo com uma expressão Set Analysis.
YTDYear to Date
LYLast Year
R12MRolling 12 Months
%YoYGrowth YoY
scroll para explorar

1. Comparações de Período - YTD, LY e Rolling 12M

Comparações de período são o caso de uso mais frequente em dashboards executivos. O segredo está em combinar modificadores de Ano e Mês com dollar-sign expansion para criar expressões que funcionam independente do período selecionado pelo usuário.

YTD
Year to Date - Do Início do Ano até Hoje

YTD representa a acumulação do início do ano corrente até o mês mais recente disponível nos dados (ou até hoje). A chave é não hardcodar o ano - usar expressão dinâmica.


// YTD simples - ignora todas as seleções de período
Sum({
  <Ano={$(=Year(Today()))},
   Mes={"<=$(=Month(Today()))"}>
} Valor)

// YTD respeitando outras seleções (ex.: Região, Produto selecionados)
// mas ignorando seleção de Ano e Mês do usuário
Sum({
  $<Ano={$(=Year(Today()))},
    Mes={"<=$(=Month(Today()))"}>
} Valor)

// YTD usando campo Data diretamente (mais preciso)
Sum({
  <Data={">=$(=YearStart(Today()))<=$(=Today())"}>
} Valor)

// YTD com seleção do usuário respeitada para outros campos:
Sum({
  $<Data={">=$(=YearStart(Today()))<=$(=Today())"}>
} Valor)
LY
Last Year - Mesmo Período do Ano Anterior

LY (Last Year) precisa corresponder exatamente ao mesmo período do YTD, mas um ano antes. A expressão deve ser consistente: se o YTD vai até junho de 2025, o LY deve ir até junho de 2024.


// LY YTD - acumulado do ano anterior até o mesmo mês
Sum({
  <Ano={$(=Year(Today())-1)},
   Mes={"<=$(=Month(Today()))"}>
} Valor)

// LY com campo Data - exatamente o mesmo intervalo 1 ano atrás
Sum({
  <Data={">=$(=AddYears(YearStart(Today()),-1))<=$(=AddYears(Today(),-1))"}>
} Valor)

// Variação percentual YoY - crescimento ano a ano
(
  Sum({$<Ano={$(=Year(Today()))},Mes={"<=$(=Month(Today()))}"}>} Valor)
  /
  Sum({$<Ano={$(=Year(Today())-1)},Mes={"<=$(=Month(Today()))}"}>} Valor)
) - 1
// Formatar como percentual: num(expressao, '#0.0%')

// Comparação mês a mês (MTD vs MTD anterior)
// Mês atual:
Sum({<Ano={$(=Year(Today()))},Mes={$(=Month(Today()))}>} Valor)
// Mês anterior:
Sum({<Ano={$(=Year(AddMonths(Today(),-1)))},Mes={$(=Month(AddMonths(Today(),-1)))}>} Valor)
R12
Rolling 12 Months - Janela Móvel de 12 Meses

Rolling 12M é diferente de YTD: enquanto o YTD sempre começa em 1 de janeiro, o Rolling 12M é uma janela que desliza - cobre os 12 meses anteriores à data atual independente do ano. Elimina sazonalidade e permite comparações contínuas.


// Rolling 12M usando campo Data
Sum({
  <Data={">=$(=AddMonths(Today(),-12))<=$(=Today())"}>
} Valor)

// Rolling 12M using Ano + Mes fields (common pattern)
// Requires a numeric representation: AnoMes = Year*100 + Month
Sum({
  <AnoMes={">=$(=Year(AddMonths(Today(),-12))*100+Month(AddMonths(Today(),-12)))
            <=$(=Year(Today())*100+Month(Today()))"}>
} Valor)

// Comparação Rolling 12M atual vs Rolling 12M anterior
// (janela de 12M que terminou 12 meses atrás)
// Período atual (R12M):
Sum({<Data={">=$(=AddMonths(Today(),-12))<=$(=Today())"}>} Valor)
// Período anterior (R12M -1 ano):
Sum({<Data={">=$(=AddMonths(Today(),-24))<=$(=AddMonths(Today(),-12))"}>} Valor)

Padrão avançado: nunca hardcode anos ou meses em expressões de período. Uma expressão com Ano={2024} envelhece e fica errada. Uma expressão com Ano={$(=Year(Today()))} funciona para sempre.

Comparação de Trimestres - QTD


// QTD - Quarter to Date (acumulado do trimestre atual)
Sum({
  <Data={">=$(=QuarterStart(Today()))<=$(=Today())"}>
} Valor)

// Trimestre anterior completo
Sum({
  <Data={">=$(=QuarterStart(AddMonths(Today(),-3)))<=$(=QuarterEnd(AddMonths(Today(),-3)))"}>
} Valor)

// Mesmo trimestre do ano anterior (para comparar Q2 2025 vs Q2 2024)
Sum({
  <Data={">=$(=AddYears(QuarterStart(Today()),-1))<=$(=AddYears(QuarterEnd(Today()),-1))"}>
} Valor)

2. Set Analysis Indireto - Controle via Variáveis

Set Analysis indireto é o padrão onde o conteúdo do conjunto é definido por variáveis - e essas variáveis podem ser alteradas pelo próprio usuário via input boxes ou botões. Transforma um dashboard estático em um sistema de análise configurável sem alterar uma linha de expressão.

Arquitetura do Set Analysis Indireto

A ideia é separar a lógica de filtro da expressão de cálculo. A variável funciona como uma "chave" que define o comportamento do conjunto - e o desenvolvedor ou o próprio usuário controla essa chave.

// Configuração no script (ou inline)
// Variáveis de período - configuráveis pelo usuário via input box
SET vAnoComparacao = 2023;   // usuário pode alterar para 2022, 2021 etc
SET vMesInicio     = 1;       // início do intervalo de análise
SET vMesFim        = 6;       // fim do intervalo de análise

// Variáveis de filtro de negócio
SET vSegmento     = 'Enterprise';
SET vRegiaoFoco   = 'Sul,Sudeste';  // múltiplos valores

// Na expressão - usa as variáveis:
Sum({
  <Ano={$(#vAnoComparacao)},
   Mes={">=$(#vMesInicio)<=$(#vMesFim)"}>
} Valor)

// A expressão funciona para qualquer configuração de variável.
// Alterar vAnoComparacao de 2023 para 2021
// muda imediatamente o resultado sem editar a expressão.

Pattern: Toggle de Modo de Análise

Um padrão elegante é criar uma variável que seleciona o "modo" de análise - e as expressões respondem a esse modo automaticamente.


// Variável de modo (definida via botão ou input box pelo usuário)
// vModo = 'YTD' | 'LY' | 'R12M'
SET vModo = 'YTD';

// Expressão que responde ao modo:
// (usando If() no NÍVEL DA EXPRESSÃO - não dentro da aggregation!)
If(vModo = 'YTD',
   Sum({<Data={">=$(=YearStart(Today()))<=$(=Today())"}>} Valor),
If(vModo = 'LY',
   Sum({<Data={">=$(=AddYears(YearStart(Today()),-1))<=$(=AddYears(Today(),-1))"}>} Valor),
   Sum({<Data={">=$(=AddMonths(Today(),-12))<=$(=Today())"}>} Valor)
))

// IMPORTANTE: o If() aqui está FORA do Sum() - ele escolre qual Sum() calcular.
// Isso é diferente de Sum(If(...)) que é lento.
// Este padrão é eficiente: apenas uma das expressões é avaliada.

Variável como Set Analysis Completo - Reutilização Máxima


// Definir o filtro completo como variável:
// (Aspas simples duplicadas para escapar dentro da string)
SET vFiltroVIP       = '{<SegmentoCliente={''VIP''}>}';
SET vFiltroEletro    = '{<Categoria={''Eletrônicos''}>}';
SET vFiltroQ1Atual   = '{<Trimestre={''Q1''},Ano={$(=Year(Today()))}>}';

// Uso em qualquer expressão do app:
Sum($(vFiltroVIP) Valor)
Count($(vFiltroVIP) DISTINCT ClienteID)
Avg($(vFiltroEletro) TicketMedio)

// Combinando variáveis (intersecção):
// VIP E Eletrônicos
Sum($(vFiltroVIP) $(vFiltroEletro) Valor)
// Expande para: Sum({<SegmentoCliente={'VIP'}>} {<Categoria={'Eletrônicos'}>} Valor)
// Qlik interpreta múltiplos modificadores como intersecção (AND)

Cuidado com aspas: dentro de um SET em script, aspas simples dentro de strings precisam ser duplicadas. SET v = "{'VIP'}" é inválido. O correto é SET v = "{''VIP''}". Verifique sempre no console de debug do Qlik antes de ir para produção.

3. Aninhamento - Set Analysis dentro de Set Analysis

Set Analysis aninhado ocorre quando o modificador de um conjunto é determinado por outro conjunto. É o nível mais avançado de Set Analysis - e o padrão que responde a perguntas de negócio que seriam impossíveis de outra forma.

N1
Aninhamento Básico - P() dentro de Modificador

O padrão mais comum de aninhamento: usar P() com um conjunto interno para definir o modificador de um conjunto externo. Vimos isso brevemente na Parte 1 - agora em profundidade.


// Pergunta: "quais são as vendas dos produtos que
//            tiveram pelo menos 1 venda no mês anterior?"
// Sem aninhamento: impossível sem join no script.

Sum({
  <ProdutoID = P({1}<Mes={$(=Month(AddMonths(Today(),-1)))},
                    Ano={$(=Year(AddMonths(Today(),-1)))}> ProdutoID)>
} Valor)

// Leitura:
// P({1}<Mes=MesAnterior, Ano=AnoAnterior> ProdutoID)
//   → conjunto de ProdutoIDs que venderam no mês anterior
// <ProdutoID = [esse conjunto]>
//   → filtra os dados para esses produtos
// Sum(Valor)
//   → soma as vendas desses produtos no período atual (seleção do usuário)
N2
Aninhamento com Múltiplos Níveis

É possível aninhar mais de dois níveis, mas cada nível adiciona complexidade e potencial custo de performance. Use com moderação - e sempre documente a lógica.


// Pergunta: "vendas dos produtos que foram comprados por clientes
//            que também compraram o Produto X"
// Nível 1: clientes que compraram Produto X
// Nível 2: produtos comprados por esses clientes
// Nível 3: vendas desses produtos na seleção atual

Sum({
  <ProdutoID = P({
    <ClienteID = P({1}<ProdutoID={'PROD-X-001'}> ClienteID)>
  } ProdutoID)>
} Valor)

// Leitura de dentro para fora:
// 1. P({1}<ProdutoID={'PROD-X-001'}> ClienteID)
//    → ClienteIDs que compraram PROD-X-001
// 2. P({<ClienteID=[clientes acima]>} ProdutoID)
//    → ProdutoIDs comprados por esses clientes
// 3. <ProdutoID=[produtos acima]> + Sum(Valor)
//    → vendas desses produtos

// Aviso de performance: aninhamento de 3+ níveis pode ser lento
// em datasets > 10M linhas. Considere pré-calcular no script.
N3
Set Analysis com TOTAL - Porcentagem do Total

Combinar Set Analysis com o qualifier TOTAL é o padrão correto para calcular percentuais de participação. O TOTAL calcula o denominador ignorando as dimensões do gráfico.


// Participação de mercado por categoria - % do total geral
Sum(Valor) / Sum(TOTAL Valor)

// Participação dentro de um conjunto específico:
// % que cada produto representa nas vendas de Eletrônicos
Sum({<Categoria={'Eletrônicos'}>} Valor)
/
Sum(TOTAL {<Categoria={'Eletrônicos'}>} Valor)

// Participação do cliente no total de vendas da sua região
// (respeitando a seleção de Região, mas ignorando a dimensão ClienteID do gráfico)
Sum(Valor) / Sum(TOTAL <ClienteID> Valor)
// TOTAL <ClienteID> = ignora a dimensão ClienteID,
//                     mas mantém outras seleções de contexto

// Comparação: participação este ano vs ano anterior
Sum({$<Ano={$(=Year(Today()))}>} Valor)
/
Sum(TOTAL {$<Ano={$(=Year(Today()))}>} Valor)

4. Padrões de Produção - Dashboard Enterprise

Os padrões a seguir são derivados de implementações reais em dashboards executivos. Cada um resolve um problema específico de negócio usando Set Analysis como ferramenta principal.

Padrão 1: KPI Card Dinâmico com Variação


// KPI: vendas do período selecionado + comparação com mesmo período do ano anterior
// Período atual (respeita seleção do usuário de Ano e Mês):
LET vVendasAtual = Sum({$} Valor);

// Mesmo período no ano anterior (substitui apenas o Ano, mantém Mês selecionado):
LET vVendasAnterior = Sum({$<Ano={$(=Max({$} Ano)-1)}>} Valor);

// Variação percentual:
Num((vVendasAtual / vVendasAnterior) - 1, '+#0.0%;-#0.0%;0.0%')

// Na prática - expressão completa no KPI:
Num(
  (Sum({$} Valor) / Sum({$<Ano={$(=Max({$}Ano)-1)}>} Valor)) - 1,
  '+#0.0%;-#0.0%;0.0%'
)
// Formatação com sinal positivo/negativo automático e cor via expression-based color

Padrão 2: Análise de Cobertura - Clientes Ativos vs Inativos


// Definição: cliente "ativo" = comprou nos últimos 90 dias
// Definição: cliente "inativo" = não comprou nos últimos 90 dias

// Total de clientes ativos:
Count({
  <ClienteID = P({1}<Data={">=$(=Today()-90)"}> ClienteID)>
} DISTINCT ClienteID)

// Total de clientes inativos (todos os clientes MENOS os ativos):
Count({
  1
  -
  <ClienteID = P({1}<Data={">=$(=Today()-90)"}> ClienteID)>
} DISTINCT ClienteID)

// Taxa de ativação (% de clientes que compraram no período):
Count({
  <ClienteID = P({1}<Data={">=$(=Today()-90)"}> ClienteID)>
} DISTINCT ClienteID)
/
Count({1} DISTINCT ClienteID)

Padrão 3: Análise de Pareto - Top 20% que Geram 80% da Receita


// Identificar quais clientes estão no top 20% por receita
// e calcular o total de receita que eles representam

// Passo 1: calcular receita por cliente
// (feito no script para performance - AGGR() caro em gráfico)
ReceitaCliente:
LOAD ClienteID, Sum(Valor) AS ReceitaTotal
RESIDENT FactVendas GROUP BY ClienteID;

// Passo 2: no gráfico, usar Set Analysis para filtrar top 20%
// (usando função Rank com threshold percentual)
Sum({
  <ClienteID = P({1}<ClienteID={"=Rank(Sum(Valor)) <= $(=Ceil(Count(DISTINCT ClienteID)*0.2))"}> ClienteID)>
} Valor)

// Percentual sobre o total:
Sum({
  <ClienteID = P({1}<ClienteID={"=Rank(Sum(Valor)) <= $(=Ceil(Count(DISTINCT ClienteID)*0.2))"}> ClienteID)>
} Valor)
/
Sum({1} Valor)

Padrão Pareto é custoso computacionalmente porque envolve uma ordenação interna. Em datasets > 5M linhas, considere pré-calcular o rank no script e armazená-lo como um campo: RankReceita = Rank(ReceitaTotal). A expressão Set Analysis fica simples: Sum({<RankReceita={"<=$(=Ceil(Count(DISTINCT ClienteID)*0.2))"}>} Valor).

Padrão 4: Comparação Orçado vs Realizado Respeitando Seleção


// Scenario: tabelas separadas - FactVendas e Orcamento
// Desafio: comparar os dois mantendo a seleção do usuário de Produto, Região etc.

// Realizado (seleção completa do usuário):
Sum({$} Valor)

// Orçado (mesma seleção de Produto e Região, mas forçando Ano/Mês do orçamento)
// Assume que Orcamento tem a mesma estrutura de campos:
Sum({
  $<TipoRegistro={'Orcamento'},
    Ano={$(=Year(Today()))}>
} Valor)

// Variação absoluta:
Sum({$<TipoRegistro={'Realizado'}>} Valor)
-
Sum({$<TipoRegistro={'Orcamento'}>} Valor)

// Variação % (Atingimento):
Num(
  Sum({$<TipoRegistro={'Realizado'}>} Valor)
  /
  Sum({$<TipoRegistro={'Orcamento'}>} Valor),
  '#0.0%'
)

5. Debug de Set Analysis e Checklist Final

Expressões Set Analysis complexas são notoriamente difíceis de debugar porque o Qlik não exibe mensagens de erro claras - ele simplesmente retorna 0 ou NULL. Conhecer as técnicas de diagnóstico é indispensável.

Técnicas de Debug

Técnica 1 - Isolar o conjunto

// Para entender o que o conjunto retorna,
// use Count() com DISTINCT antes de Sum():

Count({
  <ClienteID = P({1}<Categoria={'Eletrônicos'}> ClienteID)>
} DISTINCT ClienteID)
// Se retornar 0 - o conjunto está vazio.
// Se retornar o esperado - o conjunto está correto,
// o problema pode ser na expressão agregada.
Técnica 2 - Verificar dollar-sign expansion

// Use uma caixa de texto com a expressão
// para ver o valor expandido antes do Set Analysis:

// Adicione um objeto de texto com:
=Year(Today())          // deve retornar 2025
=Month(Today())         // deve retornar o mês atual
=MonthStart(Today())    // data de início do mês
// Se esses valores estão incorretos,
// a dollar-sign expansion no Set Analysis
// também estará errada.
// Técnica 3 - Construção incremental
// Nunca escreva uma expressão complexa de uma vez.
// Construa peça por peça e valide cada parte:

// Passo 1: teste o identificador
Sum({1} Valor)  // deve retornar o total geral

// Passo 2: adicione um modificador simples
Sum({1}<Ano={2024}>} Valor)  // deve retornar vendas de 2024

// Passo 3: torne dinâmico
Sum({1}<Ano={$(=Year(Today()))}>} Valor)  // deve retornar o mesmo

// Passo 4: adicione o segundo modificador
Sum({1}<Ano={$(=Year(Today()))},Mes={"<=$(=Month(Today()))}"}>} Valor)

// Passo 5: troque {1} por {$} se precisar respeitar seleção
Sum({$}<Ano={$(=Year(Today()))},Mes={"<=$(=Month(Today()))}"}>} Valor)

// Construção incremental elimina ambiguidade sobre onde está o erro.

Erros Comuns e Correções

Checklist Final - Set Analysis Série Completa

SetAnalysis QlikSense YTD YoY BI QlikDeveloper DataAnalytics BusinessIntelligence Qlik DashboardDesign