web-dev-qa-db-fra.com

INSÉRER ... SUR LA MISE À JOUR CLÉ DUPLICATE avec OERE?

Je fais un INSERT ... ON DUPLICATE KEY UPDATE mais j'ai besoin que la partie mise à jour soit conditionnelle, ne faisant la mise à jour que si une condition supplémentaire a changé.

Cependant, WHERE n'est pas autorisé sur ce UPDATE. Y a-t-il une solution à cela?

Je ne peux pas faire de combinaisons INSERT/UPDATE/SELECT car cela doit fonctionner sur une réplication.

40
Andreas Wederbrand

Je vous suggère d'utiliser IF () pour ce faire.

Voir: conditionnel-duplicate-key-updates-with-mysql

INSERT INTO daily_events (created_on, last_event_id, last_event_created_at)
  VALUES ('2010-01-19', 23, '2010-01-19 10:23:11')
ON DUPLICATE KEY UPDATE
  last_event_id = IF(last_event_created_at < VALUES(last_event_created_at), VALUES(last_event_id), last_event_id);
61
LouisXIV

Ceci est notre solution finale, fonctionne comme un charme!

insérer ignorer s'assurera que la ligne existe à la fois sur le maître et sur l'esclave, au cas où ils auraient déjà été détournés.

pdate ... where s'assure que seule la mise à jour la plus récente, au niveau mondial, est le résultat final après que toute la réplication soit effectuée.

mysql> desc test;
+-------+--------------+------+-----+-------------------+-------+
| Field | Type         | Null | Key | Default           | Extra |
+-------+--------------+------+-----+-------------------+-------+
| id    | int(11)      | NO   | PRI | NULL              |       | 
| value | varchar(255) | YES  |     | NULL              |       | 
| ts    | timestamp    | NO   |     | CURRENT_TIMESTAMP |       | 
+-------+--------------+------+-----+-------------------+-------+

mysql> insert ignore into test values (4, "foo", now());    
mysql> update test set value = "foo", ts = now() where id = 4 and ts <= now();
12
Andreas Wederbrand

vous pouvez utiliser deux instructions d'insertion .. puisque vous POUVEZ ajouter une clause where à la partie select pour les données source.

sélectionnez deux ensembles de données, l'un que vous insérerez avec "en double" et l'autre sera inséré sans "en double".

3
lexu

Aperçu

  • AWUpsertCondy veut changer [~ # ~] avant [~ # ~] en [~ # ~] après [ ~ # ~]

SimplifiedProblemIllustration

Problème

  • AWUpsertCondy ne veut pas que la requête d'insertion échoue si MySQL détecte une clé primaire en double
  • MySQL ne prend pas en charge la clause WHERE conditionnelle avec ON DUPLICATE KEY UPDATE

Solution

  • MySQL prend en charge la clause conditionnelle avec la fonction IF()
  • Ici, nous avons une condition simple pour mettre à jour uniquement les éléments dont l'ID utilisateur est inférieur à 9
INSERT INTO zzdemo_table02
    (lname,userid)
  SELECT
    lname,userid
    FROM(
      SELECT
        lname,userid
      FROM
        zzdemo_table01
    ) as tt01
ON DUPLICATE KEY UPDATE
    userid=IF(@doupdate:=IF( (tt01.userid < 9) , True, False), 
        tt01.userid, zzdemo_table02.userid)
    ,lname=IF(@doupdate, tt01.lname , zzdemo_table02.lname )
;

Pièges

  • Nous introduisons une variable MySQL @doupdate Afin d'indiquer si la ligne UPDATE remplit ou non la condition. Ensuite, nous utilisons cette même variable pour toutes les colonnes de base de données que nous utilisons dans l'instruction UPDATE
  • Dans le premier conditionnel, nous déclarons tous les deux la variable et déterminons si le conditionnel s'applique. Cette approche est sans doute plus lourde qu'une clause WHERE

Voir également

0
dreftymac

table php_lock:
name: idString, locked: bool, time: horodatage, locked_by:chaîne
valeurs à insérer ou à mettre à jour
1, CURRENT_TIMESTAMP, 'script'
name = 'wwww' ET locked = 2

INSERT INTO `php_lock` (`name`, locked, `time`, `locked_by`)  
(SELECT * FROM 
    (SELECT `name`,1,CURRENT_TIMESTAMP, 'script' FROM `php_lock` 
        WHERE `name`='wwww' AND `locked`=2  
    UNION (
    SELECT 'wwww',1 ,CURRENT_TIMESTAMP, 'script') 
) AS temp LIMIT 1) 
ON DUPLICATE KEY UPDATE locked=VALUES(locked), `time`=VALUES(`time`), `locked_by`=VALUES(`locked_by`);
0
Tito100