Try this:
match(y:Year)<-[:SPEND_IN]-(s:Spending)-[:SPEND_ON]->(c:Category)
with y.year as year, c.name as category, sum(s.amount) as total
order by category, year
with category, collect({year: year, total: total}) as categoryStats
unwind range(size(categoryStats)-1, 0, -1) as index
return
category,
categoryStats[index].year as year,
categoryStats[index].total as total,
CASE WHEN index <> 0 THEN categoryStats[index-1].total ELSE "N/A" END as previousYearTotal,
CASE WHEN index <> 0 THEN round(100 * (categoryStats[index].total - categoryStats[index-1].total) / categoryStats[index-1].total, 2) ELSE "N/A" END AS percentChangeFromPreviousYear
create
(y2021:Year{year:2021}),
(y2022:Year{year:2022}),
(y2023:Year{year:2023}),
(cClothes:Category{name:"Clothes"}),
(cElectronics:Category{name:"Electronics"}),
(cSupplies:Category{name:"Supplies"}),
(s0:Spending{spending_id:0, amount:100.00}),
(s1:Spending{spending_id:1, amount:200.00}),
(s2:Spending{spending_id:2, amount:300.00}),
(s3:Spending{spending_id:3, amount:400.00}),
(s4:Spending{spending_id:4, amount:500.00}),
(s5:Spending{spending_id:5, amount:600.00}),
(s6:Spending{spending_id:6, amount:700.00}),
(s7:Spending{spending_id:7, amount:800.00}),
(s8:Spending{spending_id:8, amount:900.00}),
(s9:Spending{spending_id:9, amount:55.00}),
(s0)-[:SPEND_ON]->(cClothes), (s0)-[:SPEND_IN]->(y2021),
(s1)-[:SPEND_ON]->(cElectronics), (s1)-[:SPEND_IN]->(y2021),
(s2)-[:SPEND_ON]->(cSupplies), (s2)-[:SPEND_IN]->(y2021),
(s3)-[:SPEND_ON]->(cElectronics), (s3)-[:SPEND_IN]->(y2022),
(s4)-[:SPEND_ON]->(cClothes), (s4)-[:SPEND_IN]->(y2022),
(s5)-[:SPEND_ON]->(cElectronics), (s5)-[:SPEND_IN]->(y2021),
(s6)-[:SPEND_ON]->(cClothes), (s6)-[:SPEND_IN]->(y2023),
(s7)-[:SPEND_ON]->(cElectronics), (s7)-[:SPEND_IN]->(y2021),
(s8)-[:SPEND_ON]->(cSupplies), (s8)-[:SPEND_IN]->(y2022),
(s9)-[:SPEND_ON]->(cElectronics), (s9)-[:SPEND_IN]->(y2023)
Maybe this is a little cleaner version:
match(y:Year)<-[:SPEND_IN]-(s:Spending)-[:SPEND_ON]->(c:Category)
with y.year as year, c.name as category, sum(s.amount) as total
order by category, year
with category, collect({year: year, total: total}) as categoryStats
unwind range(size(categoryStats)-1, 0, -1) as index
with
category,
categoryStats[index].year as year,
categoryStats[index].total as total,
CASE WHEN index <> 0 THEN categoryStats[index-1].total ELSE "N/A" END as previousYearTotal
return
category,
year,
total,
previousYearTotal,
CASE WHEN previousYearTotal <> "N/A" THEN round(100 * (total - previousYearTotal) / previousYearTotal, 2) ELSE "N/A" END AS percentChangeFromPreviousYear