PostgreSQL return 可以用后一个值覆盖前一个值的值列表吗?

Can PostgreSQL return a list of values with latter values overwriting previous ones?

下面的 table 代表给定文件的许可决定事件。

我想以文件的许可列表结束。如果事件的 Removed 列为 False,则添加一个许可证,但每个文件的每个许可证不超过一个。如果事件的 Removed 列为 True,则推翻该特定许可证的所有先前添加事件。稍后发生的事件优先于之前发生的事件。

对于下面的事件,我想要 return [A, B] 的列表。许可证 A 有事件添加、删除、添加,因此它是 returned。许可证 B 有事件添加、添加,因此它被 returned,但没有被复制。许可证 C 有事件添加、添加、删除,因此它不会被删除,因为后者删除会使两个添加事件无效。

这是否可以通过 PostgreSQL 查询实现,或者我需要事后处理数据?

+------+---------+---------+
| Time | License | Removed |
+------+---------+---------+
|    1 | A       | False   |
|    2 | A       | True    |
|    3 | A       | False   |
|    4 | B       | False   |
|    5 | B       | False   |
|    6 | C       | False   |
|    7 | C       | False   |
|    8 | C       | True    |
+------+---------+---------+

您可以在子查询中使用 distinct on 来过滤每个许可证的最后一条记录,然后过滤掉那些被删除的记录:

select license
from (select distinct on (license) t.* from mytable t order by license, time desc) t
where not removed

如果我理解正确,您希望每个许可证都有 last 事件。如果您知道 window 函数的工作原理,这将非常简单:您可以使用 windows 对 table 进行分区,然后通过排序等在每个 window 内部进行操作。在这种情况下,您想要对许可证进行分区,然后按时间排序(降序),最后 select 每个 window:

的最新条目
SELECT "License", "Removed" FROM (
    SELECT *, rank() OVER (PARTITION BY "License" ORDER BY "Time" DESC)) X
 WHERE rank = 1

如果您想更好地理解它是如何工作的,请尝试自己执行内部 SELECT

您可以为此使用聚合:

select license
from t
group by license
having max(time) = max(time) filter (where not removed);

having 子句正在检查许可证的最长时间是否为 "removed"。

这三个答案都很有道理。一般来说,distinct on 在 Postgres 中比 row_number() 更适合获取一行。如果你对子查询有严格的反感,我提供这个。