我必须更新具有以下结构的表:
CREATE TABLE `eav_entity_attribute` (
`entity_attribute_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Entity Attribute Id',
`entity_type_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Entity Type Id',
`attribute_set_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Set Id',
`attribute_group_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Group Id',
`attribute_id` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'Attribute Id',
`sort_order` smallint(6) NOT NULL DEFAULT '0' COMMENT 'Sort Order',
PRIMARY KEY (`entity_attribute_id`),
UNIQUE KEY `UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_SET_ID_ATTRIBUTE_ID` (`attribute_set_id`,`attribute_id`),
UNIQUE KEY `UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_GROUP_ID_ATTRIBUTE_ID` (`attribute_group_id`,`attribute_id`),
KEY `IDX_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_SET_ID_SORT_ORDER` (`attribute_set_id`,`sort_order`),
KEY `IDX_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_ID` (`attribute_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Eav Entity Attributes'
上表包含一行:
INSERT INTO `eav_entity_attribute`
(`entity_attribute_id`, `entity_type_id`, `attribute_set_id`, `attribute_group_id`, `attribute_id`, `sort_order`)
VALUES
(32758, 4, 224, 3423, 5171, 12)
我正在运行一个自动导入程序,它将读取外部数据源并写入此表。
此导入运行多次,因此有时会多次导入相同的数据。在这种情况下,该过程只是简单地用新数据覆盖旧数据,即使新数据与旧数据相同。使用 ON DUPLICATE KEY UPDATE 子句处理存在相同数据的情况。除了在这张特定的桌子上之外,这几乎可以完美地工作。
在此表上,当过程尝试更新时,我收到“重复键”消息,我无法解释。我调试了代码,这是失败的查询(从 INSERT..ON DUPLICATE KEY 中提取):
UPDATE eav_entity_attribute
SET
`attribute_group_id` = 3423
,`attribute_id` = 5171
,`attribute_set_id` = 223
,`entity_type_id` = 4
,`sort_order` = 320
WHERE
(`attribute_group_id` = 3423) AND
(`attribute_id` = 5171)
错误如下:
Error Code: 1062. Duplicate entry '3423-5171' for key 'UNQ_EAV_ENTITY_ATTRIBUTE_ATTRIBUTE_GROUP_ID_ATTRIBUTE_ID'
我知道这对 3423-5171 已经存在,但是 UPDATE 会用它们自己替换这些值,而不是创建一个新条目。我对这个问题的原因感到很困惑,任何建议都会非常受欢迎。谢谢。
更新 - 新发现
我得到了某种“灵感”,我做了一个实验。我删除了涉及( attribute_set_id
, attribute_id
)的唯一约束(注意,这不是错误中的那个),然后我运行了 INSERT..ON DUPLICATE 查询。它工作得很好。
我的是一个猜想,但这就是我的想法:我试图写入表的数据与两个约束冲突:
- 唯一的(
attribute_set_id
,attribute_id
) - 唯一的(
attribute_group_id
,attribute_id
)
INSERT 失败,大概是因为第一个约束引发的重复错误。这会触发 UPDATE,它使用第一个约束作为隐式 WHERE 子句。我的猜测是,在这种情况下,第一个约束以某种方式被忽略了,但是 UPDATE 超过了第二个,而第二个约束并没有更早涉及。
对我来说,这似乎仍然不是 UPDATE 的正当理由,它用自身替换某些内容以引发重复输入错误,但它可能会阐明其背后的逻辑。
第二次更新
我发现我正在测试的表实际上包含很多行(我忘记禁用过滤视图),这是由于成功导入其他数据而产生的。但是,“重复的候选者”在集合中仍然是唯一的。
我确认评论中发布的内容,当表仅包含该行时,INSERT..ON DUPLICATE 以及单独的 UPDATE 都有效。现在我想知道为什么当表中有更多数据时表会变得混乱,因为我们仍在讨论使用相同数据更新单个唯一行。
第三次更新 - 找到根本原因
我终于找到了 UPDATE 失败的原因,现在我必须弄清楚我是如何进入这种状态的。
线索是我在第一次更新时的猜想。简单地说,我有两个非常相似的行(请注意,当我从一个干净的数据库开始时,我使用了不同的值)。
row,entity_attribute_id,entity_type_id,attribute_set_id,attribute_group_id,attribute_id,sort_order
1,16919, 4, 120, 1746, 80, 1
2,16649, 4, 119, 1744, 80, 210
这是发生的事情:
- INSERT 尝试插入具有以下值的行:
120, 4, 1744, 80, 54
. - 这会触发“重复键”,因为
120, 80
字段的值是重复的attribute_set_id, attribute_id
(第 1 行)。 MySQL 然后尝试 UPDATE,它变成如下:
更新表
entity_type_id
= 4 ,attribute_group_id
= 1744 ,sort_order
= 54 WHERE (attribute_set_id
= 120) AND (attribute_id
= 80)这一次,UPDATE 失败,因为值
1744,80
违反了 pair 的约束attribute_group_id, attribute_id
,在第 2 行中找到。
总之
- INSERT 失败,因为第 1 行的 key 值相同
attribute_set_id, attribute_id
。 - UPDATE 失败,因为第 2 行的 key 值相同
attribute_group_id, attribute_id
。
解决方案
我将不得不审查整个导入程序,因为理论上不会出现此类重复。MySQL 做得很好,它是复杂的数据库。
感谢所有的建议。