SQL一次删除一行重复项

时间:2009-08-24 12:20:30

标签: php sql mysql duplicates duplicate-removal

我有一个表格,用于保存所有已发生的行更改。问题是,在应用程序的开头,有一个错误,每行都有一堆副本。

表格如下所示:

copies
|ID |CID |DATA
| 1 | 1  |  DA
| 2 | 2  |  DO
| 2 | 3  |  DO (copy of CID 2)
| 1 | 4  |  DA (copy of CID 1)
| 2 | 5  |  DA
| 1 | 6  |  DA (copy of CID 1)
| 2 | 7  |  DO

表格副本中的CID是唯一的。

我想要的是删除按CID排序的所有DATA GROUP BY ID重复项。

正如您在表中看到的那样,CID 2和3是相同的,它们是相继的。我想删除CID 3.与CID 4和CID 6相同;他们之间没有ID 1,是CID 1的副本。

删除重复项后,我希望该表看起来像这样:

copies
|ID |CID |DATA
| 1 | 1  |  DA
| 2 | 2  |  DO
| 2 | 5  |  DA
| 2 | 7  |  DO

有什么建议吗? :)

我认为我的问题很严重,因为每个人似乎认为最好的答案会给出这个结果:

ID   | DATA | DATA | DATA | DATA | DATA |     DATA |        CID          |
                                                   |Expected |  Quassnoi |
1809 |    1 |    0 |    1 |    0 |    0 |     NULL |  252227 |    252227 |
1809 |    1 |    0 |    1 |    1 |    0 |     NULL |  381530 |    381530 |
1809 |    1 |    0 |    1 |    0 |    0 |     NULL |  438158 | (missing) |
1809 |    1 |    0 |    1 |    0 | 1535 | 20090113 |  581418 |    581418 |
1809 |    1 |    1 |    1 |    0 | 1535 | 20090113 |  581421 |    581421 |

CID 252227和CID 438158是重复的,但因为CID 381530介于它们之间;我想保留这个。当按CID和ID排序时,它只是一个接一个地重复的副本。

4 个答案:

答案 0 :(得分:5)

DELETE   c.*
FROM     copies c
JOIN     (
         SELECT  id, data, MIN(copies) AS minc
         FROM    copies
         GROUP BY
                 id, data
         ) q
ON       c.id = q.id
         AND c.data = q.data
         AND c.cid <> q.minc

<强>更新

DELETE  c.*
FROM    (
        SELECT  cid
        FROM    (
                SELECT  cid,
                        COALESCE(data1 = @data1 AND data2 = @data2, FALSE) AS dup,
                        @data1 := data1,
                        @data2 := data2
                FROM    (
                        SELECT  @data1 := NULL,
                                @data2 := NULL
                        ) vars, copies ci
                ORDER BY
                        id, cid
                ) qi
        WHERE   dup
        ) q
JOIN    copies c
ON      c.cid = q.cid

此解决方案会使MySQL会话变量失效。

有一个纯ANSI解决方案会使用NOT EXISTS,但是,由于MySQL优化器的工作方式(它不会使用range),它会很慢相关子查询中的访问方法)。

请参阅我的博客中的这篇文章,了解相关任务的性能详情:

答案 1 :(得分:1)

您可以在子查询中使用count

delete from copies
where
    (select count(*) from copies s where s.id = copies.id 
                                   and s.data = copies.data 
                                   and s.cid > copies.cid) > 0

答案 2 :(得分:1)

// EDITED for @Jonathan Leffler comment
//$sql = "SELECT ID,CID,DATA FROM copies ORDER BY CID, ID";
$sql = "SELECT ID,CID,DATA FROM copies ORDER BY ID, CID";
$result = mysql_query($sql, $link); 
$data = "";
$id = "";
while ($row = mysql_fetch_row($result)){ 
       if (($row[0]!=$id) && ($row[2]!=$data) && ($id!="")){
            $sql2 = "DELETE FROM copies WHERE CID=".$row[1];
            $res = mysql_query($sql2, $link); 
       }
       $id=$row[0];
       $data=$row[2];
} 

答案 3 :(得分:0)

从副本c中删除c.cid in(选择max(cid)为max_cid,count(*)为num,其中num> 1,group by id,data)