On Duplicate Update不适用于唯一索引

时间:2012-10-22 09:27:27

标签: mysql database-indexes

我试图插入/更新的SQL表有这个定义:

CREATE TABLE `place`.`a_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`some_id` bigint(20) NOT NULL,
`someOther_id` bigint(20) NOT NULL,
`some_value` text,
`re_id` bigint(20) NOT NULL DEFAULT '0',
`up_id` bigint(20) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `some_id_key` (`some_id`),
KEY `some_id_index1` (`some_id`,`someOther_id`),
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;

如您所见,some_id和someOther_id共享一个索引。

我正在尝试执行以下插入/更新语句:

INSERT INTO `a_table` (`re_id`,`some_id`,`someOther_id`,`up_id`,`some_value`) VALUES      
(100,181,7,101,'stuff in the memo wow') On DUPLICATE KEY UPDATE 
`up_id`=101,`some_value`='sampleValues'

我希望因为我没有指定id,所以它将作为插入/更新规则返回到索引键(some_id_index1)。但是,它只是插入。

显然这是不正确的。我在这里做错了什么?

3 个答案:

答案 0 :(得分:6)

好的,首先是帮你提出更好的问题。你的问题的字面答案“我在这里做错了什么?”什么都不是。

您有一个包含自动增量主键和两个非唯一二级索引的表。您正在向该表插入行而不指定主键的值,因此MySQL将使用自动增量规则为其提供唯一键,因此ON DUPLICATE KEY条件将永远不会触发。事实上,人们可能会认为它是多余的。

所以你必须问自己的问题是你认为应该发生什么。现在Stack Overflow不是一个论坛,所以不要回来为这个问题添加评论,试图澄清你的原始问题。而是制定一个新问题,让那些试图准确回答你所问的内容的人明白。

正如我所看到的,有许多可能性:

  1. 您希望将二级索引修改为唯一。如果您这样做,它将触发ON DUPLICATE KEY规则并切换到更新
  2. 您实际上根本不需要自动增量列,而some_id实际上应该是您的主键
  3. 你不明白数据库索引是如何工作的(特别是至少有一个二级索引可能是不必要的,因为数据库通常可以组合多个索引或使用部分索引来优化你的查询,所以第二个二级索引更多仅作为someOther_id字段的索引非常有用,除非存在您要强制执行的特定唯一性约束。例如,如果您希望多行具有相同的some_id但仅限于someOther_id对于任何特定的some_id,只有一行特定We need a table that provides cross-reference notes about two other tables. There are different types of cross-reference (we use the column 're_id' to identify the type of cross-reference) and there are different types of notes (we use the columns 'up_id' as well as 'someValue') to store the actual notes. The cross-reference is indicated with two columns 'some_id' which is the id of the row in the 'some' table and 'someOther_id' which is the id of the row in the 'someOther' table. There can be only one cross-reference between any one row in the 'some' table and any one row in the 'someOther' table, but there can be multiple cross-references from one specific row in the 'some' table to different rows in the 'someOther' table. ,然后需要第二个二级索引,但是在这种情况下第一个不会,因为数据库可以使用第二个作为部分索引来实现相同的性能优化)
  4. 我建议你用一支笔和一张纸坐下来远离你的计算机并尝试以这样的方式写下你想做的确切内容[选择以下之一:你的毕业生;一个十一岁的孩子]可以理解。把那张纸收起来扔掉,直到你可以一口气写下来,不会犯任何错误。然后返回计算机并尝试编写刚才写的内容。

    百分之99次,你会发现这有助于你解决问题,而不需要问别人问题,因为我们的问题中有99次是由于我们自己对问题本身缺乏理解 即可。试图(几乎)向你的祖母或一个十一岁的孩子解释你的问题,迫使你抛弃一些令你眼花缭乱的假设,并在你击中眼睛釉面之前快速找到问题的核心

    以下是我想象中的一个问题陈述的一个例子。这可能是不正确的,因为我不知道你的具体问题是什么:

    (some_id,someOther_id)

    使用上面的问题陈述,我会将主键从自动增量切换为{{1}}上的两列主键,并删除所有辅助键!

    但我希望您意识到您的实际解决方案实际上可能有所不同,因为您的问题陈述与我的 guess 不同。

答案 1 :(得分:3)

来自the MySQL documentation

  

如果表中包含AUTO_INCREMENT列且INSERT ... UPDATE插入一行,则LAST_INSERT_ID()函数将返回AUTO_INCREMENT值。如果语句更新了一行,LAST_INSERT_ID()没有意义。但是,您可以使用LAST_INSERT_ID(expr)解决此问题。假设id是AUTO_INCREMENT列。要使LAST_INSERT_ID()对更新有意义,请按如下方式插入行:

INSERT INTO table (a,b,c) VALUES (1,2,3)
   ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

答案 2 :(得分:2)

相同的查询工作正常,在DUPLICATE KEY UPDATE中更改 columns_value 进入实际专栏 some_value

fiddle demo

问题是

只应在列(up_id)上定义表上的UNIQUE约束。

我刚刚使用 unique constraint 为您的表格更改了列up_id,

Fiddle_demo