MySQL自然排序

时间:2014-03-03 18:42:11

标签: mysql

背景

我有一个团队的想法,这是一个项目的集合。每个项目由两个属性定义:它们所属的组以及它们在组中的位置。

表格结构

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语句是除了使用表锁之外使其成为原子的唯一方法。

3 个答案:

答案 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}}。

但是,这个查询的表现可能会令人发指。