SQL 从存储事务的表中查找每日最大单位

Posted

技术标签:

【中文标题】SQL 从存储事务的表中查找每日最大单位【英文标题】:SQL Find the daily maximum units from a table which stores transactions 【发布时间】:2022-01-04 23:53:53 【问题描述】:

我有一个 SQL 表,它以任何给定的时间戳存储项目的单位(库存)。项目上的任何事务(添加/删除)基本上都会使用新数量和发生的时间戳更新此表。

update_timestamp  item_id  units
  1637993217       item1     3
  1637993227       item2     1
  1637993117       item1     2
  1637993237       item1     5

我需要从该表中获取每个项目的每日最大单位数。

我使用的查询与此类似:

SELECT date_format(from_unixtime((CAST(update_timestamp AS BIGINT))/1000),'%Y-%m-%d') AS day,
item_id,
MAX(units) as max_units
from Table
group by item_id, day;

给出如下输出:

   day         item_id    max_units
2021-11-23      item1         5
2021-11-24      item1         6
2021-11-23      item2         3
....
....

但是在生成输出时,我还需要计算从前一天的交易余额结转的单位。示例:对于 item1,交易很少在2021-11-24 那天结束时的数量是6。现在,如果此项目的下一次交易仅发生在2021-11-26,并假设该日期的顺序如下:[ 4, 2, 3 ]。那么6 应该继续是2021-11-252021-11-26 天的项目的最大单位。

我被困在这里,无法通过 SQL 运行它。目前我正在解决这个问题的方法是分别获取每天的最后一笔交易,然后使用 python 脚本为接下来的几天转发填充这些数据,这在我的情况下是不干净和可扩展的。

我正在 Presto SQL 引擎上运行查询。

【问题讨论】:

如果item1 有一条2021-11-23 的记录,其中max_units 等于10,那么2021-11-26 的行应该是106?跨度> @GuruStron 例如,2021-11-26 的最大值为6。对于每一天,我们只回顾不属于当天的最新记录。另一件事是,一个项目的所有交易都按时间戳排序,并与不断增加的S-No 值相关联。我在想我们是否可以使用这个S-No 列来获取当天的前一条记录-> 基本上类似于S-No of the first record of the day - 1 【参考方案1】:

您可以使用lag窗口函数来获取先前的值并选择它与当前值之间的最大值:

WITH dataset (update_timestamp, item_id, units) AS (
    VALUES (timestamp '2021-11-21 00:00:01', 'item1', 10),
        (timestamp '2021-11-23 00:00:02', 'item1', 6),
        (timestamp '2021-11-23 00:00:03', 'item2', 1),
        (timestamp '2021-11-24 00:00:01', 'item1', 2),
        (timestamp '2021-11-24 00:00:04', 'item1', 5)
)
SELECT item_id,
    day,
    coalesce( -- greatest will return NULL if one of the arguments is NULL so fallback to "current"
        greatest(
            max_units,
            lag(max_units) over (
                partition by item_id
                order by day
            )
        ),
        max_units
    ) as max_units
FROM (
        SELECT item_id,
            date_trunc('day', update_timestamp) day,
            max(units) as max_units
        FROM dataset
        GROUP BY item_id,
            date_trunc('day', update_timestamp)
    )

输出:

item_id day max_units
item2 2021-11-23 00:00:00.000 1
item1 2021-11-21 00:00:00.000 10
item1 2021-11-23 00:00:00.000 10
item1 2021-11-24 00:00:00.000 6

【讨论】:

【参考方案2】:

我认为我的答案非常接近 Guru 的答案。我假设您可能需要填写缺少的日期,因此创建了一个日历表 - 替换为您想要的任何日期。

这是用 BigQuery 编写的,所以不确定它是否会在 Presto 中编译/执行,但我认为它们在语法上很接近。

   with transactions as (
        select cast('2021-11-17' as date) as update_timestamp, 'item1' as item_id, 3 as units union all
        select cast('2021-11-18' as date), 'item2', 1 union all
        select cast('2021-11-18' as date), 'item2', 5 union all
        select cast('2021-11-20' as date), 'item1', 2 union all
        select cast('2021-11-20' as date), 'item2', 3 union all
        select cast('2021-11-20' as date), 'item2', 2 union all
        select cast('2021-11-20' as date), 'item1', 10 union all
        select cast('2021-11-24' as date), 'item1', 8 union all
        select cast('2021-11-24' as date), 'item1', 5
    ),
    
    some_calendar_table AS (
        SELECT cast(d as date) as cal_date
        FROM UNNEST(GENERATE_DATE_ARRAY('2021-11-15', '2021-11-30', INTERVAL 1 DAY)) AS d 
    ),

    daily_transaction_max as (
        SELECT update_timestamp AS transaction_date,
        item_id,
        MAX(units) as max_value
        from transactions
        group by item_id, transaction_date
    )


  select cal.cal_date
  , t.item_id
  , mt.max_value as max_inventory_from_this_dates_transactions
  , greatest(coalesce(mt.max_value, 0), coalesce(last_value(mt.max_value ignore nulls) over(partition by t.item_id 
        order by cal.cal_date 
        rows between unbounded preceding and 1 preceding)
  , 0)) as max_daily_inventory
  from some_calendar_table cal
  cross join (select distinct item_id from daily_transaction_max) t
  left join daily_transaction_max mt
    on mt.transaction_date = cal.cal_date
    and mt.item_id = t.item_id
  order by t.item_id, cal.cal_date

【讨论】:

以上是关于SQL 从存储事务的表中查找每日最大单位的主要内容,如果未能解决你的问题,请参考以下文章

Redshift 查询每日生成的表

SQL每日一练(牛客新题库)——第2天: 条件查询

每日日报

每日日报

每日干货:简说Spring事务

如何从 sql server 2008 中具有不同 TaskIds 的表中查找日期?