Do not input private or sensitive data. View Qlik Privacy & Cookie Policy.
Skip to main content

Announcements
Share your agentic AI experience, learn from others, and earn a new badge: Put Agentic AI to Work
cancel
Showing results for 
Search instead for 
Did you mean: 
andrelfg
Contributor II
Contributor II

Current year vs previous year cumulative sales

Hi all, good evening,

I need to compare the cumulative sales between a year and the year before. This for many years stored in my database.

The sales had already been normalized by the month of each year.

This is the expression I created to generate the information for each year:

Aggr(RangeSum(Above(Sum(QTY), 0, RowNo())), [SALES YEAR, [YEAR/MONTH])

YEAR/MONTH SALES YEAR QTY
(other year months) ... ...
2026/01 2024 1
2026/02 2024 10
2026/03 2024 25
2026/04 2024 8
2026/05 2024 14
... ... ...
2026/01 2025 0
2026/02 2025 3
2026/03 2025 12
2026/04 2025 11
2026/05 2025 7
... ... ...
2026/01 2026 4
2026/02 2026 5
2026/03 2026 8
2026/04 2026 12
2026/05 2026 20

 

And this is the generated graphic:

andrelfg_0-1786559771694.png

 

What I need is to created a new graphic that shows, for each year, the % growth between that year vs its last year, using the same rule (acumulated sales for each month).

I have already tried many solutions here in the topics, but I couldn't get the right result.

For exemple: Aggr(RangeSum(Above(Sum(QTY) / Sum({<[SALES YEAR] = {"$(=Only([SALES YEAR])-1)"}>}QTY), 0, RowNo())), [SALES YEAR, [YEAR/MONTH])

Thanks in advance for any help.

 

Labels (2)
9 Replies
Anil_Babu_Samineni
MVP
MVP

try this way?

((Aggr(Max(RangeSum(Above(Sum(QTY),0,RowNo()))),[SALES YEAR]) - Above(Aggr(Max(RangeSum(Above(Sum(QTY),0,RowNo()))),[SALES YEAR]),1)) / Above(Aggr(Max(RangeSum(Above(Sum(QTY),0,RowNo()))),[SALES YEAR]),1)) * 100

Best Anil, When applicable please mark the correct/appropriate replies as "solution" (you can mark up to 3 "solutions". Please LIKE threads if the provided solution is helpful
andrelfg
Contributor II
Contributor II
Author

Hi @Anil_Babu_Samineni ,

I tried your solution but it didn't work.

I will try to send more details about my data set, to try to clarify better the issue.

I will send this next monday.

Thanks in advance for your help!

Qrishna
Master
Master

I'd prefer/suggest to the calculate in the script rather than on the UI as it becomes complicated on the front end especially for cumulative aggregations using rangesum().

2554716 - Current year vs previous year cumulative sales - 1.PNG2554716 - Current year vs previous year cumulative sales - 2.PNG

WesleySouza
Partner - Contributor II
Partner - Contributor II

Ótimo caso, no fundo é um YoY (crescimento ano contra ano) em cima de um valor acumulado. Vou por partes.

Sua expressão de acumulado está correta
Aggr(
RangeSum(Above(Sum(Quantidade), 0, RowNo())),
ANO_VENDAS, ANO_MÊS
)

Ela reinicia o acumulado a cada `ANO_VENDAS` (porque a acumulação acontece dentro de cada grupo do `Aggr`) e vai somando mês a mês na ordem de `ANO_MÊS`. Um detalhe que decorre disso e é importante para o próximo passo: o acumulado no último mês de um ano é igual ao total daquele ano.

Que gráfico representa melhor?

Depende da granularidade que você quer enxergar:
Se você quer um número de crescimento por ano (ex.: 2024 cresceu +12% sobre 2023), use gráfico de colunas/barras. É o melhor porque o crescimento pode ser negativo, e a coluna acima/abaixo de zero comunica isso na hora. Ano no eixo X.

Se você quer acompanhar o crescimento *acumulado mês a mês*, comparando cada mês com o mesmo mês do ano anterior, use **gráfico de linhas**, com o número do mês (1–12) no eixo X e uma linha por ano. Aí você vê em que ponto do ano o crescimento acelera ou perde força — e resolve o problema de ano incompleto (compara sempre "até o mesmo mês").

Para responder direto à sua pergunta ("crescimento de cada ano vs. o anterior"), vá de colunas.

Expressão — crescimento anual (colunas)

Como o acumulado de dezembro = total do ano, o crescimento anual sai direto, sem precisar reconstruir a acumulação:

Dimensão: ANO_VENDAS (ordem **crescente**)
Medida: Sum(Quantidade) / Above(Sum(Quantidade)) - 1

Formate como %. O `Above()` pega o total da linha de cima (ano anterior). No primeiro ano ele fica nulo — que é o correto, já que não há ano anterior. Só garanta a ordenação crescente da dimensão, senão o `Above()` compara com o ano errado.

Expressão — crescimento acumulado mês a mês (linhas)

Aqui a comparação é "acumulado até o mês X deste ano" vs. "acumulado até o mês X do ano anterior". Fazer isso 100% na expressão (acumulação inter-registro + deslocamento de 12 meses) fica frágil, porque depende de todos os meses existirem em todos os anos. O caminho robusto e rápido é **acumular no script** e deixar o gráfico simples:

Ordenada:
LOAD ANO_VENDAS, ANO_MÊS, Quantidade
RESIDENT SuaTabela
ORDER BY ANO_VENDAS, ANO_MÊS;

Acumulada:
LOAD *,
If(ANO_VENDAS = Peek(ANO_VENDAS),
RangeSum(Peek(Qtd_Acum), Quantidade),
Quantidade) AS Qtd_Acum
RESIDENT Ordenada
ORDER BY ANO_VENDAS, ANO_MÊS;
DROP TABLE Ordenada;

(Se `ANO_MÊS` não ordenar certo como texto — tipo "Jan", "Fev" — crie antes um `MesNum` numérico e use ele no `ORDER BY`.)

Com o campo `Qtd_Acum` pronto, no gráfico de linhas:
Dimensão: `MesNum` (1–12)

Medida (último ano vs. ano anterior):

Sum({<ANO_VENDAS={"$(=Max(ANO_VENDAS))"}>} Qtd_Acum)
/
Sum({<ANO_VENDAS={"$(=Max(ANO_VENDAS)-1)"}>} Qtd_Acum)
- 1

Para comparar *cada* ano com o seu antecessor (não só o último), coloque `ANO_VENDAS` como segunda dimensão (cor) e troque a medida por `Sum(Qtd_Acum)/Above(Total Sum(Qtd_Acum)) - 1`, cuidando da ordem das dimensões.

Resumindo: coluna para o número anual de crescimento; linha para a leitura mês a mês.

Espero ter ajudado.

Executivo de Desenvolvimento de Negócios
Soeva Tech Academy — Business Intelligence & ERP
 Goiânia, GO
 wesley.souza@soeva.com.br
 +55 (62) 99246-2972
 www.soeva.com.br
andrelfg
Contributor II
Contributor II
Author

Thank you for your help, @Qrishna 

Olá  @WesleySouza , muito obrigado por toda a ajuda e explicações!

Sobre as soluções que você propôs, a minha necessidade seria na direção da sua segunda sugestão, para tratar a % de crescimento mês a mês, acumulada.

Aqui no meu caso, eu garanto que todos os dias e meses do ano existam, mesmo que não tenha ocorrido venda, isso para todos os anos. Acaba que fica mais pesado, mas resolveu o problema. Eu tive que fazer isso para que o meu gráfico que coloquei como exemplo no meu post (mostrando as vendas acumuladas de cada ano), funcionasse sem qualquer problema nas acumulações etc.

Eu citei o exemplo do gráfico com acumulação por ano/mês, mas eu tenho outro gráfico de linha que gera por dia, onde sigo a mesma ideia.

Eu vou postar abaixo os códigos de cada passo que fiz, para que isso fosse possível.

Daí baseado nisso, você acredita que seria possível, diretamente nas expressões do gráfico de linha, chegar no resultado de conseguir comparar as vendas do cada ano, em relação ao ano imediatamente anterior, para cada ano, isso acumulando mês a mês?

Novamente, agradeço muito pela ajuda!

Vendas:
LOAD *;
SQL
-- 1. Cria uma Tabela de Datas com todos os dias do ano
WITH Dates AS (
    SELECT CAST('2026-01-01' AS DATE) AS CalendarDate
    UNION ALL
    SELECT DATEADD(DAY, 1, CalendarDate)
    FROM Dates
    WHERE CalendarDate < '2028-01-31'
),
-- 2. Identifica todas as combinações únicas de unidade e ano de vendas
UnitYears AS (
    SELECT
    	DISTINCT
    	UNIDADE			AS "Unidade",
    	ANOVENDA		AS "Ano venda",
    	CODDEPARTAMENTO		AS "Departamento",
    	CODVENDEDOR		AS "Vendedor",
    FROM
    	VENDAS (NOLOCK)
),
-- 3. Combina as datas com as unidades e anos para criar a tabela completa de todos os dias por unidade/ano
CompleteMatrix AS (
    SELECT
        d.CalendarDate,
        uy."Unidade",
        uy."Ano venda",
        uy."Departamento",
        uy."Vendedor"
    FROM
        Dates AS d
    CROSS JOIN
        UnitYears AS uy
)
-- 4. Junta a tabela completa com a tabela original para preencher os dados

SELECT
    m."Unidade",
    m."Ano venda",
    m."Departamento",
    m."Vendedor",
    CONVERT(VARCHAR(4),YEAR(m.CalendarDate)) + '/' + SUBSTRING(CONVERT(VARCHAR,m.CalendarDate,111),6,2) AS "Ano/mês",
    m.CalendarDate AS data_venda,
    ISNULL(t.QTD, 0) AS qtd

FROM
    CompleteMatrix AS m
LEFT JOIN
    (
    SELECT
        UNIDADE			AS "Unidade",
        ANOVENDA		AS "Ano venda",
    	CODDEPARTAMENTO		AS "Departamento",
    	CODVENDEDOR		AS "Vendedor",

	/* Normaliza as datas de vendas */
	CONVERT(NVARCHAR(20),REPLACE(CASE
		WHEN YEAR(DTVENDA) = ANOVENDA
		THEN CASE
				WHEN SUBSTRING(CONVERT(VARCHAR,DTVENDA,111),6,5) = '02/29' THEN CONVERT(VARCHAR(4),YEAR(GETDATE())) + '/' + '02/28'
				ELSE CONVERT(VARCHAR(4),YEAR(GETDATE())) + '/' + SUBSTRING(CONVERT(VARCHAR,DTVENDA,111),6,5)
			 END
	END,'/','-'))		AS DATA_VENDA,

    	COUNT(VENDAID) AS QTD

    FROM
    	VENDAS (NOLOCK)

    GROUP BY
        UNIDADE,
        ANOVENDA,
    	CODDEPARTAMENTO,
    	CODVENDEDOR,

	/* Normaliza as datas de vendas */
	CONVERT(NVARCHAR(20),REPLACE(CASE
		WHEN YEAR(DTVENDA) = ANOVENDA
		THEN CASE
				WHEN SUBSTRING(CONVERT(VARCHAR,DTVENDA,111),6,5) = '02/29' THEN CONVERT(VARCHAR(4),YEAR(GETDATE())) + '/' + '02/28'
				ELSE CONVERT(VARCHAR(4),YEAR(GETDATE())) + '/' + SUBSTRING(CONVERT(VARCHAR,DTVENDA,111),6,5)
			 END
	END,'/','-'))

		) AS T
    ON m."Unidade" = t."Unidade"
    AND m."Ano venda" = t."Ano venda"
    AND m.CalendarDate = t.DATA_VENDA
    AND m."Departamento" = t."Departamento"
    AND m."Vendedor" = t."Vendedor"

ORDER BY
	m.CalendarDate,
	m."Ano venda",
	m."Unidade"
OPTION (MAXRECURSION 0);

 

andrelfg
Contributor II
Contributor II
Author

Para ilustrar melhor o objetivo que estou tentando alcançar, o gráfico seria como no exemplo da imagem abaixo. E eu tenho anos de vendas dinâmicos, que são criados a cada novo ano. Então seria comparar a venda acumulada mês a mês do ano com a acumulada mês a mês do ano imediatamente anterior, para todos os anos de venda.

andrelfg_0-1789068765626.png

 

SunilChauhan
Champion II
Champion II

May be you Can take a look at this . I have consider Data for 3 Year 2026,2025,2024
Take a Line Chart
Dimension: Year_Month

 

Measure :

1.


(RangeSum(Above(Sum(QTY),0,NoOfRows())) - Above(RangeSum(Above(Sum(QTY),0,NoOfRows())))) / Above(RangeSum(Above(Sum(QTY),0,NoOfRows())))

2.  RangeSum(Above(Sum(QTY),0,NoOfRows()))

 

 

 

Filter : Select Sales Year

 

Charts will look like

 

SunilChauhan_2-1789473005049.png

 

Bar Charts show actual Sales QTY.

Line/combo charts show

Cumulative SAles Quantity

I have wondering if multiple line you shows in image would be possible.

Thanks

 

Sunil Chauhan
marcus_sommer
MVP
MVP

I suggest to simplify the entire approach by removing the year-information from the dimension and just using the month.

Data relating to a certain period are belonging to this and only this period and not to a previous one or reverse. That's not a matter of selections else how the data are associated to each other. I don't want to say that's not possible to bypass these relations with more or less complex aggr-constructs but if the targets are to build on top of it cummulations and/or further rates it could become easily very ugly.

Much simpler would be to remove the differentiating information form the dimension and applying n expressions with appropriate conditions - as base something like:

sum({< Year = {"$(=max(Year))"}>} QTY)
sum({< Year = {"$(=max(Year)-1)"}>} QTY)
...

Another possibility would be to create appropriate associations within the data-model. This means not mandatory to pre-calculate facts else to add an extra and overlapping dimension-layer to it. The logic behind it is explained here: The As-Of Table - Qlik Community - 1466130

stevedark
Partner Ambassador/MVP
Partner Ambassador/MVP

Hi @andrelfg 

The above and aggr functions can get very complicated when trying to do these things, and will often give unexpected results.

I tend to deal with this type of scenario by creating a separate aggregate dimension in the load script. I explain this approach in this blog post:
https://www.quickintelligence.co.uk/qlikview-accumulate-values/

It's a very similar approach to the one that HIC lays out in the link that @marcus_sommer has posted above, but I look at a few different ways of applying this in my post.

Hope that helps.

Steve