首页 > 解决方案 > Postgres Group 通过保留先前的顺序

问题描述

我有一个像这样的查询:

SELECT foo_id, bar, timestamp, ROW_NUMBER() OVER (ORDER BY timestamp ASC)
FROM foo_table
WHERE (foo_id = '1' OR related_foo_id = '1')
AND foo_body -> 'type' = 'My_foo_type';

我明白了:

╔═════════╦══════════╦══════════════╦══════════════╦
║ foo_id  ║    bar   ║  timestamp   ║  row_number  ║
╠═════════╬══════════╬══════════════╬══════════════╬
║  1      ║     1    ║      10      ║       1      ║
║  1      ║     1    ║      11      ║       2      ║
║  2      ║     1    ║      15      ║       3      ║
║  1      ║     2    ║      25      ║       4      ║
║  1      ║     2    ║      26      ║       5      ║
╚═════════╩══════════╩══════════════╩══════════════╩

我想按 'foo_id' 和 'bar' 值分组以获得如下结果:

╔═════════╦══════════╦══════════════╦══════════════╦
║ foo_id  ║    bar   ║  timestamp   ║  row_number  ║
╠═════════╬══════════╬══════════════╬══════════════╬
║  1      ║     1    ║      10      ║       1      ║
║  2      ║     1    ║      15      ║       2      ║
║  1      ║     2    ║      25      ║       3      ║
╚═════════╩══════════╩══════════════╩══════════════╩

按 foo_id 和 bar 分组我必须去掉时间戳列,但我需要按它排序。我真的不在乎我得到的第一行还是第二行总是 (foo_id, bar) 在结果中是唯一的。

我尝试对结果进行排序和分组:

SELECT A.foo_id, A.bar, ROW_NUMBER() OVER ()
FROM (
  SELECT foo_id, bar FROM foo_table
  WHERE (foo_id = '1' OR related_foo_id = '1')
  AND foo_body -> 'type' = 'My_foo_type';
  ORDER BY timestamp ASC) A
GROUP BY foo_id, bar;

但它不尊重顺序:

╔═════════╦══════════╦══════════════╦══════════════╦
║ foo_id  ║    bar   ║  timestamp   ║  row_number  ║
╠═════════╬══════════╬══════════════╬══════════════╬
║  1      ║     1    ║      10      ║       1      ║
║  1      ║     2    ║      25      ║       2      ║
║  2      ║     1    ║      15      ║       3      ║
╚═════════╩══════════╩══════════════╩══════════════╩

在其他问题的答案之后还尝试了不同的连接,但我没有找到正确的连接。我总是得到第一次选择的相同结果。

有没有办法在不影响性能的情况下获得我想要的东西?谢谢

标签: sqlpostgresqlgroup-bysql-order-by

解决方案


我想你想要distinct on

SELECT DISTINCT ON (foo_id, bar) foo_id, bar, timestamp, ROW_NUMBER() OVER (ORDER BY timestamp ASC)
FROM foo_table
WHERE (foo_id = 1 OR related_foo_id = 1) AND
      foo_body -> 'type' = 'My_foo_type'
ORDER BY foo_id, bar, timestamp asc;

这将返回每个foo_id/bar组合的一行 - 具有最低时间戳的行。这是基于order byanddistinct on子句。

DISTINCT ON是一个 Postgres 扩展,非常方便,是执行此类查询的最有效方式。


推荐阅读