Como calcular tempo médio de resolução em DAX: passo a passo
Este tutorial mostra como calcular o tempo médio de resolução (em horas ou dias) de tickets em DAX — útil para avaliar SLA e desempenho de suporte. Vamos explicar por que usar medidas em vez de colunas calculadas e dar um exemplo prático com variáveis, tratamento de valores em falta e sugestões para validar os resultados no modelo.
Pré-requisitos
- Power BI Desktop ou outro cliente que suporte DAX.
- Modelo com uma tabela de factos chamada Tickets contendo as colunas code TicketID, code CreatedDate, code ResolvedDate e code Status.
- Tabela de datas Date com coluna code Date marcada como Date Table. Ter uma Date Table permite filtrar por mês, trimestre e calcular correctamente totais acumulados.
- Volume de dados exemplificativo: se tiver 10 000 tickets, as medidas abaixo serão rápidas; em 1 000 000 de linhas convém testar desempenho e usar agregações.
Passo 1: Entender por que usar medida e não coluna
Uma coluna calculada gera um valor por linha no momento da actualização e aumenta o tamanho do modelo. Por exemplo, uma coluna adicional com um número que ocupa 8 a 16 bytes por linha numa tabela de 1 000 000 de linhas pode consumir 8 a 16 MB adicionais, e mais em metadados. Além disso, uma coluna é estática e não reage ao contexto de filtro num visual.
Uma medida calcula dinamicamente no contexto visual. Para tempo médio de resolução queremos flexibilidade: filtrar por período, equipa, prioridade ou status e ver como a média muda. Por isso usamos medidas — menos armazenamento e mais flexibilidade.
Passo 2: Calcular a diferença de tempo básica (horas)
Vamos criar uma medida que calcula a diferença entre ResolvedDate e CreatedDate em horas. A função DATEDIFF retorna um inteiro quando usamos HOUR, por isso a média será em horas inteiras. Para obter decimais podemos usar DATEDIFF em minutes e dividir por 60.
Explicação do código: filtramos Tickets para excluir linhas com datas em falta ou mal formadas, e garantimos ResolvedDate maior ou igual a CreatedDate. Depois usamos AVERAGEX sobre esse conjunto.
Avg Resolution Hours =
VAR ResolvedTickets =
FILTER(
Tickets,
NOT(ISBLANK(Tickets[ResolvedDate]))
&& NOT(ISBLANK(Tickets[CreatedDate]))
&& Tickets[ResolvedDate] >= Tickets[CreatedDate]
)
RETURN
AVERAGEX(
ResolvedTickets,
DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], HOUR)
)
Se quiser precisão decimal a nível de minutos, use:
Avg Resolution Hours Precise =
VAR Resolved =
FILTER(
Tickets,
NOT(ISBLANK(Tickets[ResolvedDate]))
&& NOT(ISBLANK(Tickets[CreatedDate]))
&& Tickets[ResolvedDate] >= Tickets[CreatedDate]
)
RETURN
AVERAGEX(Resolved, DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], MINUTE) / 60)
Exemplo numérico: num conjunto de 10 000 tickets resolvidos, se a soma das diferenças em horas for 52 000, a média será 5,2 horas por ticket.
Passo 3: Tratar outliers e valores extremos
Outliers podem distorcer a média. Por exemplo, se 1% dos tickets demorou 365 dias a resolver, a média sobe muito. Uma abordagem simples é excluir durações acima de um limite razoável, por exemplo 90 dias. Em 10 000 tickets, 90 dias = 2160 horas; se 200 tickets excederem esse limite, estamos a excluir 2% dos casos.
Avg Resolution Hours (Trimmed) =
VAR MaxHours = 90 * 24
VAR ResolvedTickets =
FILTER(
Tickets,
NOT(ISBLANK(Tickets[ResolvedDate]))
&& NOT(ISBLANK(Tickets[CreatedDate]))
&& Tickets[ResolvedDate] >= Tickets[CreatedDate]
&& DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], HOUR) <= MaxHours
)
RETURN
IF(
COUNTROWS(ResolvedTickets)=0,
BLANK(),
AVERAGEX(ResolvedTickets, DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], HOUR))
)
Alternativas: usar medianas para uma medida robusta ou calcular percentis como 90th percentile para compreender a distribuição. Verifique sempre quantas linhas foram excluídas com uma medida de contagem para confirmar que o corte não remove demasiado dado legítimo.
Passo 4: Média ponderada por prioridade (opcional)
Se quiser dar mais peso a tickets de alta prioridade, use uma média ponderada. Assumimos uma coluna Priority com valores numéricos 1 a 5. Isto faz sentido se, por exemplo, um ticket Priority 5 for três vezes mais crítico que Priority 1.
Weighted Avg Resolution Hours =
VAR Resolved =
FILTER(
Tickets,
NOT(ISBLANK(Tickets[ResolvedDate]))
&& NOT(ISBLANK(Tickets[CreatedDate]))
&& Tickets[ResolvedDate] >= Tickets[CreatedDate]
)
VAR SumWeighted =
SUMX(
Resolved,
DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], HOUR) * COALESCE(Tickets[Priority],1)
)
VAR SumWeights =
SUMX(Resolved, COALESCE(Tickets[Priority],1))
RETURN
DIVIDE(SumWeighted, SumWeights)
Se Priority for texto (High, Medium, Low), converta antes com SWITCH ou crie uma coluna de mapeamento.
Passo 5: Mostrar em dias e formatar para o utilizador
Para mostrar o resultado em dias com uma casa decimal converta horas para dias. No Power BI, defina o formato da medida para Mostrar como Número com 1 casa decimal.
Avg Resolution Days =
VAR Hours = [Avg Resolution Hours]
RETURN
IF(ISBLANK(Hours), BLANK(), Hours / 24)
Se preferir hh:mm mostre horas inteiras e minutos com INT e MOD ou use FORMAT para formatar string mas evite FORMAT em indicadores que serão usados em cálculos.
Verificar o resultado
Crie uma visualização de cartão ou tabela com as medidas: code Avg Resolution Hours, code Avg Resolution Hours (Trimmed) e code Avg Resolution Days. Filtre por mês ou equipa para confirmar que os valores mudam conforme esperado. Compare com uma tabela de amostra de 50 tickets: calcule manualmente alguns exemplos para validar a média.
Medidas úteis para validação:
Resolved Count =
CALCULATE(COUNTROWS(Tickets), NOT(ISBLANK(Tickets[ResolvedDate])))
Trimmed Count =
CALCULATE(
COUNTROWS(Tickets),
NOT(ISBLANK(Tickets[ResolvedDate])),
DATEDIFF(Tickets[CreatedDate], Tickets[ResolvedDate], HOUR) <= 90*24
)
Verifique que Resolved Count e Trimmed Count fazem sentido e que o número excluído é plausível (por exemplo 1-5% dependendo do histórico).
Conclusão
Agora sabe calcular o tempo médio de resolução em DAX, tratar outliers e aplicar ponderação por prioridade. Próximos passos recomendados: calcular percentis (p.ex. 90th percentile) para compreender a cauda da distribuição, criar uma medida para a percentagem de tickets dentro do SLA e assegurar que as datas estão num fuso horário consistente antes de calcular durações. Dica de performance: use variáveis, evite iteradores desnecessários em grandes tabelas e pré-aggregate quando possível para modelos com milhões de linhas.