This task is performed very easily using window / analytic functions. Since MySQL does not have these, they can be modeled with the following restriction:
- You must have a unique sort field.
I used id
for this purpose.
The following query will list each row in your table, using type
as a section indicator:
SELECT t.id, t.type, t.value, (SELECT count(*) FROM testbed WHERE type = t.type AND id <= t.id) AS rownum FROM testbed t ORDER BY t.type, t.id;
I added ORDER BY
only for visibilty, not required in the final request.
The following query allows you to join 2 results and have a way to “shift values” as follows:
SELECT c.id AS c_id, c.type AS c_type, c.value AS c_value, p.id AS p_id, p.type AS p_type, p.value AS p_value FROM (SELECT t.id, t.type, t.value, (SELECT count(*) FROM testbed WHERE type = t.type AND id <= t.id) AS rownum FROM testbed t) AS c LEFT JOIN (SELECT t.id, t.type, t.value, (SELECT count(*) FROM testbed WHERE type = t.type AND id <= t.id) AS rownum FROM testbed t) AS p ON c.type = p.type AND c.rownum = p.rownum + 1 ORDER BY c.type, c.id;
Finally, your task is accomplished with the following two queries: UPDATE
and DELETE
:
UPDATE testbed AS t JOIN ( SELECT c.id AS c_id, c.type AS c_type, c.value AS c_value, p.id AS p_id, p.type AS p_type, p.value AS p_value FROM (SELECT t.id, t.type, t.value, (SELECT count(*) FROM testbed WHERE type = t.type AND id <= t.id) AS rownum FROM testbed t) AS c LEFT JOIN (SELECT t.id, t.type, t.value, (SELECT count(*) FROM testbed WHERE type = t.type AND id <= t.id) AS rownum FROM testbed t) AS p ON c.type = p.type AND c.rownum = p.rownum + 1 ) AS s ON t.id = s.c_id SET t.value = s.p_value WHERE t.value = 'A';
You can check this query for SQL Fiddle (not updates).