Usually I add an int or smallint column with the name "Ordinal" or "PositionOrdinal", as you suggest, and with an exact warning you indicate - the need to update a potentially significant number of records each time you re-order one record.
The advantage is that taking into account the key for a specific task and the new position for this task, the code for moving an element is just two operators:
UPDATE `Tasks` SET Ordinal= Ordinal+1 WHERE Ordinal> =@NewPosition UPDATE `Tasks` SET Ordinal= @NewPosition WHERE TaskID= @TaskID
There are other suggestions for a doubly linked list or lexical order. Or it can be faster, but at the cost of much more complex code, and performance will only matter if there is a lot of elements in the same group.
Whether performance or complexity of the code is important will depend on your situation. If you have millions of records, the added complexity may be worth it. However, I usually prefer simpler code, because users usually order only small lists manually. If there are not many items in the list, additional updates will not matter. This can usually handle thousands of records without a noticeable impact on performance.
The only thing to remember in your updated example is that the column is used only for sorting, and not for others that are displayed directly to the user. Thus, when dragging an item from top to bottom, as shown, the only thing you need to change is a single entry. It does not matter that you leave the first position empty. This means that there is little potential for overflowing integer sorting with sufficient re-ordering, but let me say it again: users usually only order small lists manually. I have never heard of this risk actually causing a problem.
Joel Coehoorn
source share