The context :
I have a SQLite database with a table looking like this :
CREATE TABLE items (item TEXT, position INTEGER)
This table contain several million of entries. The column position
is indexed.
My front-end occasionally build a bunch of updates to apply on the position
column. The rows to be updated are not identified by their id, because the updates can be on a wide range of items, and list all id concerned can be very expensive.
By example, a bunch can be update action like "add +10 to position >= 500 & position <= 10000" - "add -3 to position >= 100000 & position <= 100003", etc.
The problem : The conditional positions of the updates of a bunch of update are all based on the positions values before the bunched update. If I execute sequentially each update action of the bunched update, then there will probably (and actually there is) an "overlapping" problem after one of the update.
By example :
item | position
it1 | 1
it2 | 2
it3 | 3
it4 | 4
it5 | 5
it6 | 6
it7 | 7
If I have this bunch of update : "add + 2 to position >= 5 & position <= 6" - "add - 2 to position >= 3 & position <= 4" and I convert this to this SQLite queries :
UPDATE items SET position=position-2 WHERE position >= 5 AND position <= 6
UPDATE items SET position=position+2 WHERE position >= 3 AND position <= 4
I'm going to have this result :
it1 | 1
it2 | 2
it3 | 5
it4 | 6
it5 | 5
it6 | 6
it7 | 7
Instead of what I want, that's to say :
it1 | 1 { it1 | 1 }
it2 | 2 { it2 | 2 }
it3 | 5 { it5 | 3 }
it4 | 6 ===> { it6 | 4 }
it5 | 3 { it3 | 5 }
it6 | 4 { it4 | 6 }
it7 | 7 { it7 | 7 }
This is because of the "overlapping" from one operation to another one.
My first idea was to use CASE like this :
UPDATE items SET position=CASE WHEN position >= 5 AND position <= 6 THEN position-2 WHEN position >= 3 AND position <= 4 THEN position+2 ELSE position END
This solution work fine but it's very very slow, as it seem that SQLite execute this on the millions of entries of my table, even if the major party are not concerned by the update.
So I modified this like this :
UPDATE items SET position=CASE WHEN position >= 5 AND position <= 6 THEN position-2 WHEN position >= 3 AND position <= 4 THEN position+2 ELSE position END WHERE (position >= 5 AND position <= 6) OR (position >= 3 AND position <= 4)
This solution work fine and it's very quick, as SQLite execute the update only on the concerned rows.
The question : As I can have 10, or even perhaps 100 updates action to do in one bunch of update, the query can become very large, and this doesn't look very... "beautiful" / "nice".
Do you think there is a more beautiful way to handle this ? Can SQLite be able to execute some "UPDATE" queries by selecting the affected row in a first time, then effectively update the row after ?
Ideas ? Thought ?
Thank you very much !