-2

我想创建一个视图,我可以在其中加入两个最新状态及其时间戳和对视图的评论。我知道我可以使用 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
4

3 回答 3

1

您可以使用如下分析函数:

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
于 2021-02-21T10:17:26.987 回答
1

最有效的方法可能是两个横向连接:

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;

在这两种情况下,这些都避免了对更大数据集的聚合,这应该是性能的胜利。

于 2021-02-21T13:07:54.003 回答
0

谢谢楼上的回答!

我实际上使用postgres lag函数解决了它。

使用滞后功能,我能够创建一个子查询,我首先将之前的列“滞后”到工作场所状态。所以每一行都包含之前状态的信息。之后是一个简单的左连接。

于 2021-03-03T06:09:06.983 回答