从 Postgres 中的非结束日期范围列表中查找未覆盖的日期范围
Posted
技术标签:
【中文标题】从 Postgres 中的非结束日期范围列表中查找未覆盖的日期范围【英文标题】:Finding non-overridden date range from a list of non-ending date ranges in Postgres 【发布时间】:2021-01-07 14:39:10 【问题描述】:我有一个表格来存储从给定日期开始的sku
的价格:start_date
。对于sku
的新价格,此表中可能有多个条目,新的start_date
。从添加新价格之日起,每个新条目都会覆盖上一组行中的价格。
表结构是这样的:
sku_id | start_date | price
100 | "2020-01-10" | 100
100 | "2020-01-20" | 200
100 | "2020-01-30" | 300
有了这些条目,10th Jan
、21st Jan
和 31st Jan
的价格将分别显示为 100
、200
和 300
。
现在,如果我们在此表中输入另一个条目,开始日期为1st Jan
,价格为500
。然后,直到覆盖所有这 3 个价格。然后,之前获取的所有 3 个日期的价格现在将变为 500
。
sku_id | start_date | price
100 | "2020-01-10" | 100
100 | "2020-01-20" | 200
100 | "2020-01-30" | 300
100 | "2020-01-01" | 500 -> This row overrides prices of all 3 rows before it. Since start date `2020-01-01` is less then all their start date.
鉴于这个表结构,这是我的要求:
我想获取所有仍处于活动状态的记录(这意味着它们不会被任何新创建的行完全覆盖)。我想到了使用 LEAD 函数,它可以让我得到每一行的 end_date。
SELECT sku_id, start_date, price,
LEAD(start_date, 1) OVER (
PARTITION BY sku_id ORDER BY created_at
) - INTERVAL '1 day' AS end_date
FROM rate;
这个查询给了我这个结果:
sku_id | start_date | price | end_date
100 | "2020-01-10" | 100 | "2020-01-19"
100 | "2020-01-20" | 200 | "2020-01-29"
100 | "2020-01-30" | 300 | "2019-12-31"
100 | "2020-01-01" | 500 |
在此之后,我需要一些查询,它可以拒绝第 1、2 和 3 行,因为它们的开始日期小于第 3 行的结束日期。这是我无法理解如何实现的。
如果问题的标题没有意义,真的很抱歉,因为我想不出要给出什么问题的标题。
我采用的另一种方法是按降序保持加载记录。然后使用该记录作为游标,获取 start_date 小于该记录开始日期的先前行。但这会导致大量往返数据库,这是我想避免的。
如果有一个解决方案,只需一个 SQL 查询即可获得我正在寻找的内容,那就太好了。
【问题讨论】:
您打算在桌子上放多少行。可以完成查询,但根据表的大小,可能会出现严重的性能问题。如果性能是您所需要的,那么您必须使用另一种方法来解决这个问题,而不仅仅是窗口查询。 每个 sku,这个表不会有那么多行。您可以说,每个 sku 将少于 1000 行。 我很难相信前三行的start_date
s 小于第三行的end_date
,因为我很确定 2020 年 > 2019 年。这整件事充其量是可疑的。
@AdrianKlaver 我认为您没有完全阅读这个问题。坦率地说,我无法更好地解释它。当您假设有可能为未来日期设置价格时,这一切都是有道理的,这发生在酒店房间预订软件中。
【参考方案1】:
以下查询可以提供所需的输出。
select t.sku_id, t.start_date, t.price, t.created_at from
(select rate.*, min(start_date) over (partition by sku_id order by created_at desc) as calculated_date
from rate) t
where t.calculated_date = t.start_date
说明:
使用windows函数,为当前记录之后创建的条目确定min start date
。
如果开始日期大于计算出的min start date
,则过滤掉记录。
参考:https://www.db-fiddle.com/f/uZgWjur4cmqwUjuLPcCNP5/1
【讨论】:
以上是关于从 Postgres 中的非结束日期范围列表中查找未覆盖的日期范围的主要内容,如果未能解决你的问题,请参考以下文章