【问题标题】:How to accurately sum/aggregate a SQL Running Total?如何准确地求和/聚合 SQL Running Total?
【发布时间】:2022-11-23 21:09:59
【问题描述】:

我有以下场景(CTE SQL 示例),我们有这种粒度的产品销售数据;

  • 日期级别
  • 来源(设备、国家)
  • 会计周期(年、周)
  • 产品信息(组)

我有一个使用 Over Partition By,“FYTD”= Fiscal Year To Date 的运行总计,这似乎按预期工作,按不同维度计算运行总计,但是当我在最终结果中求和时,它被夸大了,就像我们一样汇总每天的 FYTD 值,而不是在最近的粒度级别。

我们如何才能在结果中返回截至最近一天的准确、真实的 FYTD 总和,并使用可扩展到具有更多财政年度/周的更大结果集的解决方案?我正在 Snowflake 中对此进行测试。

with rawdata as (
    select * from
        values
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Shoes', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Shoes', 5),
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Socks', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Socks', 5)
         as a (date, fiscalyearno, fiscalweekno, devicegroup, usercountry, productgroup, bookings)
    ),
    
    resultsset as (
    select  date
            , fiscalyearno
            , fiscalweekno
            , devicegroup
            , usercountry
            , productgroup 
            , sum(bookings) as totalbookings
            , sum(totalbookings)
                over 
                    (partition by fiscalyearno, fiscalweekno, devicegroup, usercountry, productgroup order by date asc) as fytdbookings
    from rawdata
    group by 1,2,3,4,5,6
    )

select fiscalyearno, fiscalweekno, sum(totalbookings), sum(fytdbookings)
from resultsset
group by 1,2

已尝试对最大 FYTD 值求和,但收到语法警告,指出您不能拥有嵌套聚合。

dense_rank() 有帮助但不确定是否是最佳解决方案;

with rawdata as (
    select * from
        values
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Shoes', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Shoes', 5),
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Socks', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Socks', 5),
            ('2022-10-08', 2023, 2, 'Desktop', 'UK', 'Shoes', 7),
            ('2022-10-08', 2023, 2, 'Mobile', 'UK', 'Shoes', 8),
            ('2022-10-08', 2023, 2, 'Tablet', 'UK', 'Shoes', 4),
            ('2022-10-09', 2023, 2, 'Desktop', 'UK', 'Shoes', 6),
            ('2022-10-09', 2023, 2, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-09', 2023, 2, 'Tablet', 'UK', 'Shoes', 8),
            ('2022-10-10', 2023, 2, 'Desktop', 'UK', 'Shoes', 12),
            ('2022-10-10', 2023, 2, 'Mobile', 'UK', 'Shoes', 22),
            ('2022-10-10', 2023, 2, 'Tablet', 'UK', 'Shoes', 5),
            ('2022-10-08', 2023, 2, 'Desktop', 'UK', 'Socks', 4),
            ('2022-10-08', 2023, 2, 'Mobile', 'UK', 'Socks', 1),
            ('2022-10-08', 2023, 2, 'Tablet', 'UK', 'Socks', 2),
            ('2022-10-09', 2023, 2, 'Desktop', 'UK', 'Socks', 3),
            ('2022-10-09', 2023, 2, 'Mobile', 'UK', 'Socks', 8),
            ('2022-10-09', 2023, 2, 'Tablet', 'UK', 'Socks', 9),
            ('2022-10-10', 2023, 2, 'Desktop', 'UK', 'Socks', 5),
            ('2022-10-10', 2023, 2, 'Mobile', 'UK', 'Socks', 4),
            ('2022-10-10', 2023, 2, 'Tablet', 'UK', 'Socks', 13)
         as a (date, fiscalyearno, fiscalweekno, devicegroup, usercountry, productgroup, bookings)
    ),
    
    resultsset as (
    select  date
            , fiscalyearno
            , fiscalweekno
            , devicegroup
            , usercountry
            , productgroup 
            , sum(bookings) as totalbookings
            , dense_rank()
                over 
                    (partition by fiscalyearno, devicegroup, usercountry, productgroup order by date desc, fiscalweekno desc) as fytddr    
            , sum(totalbookings)
                over 
                    (partition by fiscalyearno, devicegroup, usercountry, productgroup order by date, fiscalweekno asc) as fytdbookings
    from rawdata
    group by 1,2,3,4,5,6
    )

