1

我有一个名为 BoxPeg 的链接表,它将一系列 Pegs 绑定到 1 个 Box。

问题是 Pegs 是有序的,并且在客户端软件中被视为一个数组。

所以我们在 BoxPeg 表中有一个名为 'position' 的 INT UNSIGNED 列。

每次有人将 Peg 添加到 Box 时,我们都会这样做:

UPDATE BoxPeg SET position = position+1 WHERE box = '{BOXID}' AND position >= {NEWPEGPOSITION};
INSERT INTO BoxPeg(box, peg, position) VALUES('{BOXID}', '{PEGID}', {NEWPEGPOSITION});

这工作正常,直到客户以某种方式通过一个太大的新挂钩位置:

before:
0
1
2
3

after insert 9
0
1
2
3
9

我知道我可以在这两行之前的单独 SQL 语句中获得 MAX(position) WHERE box = '{BOXID}' 并基于此调整新的挂钩位置,但我想简单地重新排列整个系列在插入后一次拍摄。通过这种方式,我 100% 确定该系列从头到尾没有任何空白。

UPDATE 会是什么样子?

考虑这种情况:

before:
0
2
5
8

after insert 5
0
2
5
6
9

after reflow
0
1
2
3
4
4

1 回答 1

0

您可以像这样重新排列行:

UPDATE BoxPeg bp
INNER JOIN (
  SELECT *, @n := @n + 1 AS newpos
  FROM BoxPeg, (SELECT @n := -1) x
  WHERE box = '{BOXID}'
  ORDER BY position
) s
 ON bp.box = s.box
AND bp.peg = s.peg
SET bp.position = s.newpos
WHERE bp.position <> s.newpos
;

子选择使用变量来计算position由特定 定义的子集的新值{BOXID}。然后 UPDATE 语句将子选择连接到BoxPeg并使用新值更新匹配的行。(因此,当加入 时BoxPeg,子选择也充当过滤器,将更新的行限制为属于给定框的行。)

此查询的 SQL Fiddle 演示可用

请注意,如果position列是唯一约束的一部分,则此方法可能并不总是有效。尽管此查询生成的新值是唯一的,但 MySQL 似乎在更新期间而不是在语句执行结束时评估唯一约束。因此,根据更新行的顺序,如果一行接收到的值与另一个尚未更新的行中的值相同,则查询可能会失败。

于 2013-02-18T07:20:21.823 回答