【问题标题】:How to calculate running sums with append-only rows如何计算仅附加行的运行总和
【发布时间】:2019-12-05 14:42:26
【问题描述】:

我有一个表,其中的行从不变异,而只是插入;它们是不可变的记录。它有以下字段:

  • id: int
  • user_id: int
  • created: datetime
  • is_cool: boolean
  • likes_fruits: boolean

对象与用户相关联,给定用户的“当前”对象是具有最新created 日期的对象。例如。如果我想为用户更新is_cool,我会附加一条带有新created时间戳和is_cool=true的记录。

我想计算每天结束时有多少用户is_cool。 IE。我希望输出表有列:

  • day:某种date_trunc('day', created)
  • cool_users_count:在这一天结束时拥有is_cool 的用户数量。

我可以编写什么 SQL 查询来做到这一点? FWIW 我正在使用 Presto(或 Redshift,如果需要)。

请注意,还有其他列,例如likes_fruits,这意味着 is_coolfalse 的记录并不意味着 is_cool 只是更改为 false - 它可能有一段时间是 false

这是过程伪代码的样子,代表我想在 SQL 中做的事情:

// rows = ...
min_date = min([row.created for row in rows])
max_date = max([row.created for row in rows])

counts_by_day = {}
for date in range(min_date, max_date):
  rows_up_until_date = [row for row in rows if row.created <= date]
  latest_row_by_user = rows_up_until_date.reduce(
    {},
    (acc, row) => acc[row.user_id] = row,
  )
  counts_by_day[date] = latest_row_by_user.filter(row => row.is_cool).length

【问题讨论】:

    标签: sql presto


    【解决方案1】:

    您可以使用查询来做到这一点.. 尝试在 boolend 和 group by 上使用 sum

      select  date(created), sum(is_cool)
      from  my_table  
      group by date(created)
    

    或者如果你需要用户数量

    select t.date_created, count(*) num_user
    from  (
      select  distinct date(created) date_created, user_id 
      from  my_table  
      where is_cool = TRUE 
     ) t 
     group by  t.date_created
    

    或者如果需要 is_cool 的最后一个值

    select date(max_date), sum(is_cool)
    from (
        select  t.user_id, t.max_date, m.is_cool, m.user_id 
        from my_table m  
        inner join  (
            select  max(date_created) max_date, user_id 
            from  my_table 
            group by  user_id, date(date_created)
        ) t on t.max_date  = m.date_created 
                and t.user_id  = m.user_id 
        where m.is_cool = TRUE 
    ) t2
    group by date(max_date)
    

    【讨论】:

    • is_cool 可能会为一个用户来回变化,这意味着会有多个is_cool=true 行,但这并不代表多个is_cool 用户。
    • 您的评论我不清楚.. 尝试更好地解释或添加数据样本和预期结果
    • 假设我有以下行:user:1, is_cool: true, created: 9amuser:1, is_cool: false, created: 10amuser:1, is_cool: true, created:11am。结果输出应该是 1,因为有 1 个用户是 is_cool,而不是 2,因为有 2 个 is_cool 行。
    • 感谢您的更新。不幸的是,这并没有考虑到likes_fruits 可以更新。例如。用户已经is_cool,因此user:1, is_cool: true, likes_fruits: true 的新行不会代表该用户今天成为is_cool。每天的计数应该是今天变得很酷的用户,或者是今天很酷的用户。
    • 我看到第三个查询计算了截至目前is_cool 用户的数量。从历史的角度来看,我每天都希望这样。我想要is_cool 用户的数量,截至第 1 天,截至第 2 天......等等。
    【解决方案2】:

    关联子查询可能是最简单的解决方案。以下为每个用户在每个日期获取is_cool 的值:

    select u.user_id, d.date,
           (select t.is_cool
            from t
            where t.user_id = u.user_id and
                  t.created < dateadd(day, 1, d.date)
            order by t.created desc
            limit 1
           ) as is_cool
    from (select distinct date(created) as date
          from t
         ) d cross join
         (select distinct user_id
          from t
         ) u ;
    

    然后聚合:

    select date, sum(is_cool)
    from (select u.user_id, d.date,
                 (select t.is_cool
                  from t
                  where t.user_id = u.user_id and
                        t.created < dateadd(day, 1, d.date)
                  order by t.created desc
                  limit 1
                 ) as is_cool
          from (select distinct date(created) as date
                from t
               ) d cross join
               (select distinct user_id
                from t
               ) u
         ) ud
    group by date;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 1970-01-01
      • 1970-01-01
      • 2012-07-03
      • 2013-04-17
      • 1970-01-01
      • 2023-03-23
      相关资源
      最近更新 更多