【问题标题】:Postgres Group By preserving the previous orderPostgres Group 通过保留先前的顺序
【发布时间】:2020-10-01 01:20:06
【问题描述】:

我有一个类似的查询:

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      ║
╚═════════╩══════════╩══════════════╩══════════════╩

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

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

【问题讨论】:

    标签: sql postgresql group-by sql-order-by


    【解决方案1】:

    我想你想要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 bydistinct on 子句。

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

    【讨论】:

    • 非常感谢。我已经尝试过 distinct on 但似乎我误解了它的可能性。我不得不在您的解决方案中添加另一个选择以获得正确的行号,但答案对我帮助很大。谢谢
    猜你喜欢
    • 2015-01-04
    • 2023-03-20
    • 2016-06-25
    • 2018-03-16
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2022-08-08
    相关资源
    最近更新 更多