我有一个 Postgres 表
foobar
具有以下架构:
id: integer
group: integer
foo: integer
bar: integer
timestamp: integer
我跟踪各个组的更新,这些更新会改变
foo
和 bar
属性。每次收到更新时,我都会存储时间戳。
这是我可以在数据库中获得的示例值:
+------+---------+-------+-------+-------------+
| "id" | "group" | "foo" | "bar" | "timestamp" |
+------+---------+-------+-------+-------------+
| 1 | 1 | 10 | 20 | 1 |
| 2 | 1 | 11 | 19 | 2 |
| 3 | 1 | 10 | 20 | 3 |
| 4 | 1 | 10 | 20 | 4 |
+------+---------+-------+-------+-------------+
我收到的更新通常是相同的。我试图提取的一条特别关键的信息是当我第一次收到当前值的组合时 - 但不是第一次,而是第一次更新,之后没有任何更改。
一个简单的方法是以下查询:
SELECT DISTINCT ON ("group", foo, bar) *
FROM foobar
ORDER BY "group", foo, bar, timestamp DESC;
但是,该查询将返回最后一行,该行具有最新的时间戳。如果我将时间戳切换为
ASC
,我将获得第一行,因为我在时间戳 2 更新之前已经看到了确切的 foo/bar 值组合。
直观的做法是简单地将
timestamp DESC
排序命令移到 foo
之前,但 Postgres 不允许这样做。像 MySQL 的 HAVING
操作之类的东西也可以派上用场,但不幸的是 Postgres 不支持这一点。
我可以采取的一种极其低效的方法是以编程方式迭代每个组,获取最新行,然后按降序时间戳顺序获取所有行,并在观察到更改后立即停止,但似乎让数据库执行这种操作操作会更明智。
我很确定我错过了一些明显的东西,但非常感谢任何帮助。谢谢!
您可以采用老式的方法,使用
row_number
窗口函数进行“distinct on”选择:
select * from
(
select *,
row_number() over (partition by "group", foo, bar order by timestamp DESC) rn
from foobar
) t
where rn = 1;