我有以下sortable
表:
| id | txt | position |
|----|-----|----------|
| 1 | aaa | 1 |
| 2 | bbb | 2 |
| 3 | ccc | 3 |
现在,我想更改头寸顺序。假设我想将第3行移至位置1,同时保持其他行的顺序不变:
| id | txt | position |
|----|-----|----------|
| 1 | aaa | 2 |
| 2 | bbb | 3 |
| 3 | ccc | 1 |
在将要放在最上面的行更新到位置0之后,可以通过此查询来实现此目的:
SET @row_number:=0;
UPDATE
sortable,
(
SELECT
@row_number:=ifnull(@row_number, 0)+1 AS new_position,
id
FROM sortable
ORDER BY position
) AS table_position
SET position=table_position.new_position
WHERE table_position.id=sortable.id;
将行移动到第一个位置时,此方法效果很好。但是在尝试将行移动到第二个(或其他任何位置)时会遇到麻烦。
我需要一些帮助修复查询的方法,这样我就可以将任何行移动到任何位置,并且它将相应地更新其他行。因此,如果我将3移至2,则2变为3。如果我将1移至3,则2变为1,而3变为2。希望您能理解。显然,现实世界中的数据将有更多的行。这只是一个例子。
答案 0 :(得分:1)
请考虑以下内容...
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(txt VARCHAR(12) PRIMARY KEY
,position INT NOT NULL
);
INSERT INTO my_table VALUES
('aaa',1),
('bbb',2),
('ccc',3),
('ddd',4),
('eee',5),
('fff',6);
假设我们要将文本从第4位移到第1位...
SELECT *
, CASE WHEN position < 4 THEN position +1
WHEN position = 4 THEN 1
ELSE position END new_pos
FROM my_table
+-----+----------+---------+
| txt | position | new_pos |
+-----+----------+---------+
| aaa | 1 | 2 |
| bbb | 2 | 3 |
| ccc | 3 | 4 |
| ddd | 4 | 1 |
| eee | 5 | 5 |
| fff | 6 | 6 |
+-----+----------+---------+
...我们可以将其重写为UPDATE ...
UPDATE my_table x
JOIN
( SELECT *
, CASE WHEN position < 4 THEN position +1
WHEN position = 4 THEN 1
ELSE position END new_pos
FROM my_table
) y
ON y.txt = x.txt
SET x.position = y.new_pos;
SELECT * FROM my_table;
+-----+----------+
| txt | position |
+-----+----------+
| aaa | 2 |
| bbb | 3 |
| ccc | 4 |
| ddd | 1 |
| eee | 5 |
| fff | 6 |
+-----+----------+
答案 1 :(得分:1)
类似的事情应该起作用:
SET @old_number:=3;
SET @new_number:=5;
UPDATE my_table x
JOIN
(
SELECT *
, CASE WHEN @old_number > @new_number THEN
CASE WHEN position = @old_number THEN @new_number
WHEN position >= @new_number AND position < @old_number THEN position +1
ELSE position END
WHEN @old_number < @new_number THEN
CASE WHEN position = @old_number THEN @new_number
WHEN position <= @new_number AND position > @old_number THEN position -1
ELSE position END
ELSE position END new_position
FROM my_table
ORDER BY position
) y
ON y.position = x.position
SET x.position = y.new_position;
如果您预先进行了一些设置变量的准备工作,这会变得更加简洁:
SET @old_position:=1;
SET @new_position:=5;
SET @low_position = LEAST(@old_position, @new_position);
SET @high_position = GREATEST(@old_position, @new_position);
SET @position_modifier = CASE WHEN @old_position > @new_position THEN 1 ELSE -1 END;
UPDATE my_table x
JOIN
(
SELECT *
, CASE WHEN position = @old_position THEN @new_position
WHEN position BETWEEN @low_position AND @high_position THEN position + @position_modifier
ELSE position
END new_position
FROM my_table
ORDER BY position
) y
ON y.position = x.position
SET x.position = y.new_position;
在后一版本中,子查询的WHEN
语句中CASE
子句的顺序很重要。
基本上,位置需要相应地调整:
当旧职位编号大于新职位编号时,旧职位和新职位之间的所有职位(不包括旧职位)都需要增加。
当旧职位编号小于新职位编号时,旧职位与新职位之间的所有职位(不包括旧职位)都需要递减。
注意BETWEEN
包含范围,这就是WHEN
子句的顺序很重要的原因。您希望当前位置与旧位置编号的匹配首先发生,以免通过WHEN
测试而落入BETWEEN
。