我正在编写一个非常简单的程序来更新“todo”中的位置INT列。现有行的表。目标是为每个用户逐步设置位置值,从0开始。运行代码时,它似乎只捕获每个用户循环的最终值。有什么我对MySQL的变量有误解吗?或许我弄乱了循环..
这是一个深夜>。<
BEGIN
DECLARE loop_done INT DEFAULT 0;
DECLARE current_user_id INT;
DECLARE current_todo_id INT;
DECLARE todo_position INT DEFAULT 0;
DECLARE cur_users CURSOR FOR
SELECT id FROM users;
DECLARE cur_todos CURSOR FOR
SELECT id FROM todo WHERE user_id = @uid;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET loop_done = 1;
OPEN cur_users;
loop_users: LOOP
FETCH cur_users INTO current_user_id;
IF loop_done = 1 THEN
SET loop_done = 0;
LEAVE loop_users;
END IF;
SET @uid = current_user_id;
SET todo_position = 0;
OPEN cur_todos;
loop_todos: LOOP
FETCH cur_todos INTO current_todo_id;
IF loop_done = 1 THEN
SET loop_done = 0;
SET todo_position = 0;
LEAVE loop_todos;
END IF;
UPDATE todo SET position = todo_position WHERE user_id = @uid;
SET todo_position = todo_position + 1;
END LOOP loop_todos;
CLOSE cur_todos;
END LOOP loop_users;
END$$
以下是实际结果:
+----------+
| position |
+----------+
| 3 |
| 3 |
| 3 |
| 3 |
| 4 |
| 4 |
| 4 |
| 4 |
| 4 |
+----------+
这些是预期结果:
+----------+
| position |
+----------+
| 0 |
| 1 |
| 2 |
| 3 |
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+----------+
答案 0 :(得分:1)
我认为你根本不需要游标
drop table if exists todo;
create table todo (id int, user_id int, position int);
truncate table todo;
insert into todo values (1,1,null),(2,1,null),(2,2,null);
update todo t join (
select id,user_id,
if(user_id <> @p,@rn:=0,@rn:=@rn+1) rn ,
@p:=user_id p
from todo, (select @rn:=0,@p:=0) r
order by user_id,id
) s on s.id = t.id and s.user_id = t.user_id
set position = s.rn
where 1 = 1;
使用变量模拟其他dbs中的行号函数并返回
select * from todo;
+------+---------+----------+
| id | user_id | position |
+------+---------+----------+
| 1 | 1 | 0 |
| 2 | 1 | 1 |
| 2 | 2 | 0 |
+------+---------+----------+
3 rows in set (0.02 sec)