web-dev-qa-db-fra.com

Comment puis-je mettre à jour s'il existe, insérer sinon (AKA "upsert" ou "merge") dans MySQL?

Existe-t-il un moyen simple de INSERT une ligne lorsqu'elle n'existe pas ou de UPDATE si elle existe, en utilisant une requête MySQL?

150
blub

Oui, INSERT ... ON DUPLICATE KEY UPDATE . Par exemple:

INSERT INTO `usage`
(`thing_id`, `times_used`, `first_time_used`)
VALUES
(4815162342, 1, NOW())
ON DUPLICATE KEY UPDATE
`times_used` = `times_used` + 1
189
chaos

Je sais que c’est une vieille question, mais Google me conduit ici récemment, alors j’imagine que d’autres viennent ici aussi.

@chaos est correct: il y a le INSERT ... ON DUPLICATE KEY UPDATE syntaxe.

Cependant, la question initiale concernait spécifiquement MySQL, et dans MySQL, il y a REPLACE INTO ... syntaxe. IMHO, cette commande est plus facile et plus simple à utiliser pour les upserts. Du manuel:

REPLACE fonctionne exactement comme INSERT, sauf que si une ancienne ligne de la table a la même valeur qu'une nouvelle ligne pour une clé PRIMARY KEY ou un index UNIQUE, l'ancienne ligne est supprimée avant que la nouvelle ligne ne soit insérée.

Notez que ce n'est pas le SQL standard. Un exemple du manuel:

CREATE TABLE test (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64) DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.04 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.04 sec)

mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.00 sec)

Edit: Juste un avertissement juste que REPLACE INTO n'est pas comme UPDATE. Comme le dit le manuel, REPLACE supprime la ligne si elle existe, puis en insère une nouvelle. (Notez le drôle de "2 lignes affectées" dans l'exemple ci-dessus.) Cela remplacera les valeurs de all colonnes d'un enregistrement existant (et pas simplement mettre à jour certains colonnes.) Le comportement de REPLACE INTO ressemble beaucoup à celui de Sqlite INSERT OR REPLACE INTO. Voir cette question pour certaines solutions de contournement si vous souhaitez uniquement mettre à jour quelques colonnes (et non toutes les colonnes) si l'enregistrement existe déjà.

4
Armadillo Jim