sql—删除主键与其他表连接的重复行

yftpprvb  于 2021-07-24  发布在  Java
关注(0)|答案(2)|浏览(230)

某个进程导致表中不应有重复行的表中出现重复行。在线删除重复行有几个很好的答案。但是,如果那些具有id主键的副本在其他表中都有数据绑定到它们呢?
有没有办法删除第一个表中的所有重复项,并将绑定到这些键的所有数据迁移到未删除的单个pk id?
例如:

TABLE 1
+-------+----------+----------+------------+
| ID(PK)| Model    | ItemType | Color      |
+-------+----------+----------+------------+
| 1     | 4        | B        | Red        |
| 2     | 4        | B        | Red        |
| 3     | 5        | A        | Blue       |
+-------+----------+----------+------------+

TABLE 2
+-------+----------+---------+
| ID(PK)| OtherID  | Type    |
+-------+----------+---------+
| 1     | 1        | Type1   |
| 2     | 1        | Type2   |
| 3     | 2        | Type3   |
| 4     | 2        | Type4   |
| 5     | 2        | Type5   |
+-------+----------+---------+

所以理论上我想从表1中删除id为2的条目,然后让表2中的otherid字段切换到1。这实际上是x个表所需要的。这种特殊情况有4个表连接到它的id pk。

jaxagkaj

jaxagkaj1#

您不能自动执行此操作。但您可以通过一些查询来实现这一点。首先,将所有外键设置为正确的id,这可能是最小的id:

with ids (
      select t1.*, min(id) over (partition by Model, ItemType, Color) as min_id
      from table1 t1
     )
update t2
    set t2.otherid = ids.min_id
    from table2 t2 join
         ids
         on t2.otherid = ids.id
    where ids.id <> ids.min_id;

然后删除中重复或未引用的ID table2 (取决于你真正想要的):

with ids (
      select t1.*, min(id) over (partition by Model, ItemType, Color) as min_id
      from table1 t1
     )
delete from ids
    where id <> min_id;

注意:如果数据库有并发用户,您可能希望将其置于单用户模式下执行此操作,或者锁定表,以便在这两个操作期间不修改它们。

dy1byipe

dy1byipe2#

要做到这一点,您需要将所有内容打包到单个事务中,并在常规维护期间执行此操作。其他任何事情都会让事情变得像现在这样不一致。
决定你要用哪把“钥匙”。
更新所有子表以使用新的“键”,其中值是旧的“键”。
重复记录上不应有fk依赖项,请删除它们。
一旦所有的歧义都解决了,就在 (ItemType,Color) (或者不管真正的列是什么)。
如果有很多示例,您可能需要编写一个脚本来处理这个问题,并使用中的信息 sys.foreign_keys 以及 sys.foreign_key_columns 确定要更新哪些记录以及更新顺序。

相关问题