Reputation: 11394
I have a MySQL table that has the following columns: (id, position, etc.). Position indicates a sort order. How can I rearrange position of items. For example, if I want to rearrange the item at position 3 to position 5 or vice-versa, how can I achieve this?
As requested here is some sample data:
id position name
== ======== ======
1 5 Fred
2 3 Wilma
3 1 Betty
4 2 Barney
5 4 Pebbles
So if I do a select * from customer order by position
I get:
id position name
== ======== =======
3 1 Betty
4 2 Barney
2 3 Wilma
5 4 Pebbles
1 5 Fred
I might then want to move Fred up in the list, say to position 3. I would then like the list to look like this:
id position name
== ======== =======
3 1 Betty
4 2 Barney
1 3 Fred
2 4 Wilma
5 5 Pebbles
My question is, how do I move an item either up or down in the list and get the positions to adjust accordingly?
I guess it would also be important to make sure that there are no missing or repeated position numbers.
Upvotes: 4
Views: 351
Reputation: 1970
you can create a stored procedure to update position:
DELIMITER //
CREATE PROCEDURE simpleproc (IN param1 INT, IN param2 INT)
BEGIN
UPDATE sampleTable SET position = position + 1 WHERE position >= param2;
UPDATE sampleTable SET position = param2 WHERE id = param1;
END;//
DELIMITER ;
Just make sure that position is not set as primary key, i know you want it unique; but it can cause problems with procedure.
btw, param1 is id of record which you want to update and param2 is position that you want to set.
It works just fine.
Upvotes: 1
Reputation: 29667
In this UPDATE example the pos_from and pos_to have to be set.
The position with pos_from will be changed to pos_to.
And the others that need to shift up or down are corrected with +1 or -1 accordingly.
The pos_from can be higher or lower than the pos_to.
create table bedrock ( id int primary key auto_increment, position int not null, name varchar(30) not null );
insert into bedrock (position, name) values (5, 'Fred'), (3, 'Wilma'), (1, 'Betty'), (2, 'Barney'), (4, 'Pebbles');
select * from bedrock order by position;
id | position | name -: | -------: | :------ 3 | 1 | Betty 4 | 2 | Barney 2 | 3 | Wilma 5 | 4 | Pebbles 1 | 5 | Fred
update bedrock join ( select pos_from, pos_to, case when pos_to > pos_from then pos_from else pos_to end as pos_min, case when pos_to > pos_from then pos_to else pos_from end as pos_max, case when pos_to > pos_from then -1 else 1 end as pos_delta from ( select 5 as pos_from, 3 as pos_to ) q1 ) q2 on position between pos_min and pos_max set position = case when position = pos_from then pos_to else position + pos_delta end;
select * from bedrock order by position;
id | position | name -: | -------: | :------ 3 | 1 | Betty 4 | 2 | Barney 1 | 3 | Fred 2 | 4 | Wilma 5 | 5 | Pebbles
db<>fiddle here
Upvotes: 1
Reputation: 1092
I hope, you are expecting this below query.
select *,case when position = 3 then 5 when position = 5 then 3 else position end as new_position from customer order by new_position
Upvotes: -1