如何使用 postgres 10 将最新的 2 行加入到视图中
How to join latest 2 rows into a view using postgres 10
我想创建一个视图,我可以在其中将两个最新状态及其时间戳和评论加入到视图中。我知道我可以使用 min 和 max 作为时间戳,但是我怎样才能正确设置它们的注释(参见代码中的注释)?最有效的方法是什么? (除了评论,我还有大约 10 列我需要加入以了解当前和以前的状态)。
我正在使用 postgres v10
SELECT
w.workplace_id,
max(current_and_previous_statuses.timestamp) AS current_status_timestamp,
min(current_and_previous_statuses.timestamp) AS previous_status_timestamp
-- current_status.comment
-- previous_status.comment
FROM workplace w
LEFT JOIN (
SELECT
ws.workplace_status_id,
ws.timestamp,
ws.fk_workplace_id,
ws.comment
FROM workplace_status ws
ORDER BY ws.timestamp DESC
LIMIT 2
) current_and_previous_statuses ON current_and_previous_statuses.fk_workplace_id = w.workplace_id
GROUP BY w.workplace_id
您可以使用解析函数如下:
SELECT
workplace_id,
max(timestamp) AS current_status_timestamp,
min(timestamp) AS previous_status_timestamp,
Max(case when rn = 1 the comment end) as current_comment,
Max(case when rn = 2 the comment end) as previous_comment,
From
(Select w.workplace_id, ws.timestamp, ws.comment,
Row_number() over (partition by w.workplace_id order by ws.timestamp desc) as rn
FROM workplace w
LEFT JOIN workplace_status ws
ON ws.fk_workplace_id = w.workplace_id) t
Where rn <= 2
GROUP BY workplace_id
最有效的方法可能是两个横向连接:
select w.*, ws1.timestamp, ws2.timestamp, ws1.comment, ws2.comment
from workplace w left join lateral
(select ws.*
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
order by ws.timestamp desc
limit 1
) ws1
on 1=1 left join lateral
(select ws.*
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
order by ws.timestamp desc
limit 1 offset 1
) ws2
on 1=1;
为了提高性能,这需要 worksplace_status(workplace_id, timestamp)
上的索引。
一个类似的替代方案——而且性能可能非常相似——是使用单个子查询:
select w.*, ws.*
from workplace w cross join lateral
(select max(timestamp) filter (where seqnum = 1) as max_timestamp,
max(timestamp) filter (where seqnum = 2) as min_timestamp,
max(comment) filter (where seqnum = 1) as max_comment,
max(comment) filter (where seqnum = 2) as min_comment
from (select ws.*,
row_number() over (partition by ws.fk_workplace_id order by ws.timestamp desc) as seqnum
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
)
where seqnum <= 2
) ws;
在这两种情况下,这些都避免了对较大数据集的聚合,这应该是性能的胜利。
感谢以上回答!
其实我是用postgres lag函数解决的
使用滞后函数,我能够创建一个子查询,我首先将前面的列“滞后”到工作场所状态。所以每一行都包含先前状态的信息。之后就是一个简单的left join。
我想创建一个视图,我可以在其中将两个最新状态及其时间戳和评论加入到视图中。我知道我可以使用 min 和 max 作为时间戳,但是我怎样才能正确设置它们的注释(参见代码中的注释)?最有效的方法是什么? (除了评论,我还有大约 10 列我需要加入以了解当前和以前的状态)。
我正在使用 postgres v10
SELECT
w.workplace_id,
max(current_and_previous_statuses.timestamp) AS current_status_timestamp,
min(current_and_previous_statuses.timestamp) AS previous_status_timestamp
-- current_status.comment
-- previous_status.comment
FROM workplace w
LEFT JOIN (
SELECT
ws.workplace_status_id,
ws.timestamp,
ws.fk_workplace_id,
ws.comment
FROM workplace_status ws
ORDER BY ws.timestamp DESC
LIMIT 2
) current_and_previous_statuses ON current_and_previous_statuses.fk_workplace_id = w.workplace_id
GROUP BY w.workplace_id
您可以使用解析函数如下:
SELECT
workplace_id,
max(timestamp) AS current_status_timestamp,
min(timestamp) AS previous_status_timestamp,
Max(case when rn = 1 the comment end) as current_comment,
Max(case when rn = 2 the comment end) as previous_comment,
From
(Select w.workplace_id, ws.timestamp, ws.comment,
Row_number() over (partition by w.workplace_id order by ws.timestamp desc) as rn
FROM workplace w
LEFT JOIN workplace_status ws
ON ws.fk_workplace_id = w.workplace_id) t
Where rn <= 2
GROUP BY workplace_id
最有效的方法可能是两个横向连接:
select w.*, ws1.timestamp, ws2.timestamp, ws1.comment, ws2.comment
from workplace w left join lateral
(select ws.*
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
order by ws.timestamp desc
limit 1
) ws1
on 1=1 left join lateral
(select ws.*
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
order by ws.timestamp desc
limit 1 offset 1
) ws2
on 1=1;
为了提高性能,这需要 worksplace_status(workplace_id, timestamp)
上的索引。
一个类似的替代方案——而且性能可能非常相似——是使用单个子查询:
select w.*, ws.*
from workplace w cross join lateral
(select max(timestamp) filter (where seqnum = 1) as max_timestamp,
max(timestamp) filter (where seqnum = 2) as min_timestamp,
max(comment) filter (where seqnum = 1) as max_comment,
max(comment) filter (where seqnum = 2) as min_comment
from (select ws.*,
row_number() over (partition by ws.fk_workplace_id order by ws.timestamp desc) as seqnum
from workplace_status ws
where ws.fk_workplace_id = w.workplace_id
)
where seqnum <= 2
) ws;
在这两种情况下,这些都避免了对较大数据集的聚合,这应该是性能的胜利。
感谢以上回答!
其实我是用postgres lag函数解决的
使用滞后函数,我能够创建一个子查询,我首先将前面的列“滞后”到工作场所状态。所以每一行都包含先前状态的信息。之后就是一个简单的left join。