J'ai trouvé quelques solutions «qui seraient» pour le classique «Comment insérer un nouvel enregistrement ou en mettre à jour un s'il existe déjà», mais je ne parviens pas à faire fonctionner l'une d'elles dans SQLite.
J'ai un tableau défini comme suit:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
Ce que je veux faire, c'est ajouter un enregistrement avec un nom unique. Si le nom existe déjà, je souhaite modifier les champs.
Quelqu'un peut-il me dire comment procéder s'il vous plaît?
Réponses:
Jetez un œil à http://sqlite.org/lang_conflict.html .
Vous voulez quelque chose comme:
Notez que tout champ ne figurant pas dans la liste d'insertion sera défini sur NULL si la ligne existe déjà dans la table. C'est pourquoi il y a une sous-sélection pour la
ID
colonne: dans le cas de remplacement, l'instruction la mettrait à NULL et ensuite un nouvel ID serait alloué.Cette approche peut également être utilisée si vous souhaitez laisser des valeurs de champ particulières seules si la ligne dans le cas de remplacement, mais définissez le champ sur NULL dans le cas d'insertion.
Par exemple, en supposant que vous vouliez partir
Seen
seul:la source
Level
, cette approche ne peut pas être suivie.Vous devez utiliser la
INSERT OR IGNORE
commande suivie d'uneUPDATE
commande: dans l'exemple suivant sename
trouve une clé primaire:La première commande insérera l'enregistrement. Si l'enregistrement existe, il ignorera l'erreur provoquée par le conflit avec une clé primaire existante.
La deuxième commande mettra à jour l'enregistrement (qui existe désormais définitivement)
la source
Vous devez définir une contrainte sur la table pour déclencher un " conflit " que vous résolvez ensuite en effectuant un remplacement:
Ensuite, vous pouvez émettre:
Le "SELECT * FROM data" vous donnera:
Notez que le data.id est "3" et non "1" car REPLACE effectue un DELETE et INSERT, pas un UPDATE. Cela signifie également que vous devez vous assurer que vous définissez toutes les colonnes nécessaires ou vous obtiendrez des valeurs NULL inattendues.
la source
Tout d'abord, mettez-le à jour. Si le nombre de lignes affectées = 0, insérez-le. C'est le plus simple et adapté à tous les SGBDR .
la source
Insert or Replace
est vraiment plus préférable.INSERT OR REPLACE
remplacera les autres champs à la valeur par défaut.Si vous souhaitez conserver l'autre champ
ou en utilisant UPSERT (la syntaxe a été ajoutée à SQLite avec la version 3.24.0 (2018-06-04))
Le
excluded.
préfixe égal à la valeur enVALUES
.la source
Upsert est ce que vous voulez.
UPSERT
la syntaxe a été ajoutée à SQLite avec la version 3.24.0 (2018-06-04).Soyez averti qu'à ce stade, le mot "UPSERT" ne fait pas partie de la syntaxe upsert.
La syntaxe correcte est
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
et si vous effectuez
INSERT INTO SELECT ...
votre sélection, au moinsWHERE true
pour résoudre l'ambiguïté de l'analyseur sur le jetonON
avec la syntaxe de jointure.Soyez averti que
INSERT OR REPLACE...
supprimera l'enregistrement avant d'en insérer un nouveau s'il doit être remplacé, ce qui pourrait être mauvais si vous avez des cascades de clés étrangères ou d'autres déclencheurs de suppression.la source
UPSERT
syntaxe.Si vous n'avez pas de clé primaire, vous pouvez l'insérer si elle n'existe pas, puis faire une mise à jour. Le tableau doit contenir au moins une entrée avant de l'utiliser.
la source
Je crois que vous voulez UPSERT .
"INSÉRER OU REMPLACER" sans la supercherie supplémentaire dans cette réponse réinitialise tous les champs que vous ne spécifiez pas à NULL ou à une autre valeur par défaut. (Ce comportement de INSERT OR REPLACE est différent de UPDATE; c'est exactement comme INSERT, car il s'agit en fait de INSERT; cependant si ce que vous vouliez est UPDATE-si-existe, vous voulez probablement la sémantique UPDATE et serez désagréablement surpris par le résultat réel.)
La ruse de l'implémentation UPSERT suggérée consiste essentiellement à utiliser INSERT OR REPLACE, mais spécifiez tous les champs, en utilisant des clauses SELECT intégrées pour récupérer la valeur actuelle des champs que vous ne souhaitez pas modifier.
la source
Je pense qu'il vaut la peine de souligner qu'il peut y avoir un comportement inattendu ici si vous ne comprenez pas complètement comment PRIMARY KEY et UNIQUE interagissent.
Par exemple, si vous souhaitez insérer un enregistrement uniquement si le champ NOM n'est pas actuellement pris, et si c'est le cas, vous voulez qu'une exception de contrainte se déclenche pour vous le dire, alors INSERT OR REPLACE ne lancera pas d'exception et au lieu de cela résoudre la contrainte UNIQUE elle-même en remplaçant l'enregistrement en conflit (l'enregistrement existant avec le même NOM ). Gaspard le démontre très bien dans sa réponse ci-dessus.
Si vous souhaitez qu'une exception de contrainte se déclenche, vous devez utiliser une instruction INSERT et compter sur une commande UPDATE distincte pour mettre à jour l'enregistrement une fois que vous savez que le nom n'est pas pris.
la source