删除交叉引用的数据

时间:2014-01-25 17:30:29

标签: mysql sql

我有以下MySQL表:

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

我想改变它,因此每个关系只存在一行。

例如:

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

1 个答案:

答案 0 :(得分: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。

如果表中有重复项,那么查询中会有一些轻微的变化,可以做同样的事情。