具有任意 LAG 的字段的 Postgres 历史依赖性
Posted
技术标签:
【中文标题】具有任意 LAG 的字段的 Postgres 历史依赖性【英文标题】:Postgres historical dependency for field with arbitrary LAG 【发布时间】:2018-09-05 15:26:59 【问题描述】:我有一个如下所示的 postgres 表:
refnum | period | flag
--------+--------+------
ref01 | 201701 | 0
ref01 | 201702 | 0
ref01 | 201703 | 1
ref01 | 201704 | 0
ref01 | 201705 | 0
ref01 | 201706 | 1
ref01 | 201707 | 0
其中 period 基本上只是一个 int 形式的年月时间戳。我想这样做,以便我们添加一个列来维护标志 = 1 的最后一个时期。所以它应该在最后看起来像这样:
refnum | period | flag | lastPeriod
--------+--------+------+------------
ref01 | 201701 | 0 | NULL
ref01 | 201702 | 0 | NULL
ref01 | 201703 | 1 | 201703
ref01 | 201704 | 0 | 201703
ref01 | 201705 | 0 | 201703
ref01 | 201706 | 1 | 201706
ref01 | 201707 | 0 | 201706
因此,每一行的 lastPeriod 列都取决于前一行中该列的具体化值。我尝试使用窗口函数和 LAG 来执行此操作,但这仅在您知道要回顾的行数时才有效。如果窗口中的每一行都在前一行之后进行评估,那就太好了,但似乎它们是独立于之前的值运行的。我基本上想要的是类似的东西:
SELECT CASE WHEN current_row.flag = 1 THEN current_row.period ELSE prev_row.lastPeriod
我想出了解决这个问题的一种方法,但它基本上涉及创建一个临时表,其中包含标志 = 1 的所有时段,加入该表,然后拉取最大值:
select refnum, period, max(backfill) FROM
(
select refnum, a.period as period, b.period as backfill
FROM my_table a
LEFT JOIN tmp_periods b ON a.period >= b.period
) as foo group by refnum, period order by period;
但我希望我们能以更好的方式做到这一点,因为我们正在查看的表格非常大。
【问题讨论】:
【参考方案1】:你关心寻找一个有条件的最大值:
select t.*,
max(case when flag = 1 then period end) over (partition by refnum order by period) as lastperiod
from t;
更多最新版本的 Postgres 支持 filter
:
select t.*,
max(period) filter (where flag = 1) over (partition by refnum order by period)
from t;
【讨论】:
天哪,太棒了!我想不出将条件逻辑传递给这些窗口/聚合函数的方法。【参考方案2】:如果表有正确的索引,那么你可以使用 correlated 子查询:
select t.*, (case when flag = 1 then period
when flag = 0
then (select t1.period
from table t1
where t1.refnum = t.refnum and
t1.period < t.period and t1.flag = 1
order by t1.period desc
limit 1
)
end) as lastPeriod
from table t;
【讨论】:
这是一个很好的策略。我将不得不对我们的完整数据集进行一些测试,因为可能会在效率方面进行权衡。以上是关于具有任意 LAG 的字段的 Postgres 历史依赖性的主要内容,如果未能解决你的问题,请参考以下文章
使用一个查询递增具有唯一约束的字段中的一组值,Postgres
IntegrityError:postgres 从转储恢复后,所有具有 ForeignKey 的模型/字段的“id”列中的空值