J'ai eu une situation où j'avais besoin de mettre à jour ou d'insérer une table en fonction de deux champs (tous deux des clés étrangères) sur lesquels je ne pouvais pas définir une contrainte UNIQUE (donc INSERT ... ON DUPLICATE KEY UPDATE ne fonctionnera pas). Voici ce que j'ai fini par utiliser :
replace into last_recogs (id, hasher_id, hash_id, last_recog)
select l.* from
(select id, hasher_id, hash_id, [new_value] from last_recogs
where hasher_id in (select id from hashers where name=[hasher_name])
and hash_id in (select id from hashes where name=[hash_name])
union
select 0, m.id, h.id, [new_value]
from hashers m cross join hashes h
where m.name=[hasher_name]
and h.name=[hash_name]) l
limit 1;
Cet exemple est tiré d'une de mes bases de données, les paramètres d'entrée (deux noms et un nombre) étant remplacés par [hasher_name], [hash_name] et [new_value]. Le SELECT...LIMIT 1 imbriqué extrait la première valeur de l'enregistrement existant ou d'un nouvel enregistrement (last_recogs.id est une clé primaire à incrémentation automatique) et l'utilise comme valeur d'entrée dans le REPLACE INTO.