Insérer dans une table MySQL ou mettre à jour s'il existe

875

Je veux ajouter une ligne à une table de base de données, mais si une ligne existe avec la même clé unique, je veux mettre à jour la ligne.

Par exemple:

insert into table (id, name, age) values(1, "A", 19)

Disons que la clé unique est id, et dans ma base de données , il y a une ligne avec id = 1. Dans ce cas, je souhaite mettre à jour cette ligne avec ces valeurs. Normalement, cela donne une erreur.
Si je l'utilise, insert IGNOREil ignorera l'erreur, mais il ne sera toujours pas mis à jour.

Keshan
la source
6
SQL a besoin d'une syntaxe officielle pour ce cas d'utilisation qui ne force pas la duplication de valeurs dans la syntaxe et préserve la clé primaire.
Pete Alvin
Pour obtenir l'ID influencé, reportez-vous à MySQL ON DUPLICATE KEY - last insert id?
Kris Roofe du
Avertissement: à partir de la version 5.7, cette approche ne prend pas directement en charge la clause WHERE dans le cadre de l'opération INSERT / UPDATE. De plus, une MISE À JOUR compte en fait comme deux opérations distinctes (SUPPRIMER et INSÉRER) ... au cas où cela serait important à des fins d'audit. (Learnbit)
dreftymac

Réponses:

1600

Utilisation INSERT ... ON DUPLICATE KEY UPDATE

REQUETE:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name="A", age=19
Donnie
la source
86
+1 D'après ce que j'ai trouvé, cette méthode est moins problématique pour les clés à incrémentation automatique et autres collisions de clés uniques que REPLACE INTO, et elle est plus efficace.
Andrew Ensley
46
Je sais que vous faites tous allusion à cela, mais je veux être explicite pour les autres. Si l'ID que vous insérez n'est PAS la CLÉ PRIMAIRE ou UNIQUE, cela ne fonctionnera pas. Au départ, cela n'a pas fonctionné pour moi car mon ID n'était pas unique.
Keven
7
Je me demande pourquoi cela se affected row counttraduit par 2une mise à jour réussie (sur une clé en double) d'une seule ligne? Quelqu'un d'autre a eu ce résultat? (Les données sont correctement mises à jour: ce qui signifie qu'une seule ligne est mise à jour)
Dimitry K
15
C'est un peu en retard, mais de toute façon: il est indiqué dans le manuel que les mises à jour ON DUPLICATE KEY UPDATEaugmentent de 2 les lignes affectées. Il signale 0 si rien n'est réellement mis à jour (comme le normal UPDATE).
2014
61
Notez également que vous pouvez utiliser VALUES (nom) pour faire référence à la valeur que vous essayez d'insérer, par exemple INSERT INTO table (id, name, age) VALUES (1, "A", 19) ON DUPLICATE KEY UPDATE name = VALUES (name) , age = VALEURS (age)
Curious Sam
246

Découvrez REMPLACER

http://dev.mysql.com/doc/refman/5.0/en/replace.html

REPLACE into table (id, name, age) values(1, "A", 19)
Martin Schapendonk
la source
11
@Piontek Parce que celui-ci est plus court et plus facile à comprendre et que personne n'a expliqué pourquoi "insérer sur doublon" est meilleur.
Mr_Chimp
77
il modifie les ID de l'enregistrement et peut donc détruire les références étrangères.
boh
102
L'autre problème avec REPLACE INTO est que vous devez spécifier des valeurs pour TOUS les champs ... sinon les champs seront perdus ou remplacés par des valeurs par défaut. REPLACE INTO supprime essentiellement la ligne si elle existe et insère la nouvelle ligne. Dans l'exemple, si vous avez défini les valeurs de table (id, age) «REPLACE INTO (1, 19), le champ de nom deviendrait nul.
Dale
33
Il s'agit en fait de SUPPRIMER la ligne entière et d'effectuer une nouvelle insertion.
mjb
8
@mjb Par conséquent, vous devez disposer des privilèges DELETE, ce qu'il vaut mieux ne pas avoir si vous n'en avez pas besoin. L'utilisateur de la base de données de mon environnement ne dispose que des autorisations INSERT et UPDATE, donc REPLACE ne fonctionnera pas.
ndm13
54

