J'ai une base de données SQLite avec la table myTable
et les colonnes id
, posX
, posY
. Le nombre de lignes change constamment (peut augmenter ou diminuer). Si je connais la valeur de id
pour chaque ligne et le nombre de lignes, puis-je effectuer une seule requête SQL pour mettre à jour tous les champs posX
et posY
avec différents valeurs selon l'id?
Par exemple:
---------------------
myTable:
id posX posY
1 35 565
3 89 224
6 11 456
14 87 475
---------------------
Pseudocode de requête SQL:
UPDATE myTable SET posX[id] = @arrayX[id], posY[id] = @arrayY[id] "
@arrayX
et @arrayY
sont des tableaux qui stockent de nouvelles valeurs pour les champs posX
et posY
.
Si, par exemple, arrayX
et arrayY
contiennent les valeurs suivantes:
arrayX = { 20, 30, 40, 50 }
arrayY = { 100, 200, 300, 400 }
... alors la base de données après la requête devrait ressembler à ceci:
---------------------
myTable:
id posX posY
1 20 100
3 30 200
6 40 300
14 50 400
---------------------
Est-ce possible? Je mets à jour une ligne par requête en ce moment, mais cela va prendre des centaines de requêtes à mesure que le nombre de lignes augmente. Je fais tout ça dans AIR d'ailleurs.
Il y a deux façons d'accomplir cela décemment efficacement.
Première -
Si possible, vous pouvez effectuer une sorte d'insertion groupée dans une table temporaire. Cela dépend quelque peu de votre langage RDBMS/Host, mais au pire, cela peut être accompli avec un SQL dynamique simple (en utilisant une clause VALUES()
), puis une mise à jour standard à partir d'une autre table. La plupart des systèmes fournissent des utilitaires pour le chargement en masse, bien que
Seconde -
Et cela dépend aussi du SGBDR, vous pouvez construire une instruction de mise à jour dynamique. Dans ce cas, où la clause VALUES(...)
à l'intérieur du CTE a été créée à la volée:
WITH Tmp(id, px, py) AS (VALUES(id1, newsPosX1, newPosY1),
(id2, newsPosX2, newPosY2),
......................... ,
(idN, newsPosXN, newPosYN))
UPDATE TableToUpdate SET posX = (SELECT px
FROM Tmp
WHERE TableToUpdate.id = Tmp.id),
posY = (SELECT py
FROM Tmp
WHERE TableToUpdate.id = Tmp.id)
WHERE id IN (SELECT id
FROM Tmp)
(Selon la documentation, cette devrait être une syntaxe SQLite valide, mais je ne peux pas la faire fonctionner dans un violon)
Oui, vous pouvez le faire, mais je doute que cela améliorerait les performances, à moins que votre requête n'ait une très grande latence.
Vous pourriez faire:
UPDATE table SET posX=CASE
WHEN id=id[1] THEN posX[1]
WHEN id=id[2] THEN posX[2]
...
ELSE posX END, posY = CASE ... END
WHERE id IN (id[1], id[2], id[3]...);
Le coût total est donné plus ou moins par: NUM_QUERIES * (COST_QUERY_SETUP + COST_QUERY_PERFORMANCE). De cette façon, vous abaissez un peu sur NUM_QUERIES, mais COST_QUERY_PERFORMANCE augmente considérablement. Si COST_QUERY_SETUP est vraiment énorme (par exemple, vous appelez un service réseau qui est vraiment lent), alors, oui, vous pourriez toujours vous retrouver en tête.
Sinon, j'essaierais d'indexer sur id ou de modifier l'architecture.
Dans MySQL, je pense que vous pourriez le faire plus facilement avec plusieurs INSERT ON DUPLICATE KEY UPDATE (mais je ne suis pas sûr, jamais essayé).
Quelque chose comme ça pourrait fonctionner pour vous:
"UPDATE myTable SET ... ;
UPDATE myTable SET ... ;
UPDATE myTable SET ... ;
UPDATE myTable SET ... ;"
Si l'une des valeurs posX ou posY sont identiques, elles peuvent être combinées en une seule requête
UPDATE myTable SET posX='39' WHERE id IN('2','3','40');