我有以下MySQL表:

id            rid
-----       ------
1             2
2             1
2             3
3             2
1             3
3             1


我想更改此设置,以便每个关系仅存在一行。

例如:

id           rid
-----       ------
1             2
2             3
1             3

最佳答案

如果您总是成对出现(例如您的示例):

delete from table
    where id > rid;


这样会保留id较小的记录。

如果存在所有对都不存在的可能性,则:

delete t
    from table t left outer join
         (select least(id, rid) as lid, greatest(id, rid) as gid, count(*) as cnt
          from table t2
          group by least(id, rid), greatest(id, rid)
         ) t2
         on least(t.id, t.rid) = t2.lid and greatest(t.id, t.rid) = gid
    where id < rid or t2.cnt = 1;


编辑(解释):

第二个查询如何工作?老实说,我要写的是这样的:

delete t from table t
   where id < rid or
         (id > rid and
          not exists (select 1 from table t2 where t2.id = t.rid and t2.rid = t.id
         );


也就是说,我要将所有记录保留在id < rid所在的位置。但是然后,我也想将所有单例记录保留在rid > id位置。我认为MySQL不允许where子句使用语法。

相反,答案中的查询通过查看最小值和最大值来计算一对存在的次数。对于问题中的数据,子查询的结果为:

id  rid  cnt
 1   2    2
 2   3    2
 1   3    2


因此,所有这些都将使用id < rid选择该行。如果还有一行,请说4, 1。它看起来像:

lid gid  cnt
 1   2    2
 2   3    2
 1   3    2
 1   4    1


在这种情况下,前三个将使用id < rid作为行。但是也会选择新行,因为cnt为1。

如果您在表和主键中有重复项,那么在查询上会做些相同的事情而稍有不同。

关于mysql - 删除交叉引用数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21353794/

10-11 05:21