Lorsque vous utilisez l'insertion par lots, utilisez la syntaxe suivante:

INSERT INTO TABLE (id, name, age) VALUES (1, "A", 19), (2, "B", 17), (3, "C", 22)
ON DUPLICATE KEY UPDATE
    name = VALUES (name),
    ...
Fabiano Souza
la source
Très utile si vous souhaitez manipuler la nouvelle valeur
Hunger
Si VALUES(name)cela ne fonctionne pas, vous pouvez essayername = 'name_value',...;
Son Pham
26

Essayez ceci:

INSERT INTO table (id, name, age) VALUES (1, 'A', 19) ON DUPLICATE KEY UPDATE id = id + 1;

J'espère que cela t'aides.

Luis Reyes
la source
6
en fait, je n'ai pas besoin d'ajouter les nouvelles valeurs à une autre ligne avec un nouvel ID à la place, je veux remplacer les valeurs existantes de id = 1 par ces valeurs. (si je comprends bien, cela incrémente l'ID et ajoute les données)
Keshan
49
Je ne pense pas qu'il veuille augmenter l'identifiant d'un pour les doublons.
Donnie
7
"transgresser" n'est pas le mot que vous cherchez :) Malheureusement, maintenant que j'ai vu "transgresser", je ne peux plus visualiser le mot réel ..
mwfearnley
1
Cherchiez-vous des "traverses" ou des "couvertures"?
Chris Dev
4
@mwfearnley Le mot que vous essayez de visualiser est "transcende". Cela n'a pris qu'un an et demi :-)
Michael Krebs
20

Essaye ça:

INSERT INTO table (id,name,age) VALUES('1','Mohammad','21') ON DUPLICATE KEY UPDATE name='Mohammad',age='21'

Remarque:
ici, si id est la clé primaire, après la première insertion, id='1'chaque tentative d'insertion id='1'mettra à jour le nom et l'âge et l'âge du nom précédent changera.

Rasel
la source
Je veux travailler sans utiliser id . Avez-vous essayé sans clé primaire?
ersks
@ersks voir la question. l'utilisateur a demandé quand il existe une clé unique
Rasel
J'ai compris, mais j'essaie de résoudre mon problème dans lequel ces seules valeurs sont connues. Donc, dans une telle situation, j'ai écrit un commentaire ci-dessus en espérant une solution correcte.
ersks
15
INSERT IGNORE INTO table (id, name, age) VALUES (1, "A", 19);

