获取按ID分组的每个最新记录的价值

时间:2019-05-07 09:15:30

标签: sql postgresql greatest-n-per-group

我有一个随时间推移存储的数据记录表,看起来像这样:

|| ID || timestamp || position || value || field1 || field2 ||

另一个表示地理点的表格大致如下:

|| ID || position || field1 || field2 ||

每个表的field1和field2属于同一类别(这使我可以进行比较)

我有一个查询,它给我(从点数表中)最接近每个记录的点,如下所示:

SELECT B.ID, A.timestamp as date, A.value, A.field1, A.field2
FROM (SELECT DISTINCT ON (ID) * FROM records) AS A
CROSS JOIN LATERAL (SELECT *
                    FROM points
                    ORDER BY A.position <-> geom
                    LIMIT 1) AS B
WHERE A.field1 = B.field1
AND A.field2 = B.field2

这让我确切地知道记录的价值来自何处。

我需要获取每个点的最新值,我是这样开始的:

SELECT B.ID, MAX(A.timestamp) as date, A.field1, A.field2
FROM (SELECT DISTINCT ON (ID) * FROM records) AS A
CROSS JOIN LATERAL (SELECT *
                    FROM points
                    ORDER BY A.position <-> geom
                    LIMIT 1) AS B
WHERE A.field1 = B.field1
AND A.field2 = B.field2
GROUP BY B.ID, A.field1, A.field2

但是我不知道如何从结果集中的数据记录中获取值,现在,如果我只是简单地将其添加到顶部,它将要求我将其添加到GROUP BY子句中。

我已经阅读了使用INNER JOIN或LATERAL JOIN所需的其他答案,但是在这种情况下,它每秒搜索每个记录的最近点,从而大大降低了请求速度。有什么方法可以避免两次执行请求,然后使用field1和field2对其进行匹配?

编辑:

这是数据记录的样子(位置确实很长而且不相关,所以我决定不显示它们)

ID  |      timestamp      |   position   | value |   field1   |  field2
----|---------------------|--------------|-------|------------|-----------
001 | 2019-05-03 17:50:00 |    {....}    |   5   |   South    |  Forward
----|---------------------|--------------|-------|------------|-----------
002 | 2019-05-03 17:55:00 |    {....}    |  17   |   South    |  Forward
----|---------------------|--------------|-------|------------|-----------
003 | 2019-05-03 18:30:00 |    {....}    |   0   |   South    |  Backward
----|---------------------|--------------|-------|------------|-----------
004 | 2019-05-03 13:20:00 |    {....}    |  25   |    West    |  Forward
----|---------------------|--------------|-------|------------|-----------
005 | 2019-05-03 14:30:00 |    {....}    |  36   |    West    |  Backward
----|---------------------|--------------|-------|------------|-----------
006 | 2019-05-03 16:00:00 |    {....}    |  12   |    West    |  Backward

运行第一个查询(以获取最接近的点)后,我得到了:

 B.ID |      timestamp      | value |   field1   |  field2
------|---------------------|-------|------------|-----------
 475  | 2019-05-03 17:50:00 |   5   |   South    |  Forward
------|---------------------|-------|------------|-----------
 263  | 2019-05-03 17:55:00 |  17   |   South    |  Forward
------|---------------------|-------|------------|-----------
 157  | 2019-05-03 18:30:00 |   0   |   South    |  Backward
------|---------------------|-------|------------|-----------
 957  | 2019-05-03 13:20:00 |  25   |    West    |  Forward
------|---------------------|-------|------------|-----------
 547  | 2019-05-03 14:30:00 |  36   |    West    |  Backward
------|---------------------|-------|------------|-----------
 547  | 2019-05-03 16:00:00 |  12   |    West    |  Backward

其中B.ID对应于最接近记录位置的点。

运行查询以获取每个[ID / field1 / field2]组合的最新记录时,我得到的是:

 B.ID |      timestamp      |   field1   |  field2
------|---------------------|------------|-----------
 475  | 2019-05-03 17:50:00 |   South    |  Forward
------|---------------------|------------|-----------
 263  | 2019-05-03 17:55:00 |   South    |  Forward
------|---------------------|------------|-----------
 157  | 2019-05-03 18:30:00 |   South    |  Backward
------|---------------------|------------|-----------
 957  | 2019-05-03 13:20:00 |    West    |  Forward
------|---------------------|------------|-----------
 547  | 2019-05-03 16:00:00 |    West    |  Backward

您只能在此看到最后一个行消失了,因为它与(ID / field1 / field2)上的最后一个具有相同的组合,并且它更旧。

我想要的是这样:

 B.ID |      timestamp      | value |   field1   |  field2
------|---------------------|-------|------------|-----------
 475  | 2019-05-03 17:50:00 |   5   |   South    |  Forward
------|---------------------|-------|------------|-----------
 263  | 2019-05-03 17:55:00 |  17   |   South    |  Forward
------|---------------------|-------|------------|-----------
 157  | 2019-05-03 18:30:00 |   0   |   South    |  Backward
------|---------------------|-------|------------|-----------
 957  | 2019-05-03 13:20:00 |  25   |    West    |  Forward
------|---------------------|-------|------------|-----------
 547  | 2019-05-03 16:00:00 |  12   |    West    |  Backward

1 个答案:

答案 0 :(得分:0)

您是否只想再次distinct on

SELECT DISTINCT ON (p.ID) p.ID, r.*
FROM (SELECT DISTINCT ON (r.ID) r.* FROM records r
     ) r CROSS JOIN LATERAL
     (SELECT p.*
      FROM points p
      ORDER BY r.position <-> p.geom
      LIMIT 1
     ) p
WHERE r.field1 = p.field1 AND r.field2 = p.field2
ORDER BY p.ID, r.timestamp DESC;

我无法确定您的意图:

(SELECT DISTINCT ON (ID) *
 FROM records
)

至少应该有一个ORDER BY

(SELECT DISTINCT ON (ID) *
 FROM records
 ORDER BY ID
)

但是,您的示例数据和名称ID建议不要重复,因此DISTINCT ON可能不是必需的。