Style de questions et réponses
Eh bien, après avoir recherché et combattu le problème pendant des heures, j'ai découvert qu'il y avait deux façons d'accomplir cela, selon la structure de votre table et si vous avez des restrictions de clés étrangères activées pour maintenir l'intégrité. Je voudrais partager ceci dans un format propre pour gagner du temps aux personnes qui peuvent être dans ma situation.
Option 1: vous pouvez vous permettre de supprimer la ligne
En d'autres termes, vous n'avez pas de clé étrangère, ou si vous en avez, votre moteur SQLite est configuré de sorte qu'il n'y ait pas d'exceptions d'intégrité. La voie à suivre est INSÉRER OU REMPLACER . Si vous essayez d'insérer / mettre à jour un lecteur dont l'ID existe déjà, le moteur SQLite supprimera cette ligne et insérera les données que vous fournissez. Maintenant, la question se pose: que faire pour conserver l'ancien ID associé?
Disons que nous voulons UPSERT avec les données user_name = 'steven' et age = 32.
Regardez ce code:
INSERT INTO players (id, name, age)
VALUES (
coalesce((select id from players where user_name='steven'),
(select max(id) from drawings) + 1),
32)
L'astuce est dans la fusion. Il renvoie l'identifiant de l'utilisateur «steven» le cas échéant, et sinon, il renvoie un nouvel identifiant frais.
Option 2: vous ne pouvez pas vous permettre de supprimer la ligne
Après avoir analysé la solution précédente, j'ai réalisé que dans mon cas, cela pourrait finir par détruire des données, car cet ID fonctionne comme une clé étrangère pour une autre table. D'ailleurs, j'ai créé le tableau avec la clause ON DELETE CASCADE , ce qui signifierait qu'elle supprimerait les données en silence. Dangereux.
Donc, j'ai d'abord pensé à une clause IF, mais SQLite n'a que CASE . Et ce CASE ne peut pas être utilisé (ou du moins je ne l'ai pas géré) pour effectuer une requête UPDATE si EXISTS (sélectionnez id parmi les joueurs où user_name = 'steven'), et INSERT si ce n'est pas le cas. Ne pas aller.
Et puis, finalement j'ai utilisé la force brute, avec succès. La logique est que, pour chaque UPSERT que vous souhaitez effectuer, exécutez d'abord un INSERT OU IGNORE pour vous assurer qu'il y a une ligne avec notre utilisateur, puis exécutez une requête UPDATE avec exactement les mêmes données que vous avez essayé d'insérer.
Mêmes données qu'auparavant: user_name = 'steven' et age = 32.
-- make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);
-- make sure it has the right data
UPDATE players SET user_name='steven', age=32 WHERE user_name='steven';
Et c'est tout!
ÉDITER
Comme Andy l'a commenté, essayer d'insérer d'abord, puis de mettre à jour peut conduire à déclencher des déclencheurs plus souvent que prévu. Ce n'est pas à mon avis un problème de sécurité des données, mais il est vrai que déclencher des événements inutiles n'a pas de sens. Par conséquent, une solution améliorée serait:
-- Try to update any existing row
UPDATE players SET age=32 WHERE user_name='steven';
-- Make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);