//select * from resultsset
//order by 1,2,3,4,5,6

select  fiscalyearno
        , fiscalweekno
        , sum(totalbookings) as totalbookings
        , sum(iff(fytddr = 1, fytdbookings, 0)) as fytdbookings
from resultsset
group by 1,2
order by 2

【问题讨论】:

  • 我可以将 partition by fiscysearno order by fiscalweekno 的总和移动到最终查询中,以获得该特定用例的正确结果,但随着需求的变化,我们可能需要也可能不需要某个维度的 FYTD total,我们需要确保它是在结果集和最终结果中。

标签: sql snowflake-cloud-data-platform


【解决方案1】:

这并不过分。您正在总结一个运行总和。如果你有 1、2、3 的运行总和,你将得到 1、3、6。如果你有运行总和的总和,你将得到 10。我不确定你为什么想要运行求和然后聚合它。它消除了运行总和提供的细节。此外,为了通过聚合,SQL 将 totalbookings(聚合总和的别名)输入求和窗口函数。这充其量是有趣的,最坏的情况是不可预测的。

如果您简化 CTE 并查看窗口函数的结果,您可以看到运行总和问题的总和:

with rawdata as (
    select * from
        values
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Shoes', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Shoes', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Shoes', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Shoes', 5),
            ('2022-10-01', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-01', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-01', 2023, 1, 'Tablet', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-02', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-02', 2023, 1, 'Tablet', 'UK', 'Socks', 4),
            ('2022-10-03', 2023, 1, 'Desktop', 'UK', 'Socks', 1),
            ('2022-10-03', 2023, 1, 'Mobile', 'UK', 'Socks', 2),
            ('2022-10-03', 2023, 1, 'Tablet', 'UK', 'Socks', 5)
         as a (date, fiscalyearno, fiscalweekno, devicegroup, usercountry, productgroup, bookings)
    ),
    
    resultsset as (
    select  date
            , fiscalyearno
            , fiscalweekno
            , devicegroup
            , usercountry
            , productgroup 
    --        , sum(bookings) as totalbookings
            , sum(bookings)
                over 
                    (partition by fiscalyearno, fiscalweekno, devicegroup, usercountry, productgroup order by date asc) as fytdbookings
    from rawdata
   -- group by 1,2,3,4,5,6
    )

select * from resultsset;
DATE FISYNO FISWEEKNO DEVGRP USRCNTRY PRODGRP FYTDBOOK
2022-10-01 2023 1 Desktop UK Shoes 1
2022-10-01 2023 1 Mobile UK Shoes 2
2022-10-01 2023 1 Tablet UK Shoes 1
2022-10-02 2023 1 Desktop UK Shoes 2
2022-10-02 2023 1 Mobile UK Shoes 4
2022-10-02 2023 1 Tablet UK Shoes 5
2022-10-03 2023 1 Desktop UK Shoes 3
2022-10-03 2023 1 Mobile UK Shoes 6
2022-10-03 2023 1 Tablet UK Shoes 10
2022-10-01 2023 1 Desktop UK Socks 1
2022-10-01 2023 1 Mobile UK Socks 2
2022-10-01 2023 1 Tablet UK Socks 1
2022-10-02 2023 1 Desktop UK Socks 2
2022-10-02 2023 1 Mobile UK Socks 4
2022-10-02 2023 1 Tablet UK Socks 5
2022-10-03 2023 1 Desktop UK Socks 3
2022-10-03 2023 1 Mobile UK Socks 6
2022-10-03 2023 1 Tablet UK Socks 10

请注意,运行总和在某些情况下高于任何单个值,因此这解释了在对运行总和求和时总计较高的原因。

至于如何解决这个问题,我不确定。拥有所需的输出表会有所帮助,因为如前所述,计算运行总和只是为了聚合它会丢失运行总和的详细信息。

【讨论】:

  • 谢谢格雷格!我正在使用 dense_rank 接近我想要的结果,但不确定它是否是最佳解决方案。我明白你的意思,运行总和本身有价值,但 FYTD 绝对值也有价值。
  • 添加到帖子中,因为无法在此处放置代码。
猜你喜欢
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 2014-09-07
相关资源
最近更新 更多