如何 select 与 table 中的项目相关的第一行和最后一行?
How to select the first and last row relevant to an item in a table?
我有以下 events
table 跟踪与各种项目相关的事件:项目创建时间、更新时间以及最后删除时间。
例如它看起来像这样:
id
item_id
type
1
1
create
2
2
create
3
1
update
4
1
update
5
2
update
6
1
delete
7
2
update
8
3
create
所以在这个 table 中创建了项目 1,然后创建了项目 2,然后这两个项目被更新了多次。最后删除了item 1,但是item 2还在。最终项目 3 被创建并且从未被修改。
我正在尝试创建一个查询,为我提供每个项目的第一个和最后一个事件,所以在 运行 这个查询之后我会得到这个:
id
item_id
first_event_type
last_event_type
1
1
create
delete
2
2
create
update
8
3
create
NULL
我尝试了各种查询,但没有比加入 table 本身更进一步,因为我不知道如何表达加入的 table 应该 return 与当前相关的最后一个结果 item_id.
想知道是否可以只用一个查询来做到这一点?
(如果这能有所作为,我正在使用 PostgresSQL)
您可以使用 window 函数和条件聚合:
select item_id,
max(type) filter(where rn_asc = 1) as first_event_type,
max(type) filter(where rn_desc = 1 and rn_asc > 1) as last_event_type
from (
select t.*,
row_number() over(partition by item_id order by id) rn_asc,
row_number() over(partition by item_id order by id desc) rn_desc
from mytable t
) t
where 1 in (rn_asc, rn_desc)
group by item_id
Postgres 不支持“first”和“last”聚合函数。但是你可以接近 array_agg()
:
select item_id,
(array_agg(type order by id))[1] as first_type,
(array_agg(type order by id desc))[1] as last_type
from t
group by item_id;
我有以下 events
table 跟踪与各种项目相关的事件:项目创建时间、更新时间以及最后删除时间。
例如它看起来像这样:
id | item_id | type |
---|---|---|
1 | 1 | create |
2 | 2 | create |
3 | 1 | update |
4 | 1 | update |
5 | 2 | update |
6 | 1 | delete |
7 | 2 | update |
8 | 3 | create |
所以在这个 table 中创建了项目 1,然后创建了项目 2,然后这两个项目被更新了多次。最后删除了item 1,但是item 2还在。最终项目 3 被创建并且从未被修改。
我正在尝试创建一个查询,为我提供每个项目的第一个和最后一个事件,所以在 运行 这个查询之后我会得到这个:
id | item_id | first_event_type | last_event_type |
---|---|---|---|
1 | 1 | create | delete |
2 | 2 | create | update |
8 | 3 | create | NULL |
我尝试了各种查询,但没有比加入 table 本身更进一步,因为我不知道如何表达加入的 table 应该 return 与当前相关的最后一个结果 item_id.
想知道是否可以只用一个查询来做到这一点?
(如果这能有所作为,我正在使用 PostgresSQL)
您可以使用 window 函数和条件聚合:
select item_id,
max(type) filter(where rn_asc = 1) as first_event_type,
max(type) filter(where rn_desc = 1 and rn_asc > 1) as last_event_type
from (
select t.*,
row_number() over(partition by item_id order by id) rn_asc,
row_number() over(partition by item_id order by id desc) rn_desc
from mytable t
) t
where 1 in (rn_asc, rn_desc)
group by item_id
Postgres 不支持“first”和“last”聚合函数。但是你可以接近 array_agg()
:
select item_id,
(array_agg(type order by id))[1] as first_type,
(array_agg(type order by id desc))[1] as last_type
from t
group by item_id;