INSERT INTO TABLE (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE NAME = "A", AGE = 19;

REPLACE INTO table (id, name, age) VALUES(1, "A", 19);

Toutes ces solutions fonctionneront concernant votre question.

Si vous voulez en savoir plus sur ces déclarations, visitez ce lien

Dilraj Singh
la source
REPLACEn'est pas documenté dans le document lié.
Ray Baxter
requêtes SQL pleines de fautes de frappe, vos exemples ne fonctionneront pas. C'est INSERT INTO TABLE (pas INTO TABLE) et ON DUPLICATE KEY UPDATE (pas ON DUPLICATE UPDATE SET). Je ne sais pas qui vote en faveur
Robert Sinclair
1
Désolé pour l'erreur de frappe. Merci de m'avoir corrigé
Dilraj Singh
11

Lors de l'utilisation de SQLite:

REPLACE into table (id, name, age) values(1, "A", 19)

Pourvu que ce idsoit la clé primaire. Ou bien il insère simplement une autre ligne. Voir INSERT (SQLite).

DawnSong
la source
Ce replace intoqui est exactement "insérer ou mettre à jour lorsqu'il existe". @Owl
DawnSong
+1 (1 sur 3) J'ai trouvé que cela fonctionnait pour ma situation - je devais remplacer une ligne existante par une clé unique ou sinon, ajouter la ligne. Les solutions les plus simples ici.
therobyouknow
(2 de 3) Ma requête:CREATE TRIGGER worklog_update AFTER INSERT ON worklog FOR EACH ROW REPLACE INTO support_time_monthly_hours ( ProjectID, monthTotalTime, Year, Month ) SELECT jiraissue.PROJECT, SUM(worklog.timeworked), YEAR(CURRENT_DATE()), MONTH(CURRENT_DATE()) FROM worklog, jiraissue WHERE worklog.issueid = jiraissue.ID AND jiraissue.PROJECT = (SELECT PROJECT FROM jiraissue WHERE NEW.issueid = jiraissue.ID ) AND worklog.startdate BETWEEN DATE_FORMAT(NOW() ,'%Y-%m-01 00:00:00') AND NOW();
therobyouknow
(3 de 3) Question / réponse connexe stackoverflow.com/questions/41767517/…
therobyouknow
2
Le problème avec cela dans mysql est que replace supprimera les autres valeurs au cas où elles ne seraient pas fournies. Cependant, la solution @ fabiano-souza est plus appropriée
Quamber Ali
11

Tout simplement parce que je cherchais ici cette solution mais pour la mise à jour à partir d'une autre table à structure identique (dans mon cas, testez la base de données du site Web en base de données en direct):

INSERT  live-db.table1
SELECT  *
FROM    test-db.table1 t
ON DUPLICATE KEY UPDATE
        ColToUpdate1 = t.ColToUpdate1,
        ColToUpdate2 = t.ColToUpdate2,
        ...

Comme mentionné ailleurs, seules les colonnes que vous souhaitez mettre à jour doivent être incluses après ON DUPLICATE KEY UPDATE.

Pas besoin de lister les colonnes dans le INSERTou SELECT, même si je suis d'accord, c'est probablement une meilleure pratique.

SteveCinq
la source
4

Si vous souhaitez créer un non-primarychamp comme critère / condition ON DUPLICATE, vous pouvez créer une UNIQUE INDEXclé sur cette table pour déclencher le DUPLICATE.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`);

Et si vous souhaitez combiner deux champs pour le rendre unique sur la table, vous pouvez y parvenir en ajoutant plus sur le dernier paramètre.

ALTER TABLE `table` ADD UNIQUE `unique_index`(`name`, `age`);

Remarque, assurez-vous simplement de supprimer d'abord toutes les données qui ont la même valeur nameet la agevaleur sur les autres lignes.

DELETE table FROM table AS a, table AS b WHERE a.id < b.id 
AND a.name <=> b.name AND a.age <=> b.age;

Après cela, il devrait déclencher l' ON DUPLICATEévénement.

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name = VALUES(name), age = VALUES(age)
Riches
la source
2

Dans mon cas, j'ai créé des requêtes ci-dessous mais dans la première requête si id1 existe déjà et l'âge est déjà là, après cela si vous créez la première requête sans, agela valeur de agesera nulle

REPLACE into table SET `id` = 1, `name` = 'A', `age` = 19

pour éviter le problème ci-dessus, créez une requête comme ci-dessous

INSERT INTO table SET `id` = '1', `name` = 'A', `age` = 19 ON DUPLICATE KEY UPDATE `id` = "1", `name` = "A",`age` = 19

que cela vous aide ...

Renish Gotecha
la source
2
Quelqu'un sait-il pourquoi nous devons attribuer les valeurs deux fois? Pourquoi MySQL ne nous permet-il pas de terminer la requête à ON DUPLICATE KEY UPDATE sans dupliquer toutes les instructions d'affectation? Certaines tables de base de données ont de nombreuses colonnes, ce qui semble redondant / gratuit. Je comprends pourquoi nous avons l'option pour d'autres affectations, mais pourquoi ne pas avoir la possibilité de les omettre également? Juste curieux si quelqu'un le sait.
Blue Water
2

Dans le cas, vous souhaitez conserver l'ancien champ (par exemple: nom). La requête sera:

INSERT INTO table (id, name, age) VALUES(1, "A", 19) ON DUPLICATE KEY UPDATE    
name=name, age=19;
Xman Classique
la source