Pojedyncza operacja zamiany...
ZAMIANA(@stara_poz, @nowa_poz)
UPDATE
my_table
SET
position = CASE WHEN position = @old_pos THEN @new_pos ELSE @old_pos END
WHERE
position IN (@old_pos, @new_pos)
Nie jest to jednak łatwe do rozszerzenia do tabeli operacji wymiany. Dzieje się tak dlatego, że będzie próbował wykonać wszystkie zamiany naraz, podczas gdy w rzeczywistości zamiany muszą nastąpić w określonej kolejności...
Ponadto, jeśli chcesz wykonać SWAP(@id, @new_pos), musisz wykonać podzapytanie lub samodzielne dołączenie do aktualizowanej tabeli. MySQL tego nie lubi i chociaż istnieją sposoby na obejście tego ograniczenia, powoduje to trochę bałaganu...
UPDATE
my_table
INNER JOIN
(SELECT position AS old_pos, @new_pos AS new_pos FROM (SELECT position FROM my_table WHERE id = @id)) AS params
ON my_table.position IN (params.old_pos, params.new_pos)
SET
myTable.position = CASE WHEN position = old_pos THEN new_pos ELSE old_pos END
(myślę to zadziała)
UWAGA:
Oba zakładają, że znaleziono ZARÓWNO @old_pos i @new_pos, lub @id i @new_pos, nie jest to sprawdzane i będzie narobić bałaganu, jeśli nie istnieją.
Można to rozwiązać, umieszczając go w transakcji i wycofując, jeśli ROW_COUNT() pokazuje, że tylko 1 rekord został zaktualizowany.