Style Q&A
Eh bien, après avoir fait des recherches et m'être battu avec le problème pendant des heures, j'ai découvert qu'il y a deux façons d'y parvenir, en fonction de la structure de votre table et si vous avez des restrictions de clés étrangères activées pour maintenir l'intégrité. J'aimerais partager cette information dans un format simple pour faire gagner du temps aux personnes qui se trouvent 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 manière à ce qu'il n'y ait pas d'exceptions d'intégrité. La solution est la suivante INSÉRER OU REMPLACER . Si vous essayez d'insérer/mettre à jour un joueur 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 garder 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 coalescence. Elle renvoie l'identifiant de l'utilisateur 'steven' s'il existe, et sinon, elle renvoie un nouvel identifiant.
Option 2 : Vous ne pouvez pas vous permettre de supprimer la ligne.
Après avoir bricolé avec la solution précédente, j'ai réalisé que dans mon cas, cela pourrait détruire des données, puisque cet ID fonctionne comme une clé étrangère pour une autre table. Par ailleurs, j'ai créé la table avec la clause SUR LA SUPPRESSION EN CASCADE ce qui signifie qu'il supprimerait les données en silence. Dangereux.
J'ai d'abord pensé à une clause IF, mais SQLite ne dispose que de CASE . Et ceci CASE ne peut pas être utilisé (ou du moins je n'y suis pas parvenu) pour effectuer un UPDATE requête if EXISTS(select id from players where user_name='steven'), et INSERT si ce n'était pas le cas. Pas question.
Et puis, finalement, j'ai utilisé la force brute, avec succès. La logique est la suivante : pour chaque UPSERT que vous souhaitez effectuer, exécutez d'abord une commande INSÉRER OU IGNORER pour s'assurer qu'il y a une rangée avec notre utilisateur, et ensuite exécuter un UPDATE avec exactement les mêmes données que vous avez essayé d'insérer.
Mêmes données que précédemment : nom d'utilisateur='steven' et âge=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 !
EDIT
Comme Andy l'a fait remarquer, le fait d'essayer d'insérer d'abord et de mettre à jour ensuite peut entraîner le déclenchement de déclencheurs plus souvent que prévu. À mon avis, ce n'est pas un problème de sécurité des données, mais il est vrai que déclencher des événements inutiles n'a pas beaucoup de sens. Par conséquent, une solution améliorée serait la suivante :
-- 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);