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

sdnqo3pr  于 2021-06-24  发布在  Mysql
关注(0)|答案(2)|浏览(316)

我看到很多人都问起了升级(这个,这个,这个,这个,这个,这个,这个,还有更多,甚至是官方的文件)。
但是,对于新手来说,如何使用主键或唯一索引创建重复键还没有得到足够的解释。
我需要的是:
如果 table1 的独特组合3列( attributeId, entityId, carId )中有一个副本 table2 ,然后更新 value 列。否则就拿走 table1 的行并将其插入 table2 .
这个 attributeId, entityId, carId 每行的组合都是唯一的。
ie:如果一行有列作为 1,2,5 ,则没有其他行 1,2,5 . 但另一排可能 5,1,2 或者 3,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 如果attributeid、entityid和carid的值完全相同,则更新 value 中的列 table1 有价值的 value 中的列 table2 . 如果没有对应的行,则取 table2 并将其附加到 table1 .

9rygscc1

9rygscc11#

该规范似乎针对两种不同的操作:1)更新表1中的现有行,2)向表2中插入新行。
规范说“更新值列”。。。我们认为这意味着更新 table1 .
说明书上还写着“插入。。。进入 table2 .
令人困惑的是,该规范还显示了一个伪代码示例 INSERT INTO table1 .
更新 table1 基于中的值 table2 ,假设我们要忽略三列中任何一列的值为空的行。。。

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 如果attributeid、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中有多行的attributeid、entityid和carid三列值相同,则不确定是哪一行 value 将从中删除。
如果在其他列或列的组合上定义了其他唯一约束,则该语句有可能抛出“复制键”错误(在不知道关键定义的情况下,我们有点盲目。)我们可以添加 IGNORE 关键字,只忽略由于“unique key”冲突而无法插入的行。)
同样,如果 table2 如果三列中的值相同(没有迹象表明这三列的组合在表2中是唯一的),则无法确定这些行中的哪一行 value 将从中删除。
相同的操作可以在相反的方向上执行,交换表引用的所有引用 table1 以及 table2 在查询中。
执行这些操作时,不必向任何一个表添加唯一键。如果定义一个合适的索引,并且将这三列作为索引中的前导(第一)列,那么(很可能)会对性能有好处(对于此操作,它不一定需要是唯一的索引。)
如果该列的组合应该是唯一的,那么一定要在该列的组合上添加唯一键。但是指定的操作可以在没有定义唯一键的情况下执行。
mysql INSERT ... ON DUPLICATE KEY 语法至少需要一个主键或唯一键才能操作。如果目标表上有多个唯一键约束,并且一个insert会违反两个或多个唯一键约束,那么我认为在update操作中使用哪一个键是不确定的。我个人倾向于避免在定义了多个唯一键的表上使用这种语法。

mo49yndu

mo49yndu2#

你可以使用语法

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

根据文件:
如果指定ignore,则在唯一键上具有重复项的行中只使用一行。其他冲突行将被删除。不正确的值将被截断为最接近匹配的可接受值。
不幸的是,它没有指定将保留哪个值。做一些测试,它似乎保持了第一次出现,但你永远不能确定。
如果哪个条目将被删除并不困扰您,这是最简单的解决方案,否则如果您想要更多的控制权,最好通过一个临时表。
命令 CREATE UNIQUE PIndex ON table1 (attributeId, entityId, carId); (请注意,添加了 UNIQUE )只会在第一个重复密钥上失败,并且没有管理重复项的选项可用。

相关问题