背景
我有一个团队的想法,这是一个项目的集合。每个项目由两个属性定义:它们所属的组以及它们在组中的位置。
表格结构
CREATE TABLE group (
id INT AUTO_INCREMENT,
--other fields
PRIMARY KEY(id)
) ENGINE = MyISAM;
CREATE TABLE items (
group_refid INT NOT NULL, --points to id in group table
group_pos SMALLINT AUTO_INCREMENT,
--other fields
PRIMARY KEY(group_refid, group_pos)
) ENGINE = MyISAM;
所以现在插入项目效果很好。我需要做的就是:
INSERT INTO items (group_refid) VALUES (1);
,该项目将附加到组的末尾。当我想移动其中一个项目时,我的问题出现了。移动项目应如下工作:
示例:
我在位置1,2,3,4中有三个项目,但我想将位置3中的一个移动到位置1.
预期结果:3,1,2,4,但表中的group_pos
应为1,2,3,4或1,2,3,5
我想这样做,以便保留元素的顺序(除了被移动的元素之外)。有一种很好的方法可以在一个SQL语句中执行此操作吗?我更喜欢一个语句,因为我不能使用事务,所以一个off语句是除了使用表锁之外使其成为原子的唯一方法。
答案 0 :(得分:1)
尝试这样的事情,让你的group_pos
浮动而不是小。
在小提琴中尝试这个sqlFiddle我将@position设置为1以获得第二个位置,如果你希望它在列表中排在第一位,你可以尝试将其设置为0。
SET @position = 1;
UPDATE items SET group_pos =
(SELECT SUM(group_pos)/2 as newGroupPos FROM
(SELECT 0 as group_pos,0 as rank
UNION
SELECT group_pos,@rank:=@rank+1 as rank FROM items,(SELECT @rank:=0)var
WHERE group_refid=1
ORDER BY group_pos
)T1 WHERE rank IN (@position,@position+1)
)
WHERE group_refid=1 AND group_pos=3;
答案 1 :(得分:0)
你可以用2个语句来做。假设您要使用group_refid = 37
重新排列项目,并专门将项目group_pos = 3
移至顶部(将其设为=1
)并将所有其他项目向下移动。
首先把它拉到零位置:
UPDATE items
WHERE group_refid = 37
AND group_pos = 3
SET group_pos = 0 ; -- this is a temporary value
然后将所有这些都推下来:
UPDATE items
WHERE group_refid = 37
SET group_pos = group_pos + 1
ORDER BY group_refid, group_pos DESC ; -- the order by is required
答案 2 :(得分:0)
我认为链接IF语句应该有效:
UPDATE items
SET group_pos =
IF(group_pos = 3, 1, # sets 3 to 1
# otherwise, increment if pos is less than 3
IF(group_pos < 3, group_pos + 1, group_pos))
显然,如果你没有将条件group_pos < 3
移动到第一个位置,条件BETWEEN 2 and 3
必须改变,例如如果你把它移到第二位,到{{1}}。
但是,这个查询的表现可能会令人发指。