插入...重复键更新在哪里?

发布于 2024-08-25 19:01:51 字数 204 浏览 7 评论 0原文

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

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

我无法执行 INSERT/UPDATE/SELECT 的组合,因为这需要通过复制来完成。

I'm doing a INSERT ... ON DUPLICATE KEY UPDATE but I need the update part to be conditional, only doing the update if some extra condition has changed.

However, WHERE is not allowed on this UPDATE. Is there any workaround for this?

I can't do combinations of INSERT/UPDATE/SELECT since this needs to work over a replication.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

﹉夏雨初晴づ 2024-09-01 19:01:51

我建议你使用 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);

I suggest you to use IF() to do that.

Refer: 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);
二智少女猫性小仙女 2024-09-01 19:01:51

这是我们的最终解决方案,效果非常好!

插入忽略将确保该行同时存在于主服务器和从服务器上,以防它们发生转移。

更新...其中确保只有最新的全局更新才是所有复制完成后的最终结果。

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

This is our final solution, works like a charm!

The insert ignore will make sure that the row exists on both the master and slave, in case they've ever diverted.

The update ... where makes sure that only the most recent update, globally, is the end result after all replication is done.

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();
请别遗忘我 2024-09-01 19:01:51

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

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

you could use two insert statements .. since you CAN add a where clause to the select part for the source data.

select two sets of data, one that you will insert with 'on duplicate' and the other will be inserted without 'on duplicate'.

埋葬我深情 2024-09-01 19:01:51

概述

  • AWUpsertCondy 想要将 BEFORE 更改为 AFTER

SimplifiedProblemIllustration

问题

  • 如果 MySQL 检测到重复的主键,AWUpsertCondy 不希望插入查询失败
  • MySQL 不支持条件 WHERE 子句with ON DUPLICATE KEY UPDATE

解决方案

  • MySQL 支持使用 IF() 函数的条件子句
  • 这里我们有一个简单的条件来仅更新那些 userid 小于 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 子句更麻烦

另请参阅

Overview

  • AWUpsertCondy wants to change BEFORE into AFTER

SimplifiedProblemIllustration

Problem

  • AWUpsertCondy does not want the insert query to fail if MySQL detects duplicate primary key
  • MySQL does not support conditional WHERE clause with ON DUPLICATE KEY UPDATE

Solution

  • MySQL supports conditional clause with the IF() function
  • Here we have a simple conditional to update only those items with userid less-than 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 )
;

Pitfalls

  • We introduce a MySQL variable @doupdate in order to flag whether or not the UPDATE row meets the condition. Then we use that same variable for all the database columns we use in the UPDATE statement
  • In the first conditional we both declare the variable and determine whether the conditional applies. This approach is arguably more cumbersome than a WHERE clause

See also

且行且努力 2024-09-01 19:01:51

php_lock
名称:idString,锁定:bool,
time:时间戳,locked_by:要插入或的字符串

更新
1, CURRENT_TIMESTAMP, 'script'
其中 name='wwww' AND
已锁定=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`);

table php_lock:
name:idString, locked:bool,
time:timestamp, locked_by:string
values to insert or
update
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`);
简单 2024-09-01 19:01:51

On重复键不允许我们使用where子句,因此有两种替代方法可以实现相同的目的。

  1. 如果你知道大多数时候你会得到重复的密钥

    <代码>a.首先使用 update 查询和 where 子句更新表
    b.如果更新失败,则使用插入查询将记录插入表中

  2. 如果您大多数时候知道要插入表中,则

    <代码>a.使用插入忽略查询将记录插入表中 - 它实际上是在发现重复键时忽略插入
    b.如果插入忽略失败,则使用更新查询更新记录

参考插入忽略 点击此处

On duplicate key do not allow us to use where clause, so there are two alternative to achieve the same.

  1. If you know most of the time you will get the duplicate key then

    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. If you know most of the time you are going to insert into table then

    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

For reference of insert ignore click here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文