这有点让人头疼,但这是我的想法:
create table orderedtable (
pk SERIAL PRIMARY KEY,
ord INTEGER NOT NULL,
UNIQUE(ord) DEFERRABLE INITIALLY DEFERRED
)
DEFERRABLE INITIALLY DEFERRED 很重要,这样中间状态才不会在重新排序期间导致违反约束。
INSERT INTO orderedtable (ord) VALUES (1),(2),(3),(4),(5),(10),(11)
请注意,在此表中插入时,在ord 值之间留出间隙会更有效,以便在稍后插入或移动行时将需要移动的订单值的数量降至最低。连续值用于演示目的。
诀窍在于:您可以使用递归查询找到从特定值开始的连续值序列。
例如,假设您想在位置 3 上方插入或移动一行。一种方法是将当前位于位置 4 和 5 的行向上移动一个以打开位置 4。
WITH RECURSIVE consecutives(ord) AS (
SELECT ord FROM orderedtable WHERE ord = 3+1 --start position
UNION ALL
SELECT orderedtable.ord FROM orderedtable JOIN consecutives ON orderedtable.ord=consecutives.ord+1 --recursively select rows one above, until there is a hole in the sequence
)
UPDATE orderedtable
SET ord=orderedtable.ord+1
FROM consecutives
WHERE orderedtable.ord=consecutives.ord;
上面将ord 从1,2,3,4,5,10,11 重新编号为1,2,3,5,6,10,11,在4 处留下一个洞。
如果 ord=4 已经有一个洞,上面的查询就不会做任何事情。
然后插入或移动另一行,给它现在免费的ord 值 4。
您可以通过将 +1 更改为 -1 来向下而不是向上推行。