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-25
和2021-11-26
天的项目的最大单位。
我被困在这里,无法通过 SQL 运行它。目前我正在解决这个问题的方法是分别获取每天的最后一笔交易,然后使用 python 脚本为接下来的几天转发填充这些数据,这在我的情况下是不干净和可扩展的。
我正在 Presto SQL 引擎上运行查询。
【问题讨论】:
如果item1
有一条2021-11-23
的记录,其中max_units
等于10
,那么2021-11-26
的行应该是10
或6
?跨度>
@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 从存储事务的表中查找每日最大单位的主要内容,如果未能解决你的问题,请参考以下文章