【问题标题】:INSERT ... ON DUPLICATE KEY UPDATE with WHERE?INSERT ... 使用 WHERE 进行重复的密钥更新?
【发布时间】:2011-01-28 23:50:39
【问题描述】:

我正在做一个INSERT ... ON DUPLICATE KEY UPDATE,但我需要更新部分是有条件的,只有在某些额外条件发生变化时才进行更新。

但是,WHERE 不允许用于此 UPDATE。有什么解决方法吗?

我不能进行 INSERT/UPDATE/SELECT 的组合,因为这需要在复制过程中起作用。

【问题讨论】:

    标签: mysql replication


    【解决方案1】:

    我建议你使用 IF() 来做到这一点。

    参考:conditional-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);
    

    【讨论】:

    • 我从来不知道我可以访问 UPDATE 部分中的原始表值。这可能解决了我的问题(尽管我的旧工作非常好:))
    • MySQL 可能会抱怨“字段列表中的列不明确” - 那么您需要使用:ON DUPLICATE KEY UPDATE daily_events.last_event_id = IF(daily_events.last_event_created_at &lt; VALUES(last_event_created_at), VALUES(last_event_id), daily_events.last_event_id);
    • 很遗憾,发布到 thewebfellas.com 的链接已失效。
    • 发布到 thewebfellas.com 的链接现在可用
    【解决方案2】:

    这是我们的最终解决方案,就像一个魅力!

    insert ignore 将确保主设备和从设备上都存在该行,以防它们被转移。

    update ... where 确保只有全球范围内的最新更新才是所有复制完成后的最终结果。

    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();
    

    【讨论】:

    • 解释在@lexu 答案中:两个语句,第一个是insert ignore,第二个类似于update ignore
    • 看起来第二个语句只是在做update test set value = "foo", ts = now() where id = 4 and ts &lt; now(),除了以非常复杂的方式。
    • 是的,你是对的。自从发布此答案后,我将代码更改为insert ignore...,后跟update .... where ts &lt; now()
    • @AndreasWederbrand 您能否相应地更新您的答案,以便其他人也可以从您的结论中受益?
    【解决方案3】:

    您可以使用两个插入语句..因为您可以将 where 子句添加到源数据的选择部分。

    选择两组数据,一组您将在“重复时”插入,另一组将在不“重复时”插入。

    【讨论】:

      【解决方案4】:

      概述

      • AWUpsertCondy 想要将 BEFORE 更改为 AFTER

      问题

      • AWUpsertCondy 不希望在 MySQL 检测到重复主键时插入查询失败
      • MySQL 不支持带有ON DUPLICATE KEY UPDATE 的条件 WHERE 子句

      解决方案

      • MySQL 支持带有IF() 函数的条件子句
      • 这里我们有一个简单的条件来仅更新用户 ID 小于 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 )
      ;
      
      

      陷阱

      • 我们引入了一个 MySQL 变量 @doupdate 来标记 UPDATE 行是否满足条件。然后我们对 UPDATE 语句中使用的所有数据库列使用相同的变量
      • 在第一个条件中,我们都声明了变量并确定条件是否适用。这种方法可以说比 WHERE 子句更麻烦

      另见

      【讨论】:

        【解决方案5】:

        php_lock:
        name:idString, locked:bool, time:timestamp, locked_by:string
        要插入的值或 更新
        1, CURRENT_TIMESTAMP, 'script'
        where name='wwww' AND 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`);
        

        【讨论】:

          【解决方案6】:

          On duplicate key 不允许我们使用 where 子句,所以有两种替代方法可以实现相同。

          1. 如果你知道大部分时间你会得到重复的密钥,那么

            a. Update the table first using update query and where clause b. If update fails then insert the record into table using insert query

          2. 如果您知道大部分时间要插入表格,那么

            a. Insert the record into table using insert ignore query - what it does is actually ignore the insert if duplicate key found b. If insert ignore fails then update the record using update query

          供参考insert ignore click here

          【讨论】:

          • insert ignore 怎么会失败?
          • 如果您尝试插入相同的唯一键 insert ignore 将失败。
          • 不,这就是ignore 所做的。它忽略重复键异常。
          猜你喜欢
          • 2015-12-11
          • 2018-09-26
          • 2014-10-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-31
          • 2018-06-24
          • 2012-11-17
          • 2013-03-07
          相关资源
          最近更新 更多