18 octobre 2007
Pour commencer: depuis la dernière version de MySQL, la syntaxe présentée dans le titre n'est pas possible. Mais il existe plusieurs façons très simples d'accomplir ce qui est attendu en utilisant les fonctionnalités existantes.
Il existe 3 solutions possibles: utiliser INSERT IGNORE, REPLACE ou INSERT… ON DUPLICATE KEY UPDATE.
Imaginez 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;
Imaginez maintenant que nous ayons un pipeline automatique qui importe les métadonnées des transcriptions à partir d'Ensembl et que, pour diverses raisons, le pipeline peut être interrompu à n'importe quelle étape de l'exécution. Ainsi, nous devons garantir 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 en raison d'erreurs de «clé primaire en double».
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éé. Cependant, l'utilisation de cette méthode n'est pas efficace dans notre cas: nous n'avons pas besoin d'écraser les enregistrements existants, c'est bien de les ignorer.
Méthode 2: utiliser INSERT IGNORE Aussi très simple:
INSERT IGNORE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Ici, si 'ensembl_transcript_id' est déjà présent dans la base de données, il sera ignoré en silence (ignoré). (Pour être plus précis, voici une citation du manuel de référence MySQL: «Si vous utilisez le mot clé IGNORE, les erreurs qui se produisent lors de l'exécution de l'instruction INSERT sont traitées à la place comme des avertissements. Par exemple, sans IGNORE, une ligne qui duplique un index UNIQUE existant ou la valeur PRIMARY KEY dans le tableau provoque une erreur de clé en double et l'instruction est abandonnée. ”.) 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). Il doit donc être utilisé s'il a été testé auparavant sans le mot clé IGNORE.
Méthode 3: en utilisant INSERT… ON DUPLICATE KEY UPDATE:
La troisième option consiste à utiliser la INSERT … ON DUPLICATE KEY UPDATE
syntaxe, et dans la partie UPDATE, rien ne fait une opération dénuée de sens (vide), comme calculer 0 + 0 (Geoffray suggère de faire l'affectation id = id pour que le moteur d'optimisation MySQL ignore cette opération). L'avantage de cette méthode est qu'elle ignore uniquement les événements de clé en double et abandonne toujours d'autres erreurs.
Enfin, ce billet a été inspiré par Xaprb. Je conseillerais également de consulter son autre article sur l'écriture de requêtes SQL flexibles.