Reputation: 157
I am writing a very simple program to update the location INT column in the 'todo' table for existing rows. The objective is to set the location value incrementally for each user, starting at 0. When running the code, it seems to only capture the final value for each user's loop. Is there something I'm misunderstanding about MySQL's variables? Or maybe I messed up the loops..
This has been a late night >.<
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$$
Here are the actual results:
+----------+
| position |
+----------+
| 3 |
| 3 |
| 3 |
| 3 |
| 4 |
| 4 |
| 4 |
| 4 |
| 4 |
+----------+
These are the expected results:
+----------+
| position |
+----------+
| 0 |
| 1 |
| 2 |
| 3 |
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
+----------+
Upvotes: 1
Views: 852
Reputation: 17615
I don't think you need cursors at all for example
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;
Simulates row number functions found in other dbs using a variable and returns
select * from todo;
+------+---------+----------+
| id | user_id | position |
+------+---------+----------+
| 1 | 1 | 0 |
| 2 | 1 | 1 |
| 2 | 2 | 0 |
+------+---------+----------+
3 rows in set (0.02 sec)
Upvotes: 1