18 octobre 2007
Pour commencer : à partir de la dernière version de MySQL, la syntaxe présentée dans le titre n'est pas possible. Mais il existe plusieurs moyens très faciles d'accomplir ce qui est ce qui est attendu en utilisant la fonctionnalité existante.
Il y a 3 solutions possibles : utiliser INSERT IGNORE, REPLACE, ou INSERT ON DUPLICATE KEY UPDATE.
Imaginons que nous ayons une table :
CREATE TABLE `transcripts` (
`ensembl_transcript_id` varchar(20) NOT NULL,
`transcript_chrom_start` int(10) unsigned NOT NULL,
`transcript_chrom_end` int(10) unsigned NOT NULL,
PRIMARY KEY (`ensembl_transcript_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Imaginons maintenant que nous ayons un pipeline automatique qui importe des transcriptions des méta-données d'Ensembl, et que, pour diverses raisons, le pipeline peut être interrompu à n'importe quelle étape de l'exécution. Ainsi, nous devons assurer deux choses :
-
les exécutions répétées du pipeline ne détruiront pas notre base de données
-
les exécutions répétées ne mourront pas à cause d'erreurs de "duplicate clé primaire ".
Méthode 1 : utiliser REPLACE
C'est très simple :
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Si l'enregistrement existe, il sera écrasé ; s'il n'existe pas encore, il sera créé. il n'existe pas encore, il sera créé. Cependant, l'utilisation de cette méthode n'est pas efficace efficace dans notre cas : nous n'avons pas besoin d'écraser les enregistrements existants, il est simplement les ignorer.
Méthode 2 : utiliser INSERT IGNORE Egalement très simple :
INSERT IGNORE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Ici, si le 'ensembl_transcript_id' est déjà présent dans la base de données base de données, il sera silencieusement sauté (ignoré). (Pour être plus précis voici une citation du manuel de référence de MySQL : "Si vous utilisez le mot-clé IGNORE les erreurs qui surviennent lors de l'exécution de l'instruction INSERT sont plutôt sont traitées comme des avertissements. Par exemple, sans IGNORE, une ligne qui duplique un index UNIQUE ou une valeur PRIMARY KEY existant dans la table provoque une erreur de clé dupliquée et l'instruction est interrompue"). Si l'enregistrement n'existe pas encore, il sera créé.
Cette deuxième méthode présente plusieurs faiblesses potentielles, notamment la non-interruption de la requête en cas de problème (voir le manuel). Elle doit donc être utilisée si elle a été testée au préalable sans le mot clé IGNORE.
Méthode 3 : utiliser INSERT ON DUPLICATE KEY UPDATE :
La troisième option consiste à utiliser INSERT … ON DUPLICATE KEY UPDATE
syntaxe, et dans la partie UPDATE, il suffit de ne rien faire et d'effectuer une opération vide de sens. (vide), comme le calcul de 0+0 (Geoffray suggère de faire l'affectation de l'id=id pour que le moteur d'optimisation de MySQL ignore cette opération). l'affectation de l'id=id pour que le moteur d'optimisation de MySQL ignore cette opération). L'avantage de cette méthode est qu'elle ignore seulement les événements de clés dupliquées duplicate key events, et s'arrête toujours en cas d'autres erreurs.
Dernière remarque : ce billet a été inspiré par Xaprb. Je vous conseille également de de consulter son autre billet sur l'écriture de requêtes SQL flexibles.
2 votes
dev.mysql.com/doc/refman/5.0/fr/if.html
0 votes
Voir stackoverflow.com/questions/44550788/ pour une discussion sur le fait de ne pas brûler les valeurs auto_inc.
0 votes
@RickJames - c'est une question intéressante mais je ne suis pas sûr qu'elle soit directement liée à cette question :)
1 votes
Elle a été mentionnée dans un commentaire, et cette autre Question prétendait que cette Question était un "duplicata exact". J'ai donc pensé que c'était une bonne idée de relier les questions entre elles pour le bénéfice des autres.
0 votes
@RickJames Je pense que dès qu'un commentaire est laissé sur une question, il apparaîtra comme lié dans la barre latérale de l'autre question, aussi : : mais je vois ce que vous essayiez de faire :)
1 votes
Oh, je ne pense jamais à regarder la barre latérale.
0 votes
@warren Pensez-vous que la suppression de la balise php (et de la phrase correspondante) pourrait améliorer la question ?
0 votes
@Neyt - Je ne le fais pas, non.
0 votes
Voir aussi stackoverflow.com/a/13463938/338904
0 votes
@e2-e4 - merci d'avoir repéré une question qui doit être fermée car elle fait double emploi avec celle-ci :)
0 votes
@warren Bonne chance avec ça.
0 votes
@e2-e4 - J'ai signalé qu'il s'agissait d'un doublon. Je suppose que vous avez fait de même :)