获取给定日期列表的多个类别的值总和

Get sum of values for multiple categories for a given list of dates

我需要编写一个查询来获取给定日期列表中每个类别的值总和。如果某个类别的值不存在,我们应该从前一个日期获取值。基本上类似于“每个日期每个类别的最大值”。最终目标是趋势图。如果类别的先前值不存在,则将值设置为 0 即可。

见下表和结果:

类别

id name
1 savings
2 cash
3 stocks

项目

id categoryId value createdAt
1 1 100 2022-01-01
2 2 20 2022-01-01
3 3 500 2022-01-01
4 2 0 2022-01-02
5 3 1000 2022-01-03

结果

createdAt total
2022-01-01 620
2022-02-02 600
2022-02-03 1100

要获得单个日期的结果,我可以这样做:

SELECT SUM(value) as total
FROM Category
LEFT JOIN (
    SELECT id, categoryId, value
    FROM Item
    WHERE id IN (
        SELECT MAX(id) FROM Item WHERE createdAt <= '2022-01-10' GROUP BY categoryId)
) items ON Category.id = items.categoryId;

我完全不知道如何处理多个日期,例如。如果我的输入是 2022 年 1 月的每一天。我 运行 在 MySQL 8.0.23。此外,如果这对于单个查询不可行,我会提出想法。你有什么建议吗?

试试这个:

with u as
(select id as categoryId from Category),
v as
(select distinct createdAt from Item),
w as
(select * from u cross join v),
x as
(select createdAt, 
categoryId, 
(select value 
from Item 
where categoryId = w.categoryId and createdAt <= w.createdAt 
order by createdAt desc 
limit 1) as value
from w)
select createdAt, sum(value) as total
from x
group by createdAt

基本上获取创建日期与categoryIds的所有组合,然后使用子查询获取每个categoryId最接近或相等日期的值。

一个Fiddle.

一个选项使用window函数如SUM() OVER ()LAG()

WITH i AS
(
 SELECT SUM(`value`) OVER (PARTITION BY `createdAt`,`categoryId` ORDER BY `createdAt`) AS total_sofar,
        LAG(`value`,1,0) OVER (PARTITION BY `categoryId` ORDER BY `createdAt`) AS lg,
        `createdAt`
   FROM Item 
)
SELECT DISTINCT `createdAt`,
       SUM(total_sofar) OVER (ORDER BY `createdAt`)-SUM(lg) OVER (ORDER BY `createdAt`) AS total
  FROM i
 ORDER BY `createdAt` 

因为您有 MySQL 8.0 版的 DBMS。诀窍是分组(partitioning by categoryId 连同 LAG 在第一次查询时)

Demo