I am looking for the most efficient way to update a number of rows selected by a where and order by statement, so that the position 1 to n is saved to those rows. For same values in the ordering field, there should be the same position, but then the next position(s) would have to be skipped.
ID, catagory_id, price, position
1, 1, 19.99, NULL
2, 2, 9.99, NULL
3, 1, 9.99, NULL
4, 1, 9.99, NULL
5, 1, 2.99, NULL
UPDATE stuff SET position=XXX WHERE category_id = 1 ORDER BY price ASC
ID, catagory_id, price, position
1, 1, 19.99, 4
2, 2, 9.99, NULL
3, 1, 9.99, 2
4, 1, 9.99, 2
5, 1, 2.99, 1
Note that position=2 is set twice and thus position=3 is omitted.
Is that possible with a single SQL query? I don’t want to issue an update statement for each row as there will be millions I will have to update daily.
Without the same positions, I have used:
SELECT @row:=0;
UPDATE offers SET position = (@row:=@row+1) WHERE category_id = 1 ORDER BY price ASC;
Your question is not clear. As I understand you want to populate the position column with the rank of a particular row in given category.
[1] Initinalize:
SELECT @pos:=0, @prev_price:=-1.0, @omitted:=0;[2] Use this query to get the required position numbers:
SELECT id, IF(price > @prev_price, @pos:=@omitted+@pos+1, @pos) AS position, IF(@prev_price = price, @omitted:=@omitted+1, @omitted:=0), @prev_price:=price FROM offers WHERE category_id = 1 ORDER BY price ASC;[3] Now the result set to do
INSERT .... ON DUPLICATE KEY UPDATEINSERT INTO offers (id, position) SELECT A.id, A.position FROM (SELECT id, IF(price > @prev_price, @pos:=@omitted+@pos+1, @pos) AS position, IF(@prev_price = price, @omitted:=@omitted+1, @omitted:=0), @prev_price:=price FROM offers WHERE category_id=1 ORDER BY price ASC) AS A ON DUPLICATE KEY UPDATE position = A.position;