多个 UNIQUE 字段的 ON DUPLICATE KEY UPDATE 的 MySQL 行为

Posted

技术标签:

【中文标题】多个 UNIQUE 字段的 ON DUPLICATE KEY UPDATE 的 MySQL 行为【英文标题】:MySQL behavior of ON DUPLICATE KEY UPDATE for multiple UNIQUE fields 【发布时间】:2013-04-28 23:31:01 【问题描述】:

mysql 4.1.0 开始,可以添加 ON DUPLICATE KEY UPDATE 语句来指定插入的值(使用 INSERTSETVALUES)已经在目标表 w.r.t 中时的行为。 PRIMARY KEY 或一些 UNIQUE 字段。如果PRIMARY KEY 或某些UNIQUE 字段的值已在表中,则INSERT 将替换为UPDATE

ON DUPLICATE KEY UPDATE 在有多个的情况下如何表现 UNIQUE 我的表中的字段?

如果UNIQUE 字段匹配,我可以只更新一次吗?

只有当UNIQUE 两个字段同时匹配时,我才能更新吗?

【问题讨论】:

【参考方案1】:

考虑

INSERT INTO table (a,b,c) VALUES (1,2,3)
    -> ON DUPLICATE KEY UPDATE c=c+1;

如果 a 和 b 是 UNIQUE 字段,则 UPDATE 出现在 a = 1 OR b = 2 上。此外,当两个或更多条目满足条件a = 1 OR b = 2 时,仅更新一次。

Ex here table table with Id and Name UNIQUE 字段

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6

如果查询是

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7);

然后我们得到

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6
1      C        7

这违反了 Id 和 Name 的唯一性。现在有了

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7)
ON DUPLICATE KEY UPDATE Value = 7;

我们得到

Id     Name     Value 
1      P        7 
2      C        7 
3      D        29 
4      A        6

多个键的行为如下

如果UNIQUE 字段之一等于要插入的值,则执行ON DUPLICATE KEY UPDATE 中的UPDATE。这里,UPDATEId = 1 OR Name = C 上执行。相当于

UPDATE table 
SET Value = 7
WHERE Id = 1 OR Name = C;

如果我只想要一个更新,对于任一键怎么办

可以使用UPDATE 语句和LIMIT 关键字

UPDATE table 
SET Value = 7
WHERE Id = 1 OR Name = C
LIMIT 1;

这将给

Id     Name     Value 
1      P        7 
2      C        3 
3      D        29 
4      A        6

如果我只想在两个键的值都匹配的情况下进行一次更新怎么办

一种解决方案是ALTER TABLE 并使PRIMARY KEY(或唯一性)在这两个字段上都起作用。

ALTER TABLE table 
DROP PRIMARY KEY,
ADD PRIMARY KEY (Id, Name);

现在开始

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7)
ON DUPLICATE KEY UPDATE Value = 7;

我们得到

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6
1      C        7

因为没有找到重复项(在两个键上)。

【讨论】:

如果您有一个包含两列作为主键的表,并且希望使用 ON DUPLICATE KEY,必须避免向 pk 列添加唯一索引,因为如果 pk1 或 pk2 存在于值。 有没有办法在第 2 列上设置唯一约束,但有它不会影响此重复键更新操作吗?这意味着如果不满足唯一约束,则插入或更新将失败。 我的测试与这个答案声称的相矛盾(在 MySQL 8.0.22 上)。 只有一个重复的行被更新,它似乎是发现重复的第一个索引的行。烦人,因为很难控制索引顺序,而且索引顺序应该无关紧要。 (请注意,PK 始终是第一个唯一索引,因此 PK 副本将始终是更新的第一个竞争者 - 这是所有这一切中唯一合乎逻辑的事情。)【参考方案2】:

    MySQL 的行为... 它的行为符合预期,即执行 ON DUPLICATE KEY 子句。

    我可以有一个更新... 实际上,您只有一个 ON DUPLICATE KEY 子句,因此您需要放置一些代码来区分涉及哪个约束。幸运的是,这是可能的。您唯一应该知道的是,分配的顺序很重要,您可以分配多次。假设您对 a 和 b 具有唯一性约束,并且仅在涉及唯一性时才想更新 c: ... 关键更新 c = IF(a = VALUES(a) and b VALUES(b), VALUES(c), c), b = VALUES(b)

    但是如果你改变了分配的顺序,if 中的第二个条件将始终为 false。

    见 2。

【讨论】:

以上是关于多个 UNIQUE 字段的 ON DUPLICATE KEY UPDATE 的 MySQL 行为的主要内容,如果未能解决你的问题,请参考以下文章

MySQL优化

postgresql----数据库表约束----UNIQUE

Mysql索引

Caused by org hibernate DuplicateMappingException Duplicat

Django model中设置多个字段联合唯一约束

索引-视图-触发器-游标的基本语法