在 PostgreSQL 中维护有序列表的最佳方法?

xzh*_*zhu 7 postgresql

假设我有一个名为 的表list,其中有item这样的 s (ids 是随机 uuid):

id  rank  text
--- ----- -----
x   0     Hello
x   1     World
x   2     Foo
x   3     Bar
x   4     Baz
Run Code Online (Sandbox Code Playgroud)

rank我想维护列始终从 到0的属性(n-1n行数)——如果客户端请求insert带有 的项目rank = 3,那么 pg 服务器应分别将当前的3和推送到4和:45

id  rank  text
--- ----- -----
x   0     Hello
x   1     World
x   2     Foo
x   3     New Item!
x   4     Bar
x   5     Baz
Run Code Online (Sandbox Code Playgroud)

我当前的策略是使用一个专用的插入函数add_item(item)来扫描表,过滤掉排名等于或大于要插入的项目的项目,并将这些排名加一。然而,我认为这种方法会遇到各种各样的问题——比如竞争条件。

是否有更标准的做法或更稳健的方法?


注意:排名列完全独立于其余列,插入并不是我需要支持的唯一操作。将其视为可排序待办事项列表的后端,用户可以动态添加/删除/重新排序项目。

Tim*_*sen 0

逐字执行您的建议可能很困难或根本不可能,但我可以建议一种解决方法。维护一个新列ts,用于存储插入记录的时间。然后,插入当前时间以及记录的其余部分,即

id  rank  text      ts
--- ----- -----     --------------------
x   0     Hello     2017-12-01 12:34:23
x   1     World     2017-12-03 04:20:01
x   2     Foo       ...
x   3     New Item! 2017-12-12 11:26:32
x   3     Bar       2017-12-10 14:05:43
x   4     Baz       ...
Run Code Online (Sandbox Code Playgroud)

现在我们可以通过查询轻松生成您想要的排序:

SELECT id, rank, text,
    ROW_NUMBER() OVER (ORDER BY rank, ts DESC) new_rank
FROM yourTable;
Run Code Online (Sandbox Code Playgroud)

这将在上面的示例表中生成 0 到 5 的排名。基本思想是只使用已经存在的rank列,但如果相同的排名出现多次,则让时间戳打破排序的平局。