2016-10-05 68 views
0

我看到很多人都问upserting(thisthisthisthisthisthismore甚至official doc)。插入到MySQL,但多列和唯一索引作为重复检查?

然而,新手不能很好地理解的东西是如何使用主键或唯一索引创建重复键。

我需要什么
如果table1独特的3列(attributeId, entityId, carId)的组合在table2副本,然后更新value列。否则取table1的行并将其插入table2

attributeId, entityId, carId组合对每一行都是唯一的。
ie:如果一行有1,2,5列,那么没有其他行会有1,2,5。但另一行可能有5,1,23,4,2

这里的困境是关于创建唯一索引。难道不足以就去做这样的:

CREATE INDEX PIndex ON table1 (attributeId, entityId, carId);

或者是有必要删除所有其他指标,然后创建这个索引,然后运行这样的查询? (以下伪代码):

INSERT INTO table1 (attributeId, entityId, carId, value, name) 
    VALUES (table2.attributeId,table2.entityId,table2.carId,table2.value,table2.name) 
ON DUPLICATE KEY UPDATE value=VALUES(value); 

的基本逻辑的存在:
如果在table2一个行中,有一个相应行中table1与恰好为属性Id,ENTITYID和carId相同的值,然后更新value列的table1,其中value列的值为table2。如果没有相应的行,则取行table2并将其附加到table1

回答

1

似乎规范是针对两种不同的操作:1)更新table1中的现有行,以及2)将新行插入到table2中。

的规范说“更新值列” ......我们认为这意味着更新的table1该行的值列。

该规范还“插入到... table2

混淆,本说明书中还示出了示例性伪码INSERT INTO table1


要执行的一个UPDATE table1基于值table2,假设我们要忽略那些具有在任何三列的NULL值的行...

UPDATE table1 t 
    JOIN table2 s 
    ON t.attributeid = s.attributeid 
    AND t.entityid = s.entityid 
    AND t.carid  = s.carid 
    SET t.value = s.value 

如果table2有“重复”(即在table2与三个属性Id,ENTITYID和carid的相同的值的多个行,它是不定其中那些行的value将从服用。


要插入在表2中,但是从表1(再次假设这三个栏可能无法在表2是唯一的)“失踪”行,我们可以用一个反连接模式以消除已经有行表1中的“匹配”。

例如:

INSERT INTO table1 (attributeid, entityid, carid, value) 
SELECT v.* 
    FROM (SELECT s.attribute_id 
       , s.entity_id 
       , s.carid 
       , s.value 
      FROM table2 s 
      LEFT 
      JOIN table1 r 
       ON r.attributeid = s.attributeid 
      AND r.entityid = s.entityid 
      AND r.carid  = s.carid 
      WHERE r.attributeid IS NULL 
      AND s.attributeid IS NOT NULL 
      AND s.entityid IS NOT NULL 
      AND s.carid  IS NOT NULL 
      GROUP 
       BY s.attributeid 
       , s.entityid 
       , s.carid 
     ) v 

如果有“重复”在表2(即,在表2的多个行与三个属性Id,ENTITYID和carid的相同的值,它是不确定哪一行value将取自

如果在其他列或列组合上定义了其他UNIQUE约束,则该语句有可能抛出“重复键”错误(不知道键的定义,我们有点儿飞盲。)我们可以添加IGNORE关键字如果我们希望语句成功,只是忽略由于“唯一键”违规而无法插入的行。)

同样,如果在table2与在三列相同的值(没有给出指示该列的这种组合是在表2是唯一的)的行,它是不确定的,其这些行的value将被带走。

可以在相反的方向执行相同的操作,交换查询中所有出现的表格引用table1table2


没有必要为任何一个表添加一个UNIQUE KEY来执行这些操作。如果定义了合适的索引,那么(可能)会带来性能上的好处,这三列将作为索引中的第一列。 (对于此操作,这不一定需要是UNIQUE索引。)

如果该列组合应该是唯一的,那么通过所有方法在该组合列上添加一个UNIQUE KEY。但是指定的操作可以在没有定义唯一键的情况下执行。

MySQL INSERT ... ON DUPLICATE KEY语法确实需要至少一个PRIMARY KEY或UNIQUE KEY来操作。如果目标表上存在多个UNIQUE KEY约束,并且INSERT会违反两个或更多个唯一键约束,那么我相信不确定哪些键将用于UPDATE操作。就我个人而言,我倾向于避免在定义了多个UNIQUE KEY的表上使用该语法。

+0

我的天啊。我很惊讶这是一个如此复杂的操作。完美的作品!非常感谢您花时间帮忙,spencer :) – Nav

0

您可以使用语法

ALTER IGNORE TABLE table1 ADD UNIQUE INDEX PIndex (attributeId, entityId, carId); 

根据the documentation

如果忽视的是指定的,只有一行与唯一键重复使用的行。其他冲突的行被删除。不正确的值将被截断为最接近的匹配可接受值。

不幸的是,它没有指定哪个价值将被保留。做一些测试似乎喜欢它保持第一次出现,但你永远无法确定。

如果哪个入口不会打扰您,这是最简单的解决方案,否则如果您想要更多控制,最好通过临时表。

命令CREATE UNIQUE PIndex ON table1 (attributeId, entityId, carId);(注意添加的UNIQUE)只会在第一个重复键上失败,并且没有管理重复项的选项可用。