在 Postgresql 中为每个被拒绝或接受的日期查找第一个 OPENED_DATE
Posted
技术标签:
【中文标题】在 Postgresql 中为每个被拒绝或接受的日期查找第一个 OPENED_DATE【英文标题】:Find first OPENED_DATE for every Denied or Accepted date in Postgresql 【发布时间】:2021-02-27 13:12:03 【问题描述】:我需要找到请求的第一个文档打开日期。对于每个请求,第一步是打开一个文档,然后可以多次拒绝或接受它。我需要在拒绝和接受日期之间找到第一个 open_date。我尝试了LEAD
函数,但它找到了最接近的函数。
我的表格如下所示:
id | document_id | oper_name | created_at |
--------------------------------------------------------------------
24 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:18 |
25 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:19 |
27 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:40:27 |
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 |
29 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:42:16 |
30 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 11:45:01 |
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 |
32 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 12:34:16 |
33 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:12:01 |
34 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 13:42:23 |
35 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 14:40:23 |
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 |
37 | 102 | DOCUMENT_IS_OPENED | 2020-07-06 16:20:45 |
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 |
我的结果应该如下所示:
id | document_id | oper_name | created_at | open_date | parnt_id
28 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24
31 | 102 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29
36 | 102 | DOCUMENT_IS_ACCEPTED| 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32
38 | 102 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37
我尝试了下面的查询,但它没有像我想要的那样工作
select * from (
select id,document_id,event_type,created_at,
LEAD(created_at,-1) OVER (ORDER BY created_at asc) as open_date
from table where document_id = 102 order by created_at asc
) s where event_type in ('DOCUMENT_IS_DENY','DOCUMENT_IS_ACCEPTED')
【问题讨论】:
【参考方案1】:这听上去像是一个孤岛问题。这是一种方法:
select document_id,
max(id) filter(where rn_desc = 1) as id,
max(oper_name) filter(where rn_desc = 1) as oper_name,
max(created_at) as created_at,
min(created_at) as open_date,
max(id) filter(where rn_asc = 1) as parent_id
from (
select t.*,
row_number() over(partition by document_id, grp order by created_at) rn_asc,
row_number() over(partition by document_id, grp order by created_at desc) rn_desc
from (
select t.*,
count(*) filter(where oper_name <> 'DOCUMENT_IS_OPENED') over(partition by document_id order by created_at desc) grp
from mytable t
) t
) t
where 1 in (rn_asc, rn_desc)
group by document_id, grp
order by document_id, id
这个想法是将记录放在组(岛屿)中,其中每个组以非打开操作结束。我们如何定义组:使用从表中的最新日期开始并倒退的非打开操作计数。然后,我们可以使用窗口函数来识别每个岛的起点和终点,并通过条件聚合展示我们感兴趣的列。
Demo on DB Fiddle:
文档 ID |编号 |操作名称 | created_at |开放日期 | parent_id ----------: | -: | :-------------------- | :----------------- | :----------------- | --------: 102 | 28 | DOCUMENT_IS_DENY | 2020-07-06 11:40:31 | 2020-07-06 11:40:18 | 24 102 | 31 | DOCUMENT_IS_DENY | 2020-07-06 11:48:30 | 2020-07-06 11:42:16 | 29 102 | 36 | DOCUMENT_IS_ACCEPTED | 2020-07-06 15:48:30 | 2020-07-06 12:34:16 | 32 102 | 38 | DOCUMENT_IS_DENY | 2020-07-06 16:41:30 | 2020-07-06 16:20:45 | 37【讨论】:
非常感谢它工作正常。从未听说过gaps-and-islands problem
以上是关于在 Postgresql 中为每个被拒绝或接受的日期查找第一个 OPENED_DATE的主要内容,如果未能解决你的问题,请参考以下文章