升级到MySQL,但使用多列和唯一索引作为重复检查?

升级到MySQL,但使用多列和唯一索引作为重复检查?,mysql,indexing,upsert,database-indexes,on-duplicate-key,Mysql,Indexing,Upsert,Database Indexes,On Duplicate Key,我看到很多人问起了升级(、、甚至是升级) 然而,对于新手来说,还没有充分解释的是如何使用主键或唯一索引创建重复键。 我需要什么: 如果table1的3列唯一组合(attributeId、entityId、carId)在table2中存在重复项,则更新值列。否则,将表1的行插入表2 attributeId、entityId、carId的组合对于每一行都是唯一的。 ie:如果一行的列为1,2,5,那么其他行将不会有1,2,5。但另一行可能有5,1,2或3,4,2等 这里的难题是创建唯一索引。这样做是

我看到很多人问起了升级(、、甚至是升级)

然而,对于新手来说,还没有充分解释的是如何使用主键或唯一索引创建重复键。

我需要什么
如果
table1
的3列唯一组合(
attributeId、entityId、carId
)在
table2
中存在重复项,则更新
列。否则,将
表1
的行插入
表2

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

这里的难题是创建唯一索引。这样做是否足够:

在表1上创建索引PIndex(attributeId、entityId、carId)

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

基本逻辑是:
如果对于
表2
中的一行,在
表1
中有一个对应行的attributeId、entityId和carId值完全相同,则使用
表2
中的
value
列的值更新
表1
中的
value
列。如果没有对应的行,则取
table2
的行并将其附加到
table1

您可以使用语法

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

如果指定了IGNORE,则在唯一键上具有重复项的行中仅使用一行。其他冲突行将被删除。不正确的值将被截断为最接近的匹配可接受值

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

如果您不介意删除哪个条目,这是最简单的解决方案,否则如果您想要更多的控制权,最好通过一个临时表


命令
在表1上创建唯一的PIndex(attributeId、entityId、carId)
(请注意,添加的
UNIQUE
)在第一个复制键上将失败,并且没有管理复制项的选项可用。

该规范似乎适用于两种不同的操作:1)更新表1中的现有行,2)在表2中插入新行

规范中说“更新值列”。。。我们认为这意味着更新
表1
行中的值列

该规范还规定“将……插入
表2

令人困惑的是,该规范还显示了一个示例伪代码
插入表1


要根据
表2
中的值执行
表1
的更新,假设我们将忽略三列中任何一列中具有空值的行

 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 
如果
中存在“重复项”(即
中有多行的属性ID、实体ID和carid三列值相同,则不确定将从这些行的
值中选取哪一行


要插入在表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中的多行具有相同的attributeid、entityid和carid三列值),则无法确定将从哪一行获取值

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

同样,如果
表2
中的行在三列中具有相同的值(没有迹象表明此列组合在表2中是唯一的),则不确定将从这些行中选择哪一行

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


执行这些操作时,无需向两个表中的任何一个表添加唯一键。定义适当的索引,将这三列作为索引中的前导(第一)列(这不一定是此操作的唯一索引),可能会(可能)提高性能

如果该列的组合应该是唯一的,那么无论如何都要在该列的组合上添加一个唯一键。但是指定的操作可以在不定义唯一键的情况下执行


MySQL
INSERT…ON DUPLICATE KEY
语法确实需要至少一个主键或唯一键来操作。如果目标表上存在多个唯一键约束,并且一次INSERT将违反两个或多个唯一键约束,我相信不确定更新操作中将使用这些键中的哪一个。根据通常,我倾向于避免在定义了多个唯一键的表上使用这种语法。

天哪,我很惊讶这是一个如此复杂的操作。工作非常完美!非常感谢您花时间提供帮助,spencer:)
 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