INSERT IF NOT EXIST ELSE UPDATE?

j'en ai trouvé quelques-unes" serait "des solutions pour le classique" Comment puis-je insérer un nouvel enregistrement ou en mettre un à jour s'il existe déjà " mais je ne peux pas en faire fonctionner un seul en 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 veux modifier les champs.

est-ce que quelqu'un peut me dire comment faire s'il vous plaît?

224
demandé sur svick 2010-09-03 14:47:14

8 réponses

regardez http://sqlite.org/lang_conflict.html .

Vous voulez quelque chose comme:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);

notez que tout champ ne figurant pas dans la liste insert sera défini à NULL si la ligne existe déjà dans la table. C'est la raison pour laquelle il y a un sous-Select pour la colonne ID : dans le cas de remplacement, la déclaration serait définie à NULL et alors un nouvel ID serait attribué.

cette approche peut aussi être utilisé si vous voulez laisser des valeurs de champ particulières seules si la ligne dans le cas de remplacement mais mettez le champ à NULL dans le cas d'insertion.

par exemple, en supposant que vous voulez laisser Seen seul:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
   (select ID from Book where Name = "SearchName"),
   "SearchName",
    5,
    6,
    (select Seen from Book where Name = "SearchName"));
274
répondu janm 2014-07-02 06:34:43

vous devez utiliser la commande INSERT OR IGNORE suivie de la commande UPDATE : Dans l'exemple suivant name est une clé primaire:

INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'

la première commande insérera l'enregistrement. Si l'enregistrement existe, il ignore l'erreur provoquée par le conflit avec une clé primaire.

la deuxième commande mettra à jour l'enregistrement (qui existe maintenant définitivement)

64
répondu moshik 2018-09-20 23:12:57

vous devez définir une contrainte sur la table pour déclencher un " conflit "que vous résolvez ensuite en faisant un remplacement:

CREATE TABLE data   (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);

alors vous pouvez émettre:

INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);

le "SELECT * FROM data" vous donnera:

2|2|2|3.0
3|1|2|5.0

notez que les données.id est " 3 "et non" 1 " parce que remplacer fait un Supprimer et insérer, pas une mise à jour. Cela signifie également que vous devez vous assurer que vous définissez tous les colonnes nécessaires ou vous obtiendrez des valeurs nulles inattendues.

61
répondu gaspard 2011-01-27 10:54:28

tout d'abord mettre à jour. Si nombre de lignes affectées = 0, alors insérez-le. C'est le plus facile et adapté pour tous RDBMS .

31
répondu Burçin 2010-09-03 10:50:07

INSERT OR REPLACE remplacera les autres champs ( TypeID , Level ) par la valeur par défaut.

INSERT OR REPLACE INTO book(id, name) VALUES(1001, 'Programming')

j'utilise ce

INSERT OR IGNORE INTO book(id) VALUES(1001);
UPDATE book SET name = 'Programming' WHERE id = 1001;

vous pouvez également utiliser

INSERT OR REPLACE INTO book (id, name) 
VALUES (1001, 'Programming',
  (SELECT typeid FROM book WHERE id = 1001),
  (SELECT level FROM book WHERE id = 1001),
)

mais je pense que la première méthode plus facile à lire

15
répondu Steely Wing 2014-08-22 04:19:07

Si vous n'avez pas de clé primaire, Vous pouvez insérer s'il n'existe pas, puis faire une mise à jour. Le tableau doit contenir au moins une entrée avant de l'utiliser.

INSERT INTO Test 
   (id, name)
   SELECT 
      101 as id, 
      'Bob' as name
   FROM Test
       WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;

Update Test SET id='101' WHERE name='Bob';
4
répondu matt 2016-01-01 18:04:35

je crois que vous voulez UPSERT .

"insérer ou remplacer" sans la supercherie supplémentaire dans cette réponse va réinitialiser tous les champs que vous ne spécifiez pas à NULL ou autre valeur par défaut. (Ce comportement D'INSERT ou de REPLACE est différent de UPDATE; il est exactement comme INSERT, car il est en fait INSERT; cependant si ce que vous vouliez est UPDATE-if-exists vous voulez probablement la sémantique de mise à jour et sera désagréablement surpris par le résultat réel.)

la ruse de L'implémentation upsert suggérée est essentiellement D'utiliser insérer ou remplacer, mais de spécifier tous les champs, en utilisant des clauses de sélection intégrées pour récupérer la valeur courante pour les champs que vous ne voulez pas changer.

2
répondu metamatt 2017-05-23 12:10:31

je pense qu'il vaut la peine de souligner qu'il peut y avoir un comportement inattendu ici si vous ne comprenez pas bien comment clé primaire et UNIQUE interagir.

à titre d'exemple, si vous voulez insérer un enregistrement seulement si le champ nom n'est pas pris actuellement, et si c'est le cas, vous voulez qu'une exception de contrainte s'allume pour vous le dire, alors insérer ou remplacer ne lancera pas et exception et résoudra la contrainte UNIQUE en remplaçant le document en conflit (le document existant par le même nom ). Gaspard démontre très bien dans sa réponse ci-dessus.

si vous voulez une exception de contrainte au feu, vous devez utiliser un INSERT statement, et compter sur une mise à jour séparée commande pour mettre à jour le dossier une fois que vous savez que le nom n'est pas pris.

1
répondu Matt Matthias 2017-05-23 10:31:30