Php SQL每次删除重复的一行

Php SQL每次删除重复的一行,php,sql,mysql,duplicates,duplicate-removal,Php,Sql,Mysql,Duplicates,Duplicate Removal,我有一个表,保存所有发生的行更改。问题在于,在应用程序的开始阶段,有一个bug生成了每一行的大量副本 该表如下所示: 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 copies |ID |CID

我有一个表,保存所有发生的行更改。问题在于,在应用程序的开始阶段,有一个bug生成了每一行的大量副本

该表如下所示:

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
copies
|ID |CID |DATA
| 1 | 1  |  DA
| 2 | 2  |  DO
| 2 | 5  |  DA
| 2 | 7  |  DO
CID在表副本中是唯一的

我想要的是删除按ID分组的所有重复数据,这些重复数据是按CID排序的

正如您在表中所看到的,CID 2和3是相同的,并且它们是一个接一个的。我想删除CID 3。与CID 4和CID 6相同;它们之间没有ID 1,是CID 1的副本

删除重复项后,我希望该表如下所示:

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
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排序时,只有重复项直接在另一个之后。

您可以在子查询中使用计数:

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
此解决方案使用MySQL会话变量

有一个纯ANSI解决方案将使用NOT EXISTS,但是,由于MySQL optimizer的工作方式,它会很慢—它不会在相关子查询中使用范围访问方法

请参阅我的博客中的这篇文章,了解有关相当接近的任务的性能详细信息:



从副本c中删除其中的c.cid选择maxcid作为max_cid,从副本中计数*作为num,其中num>1按id分组,数据

真的吗?这里有三种纯SQL方法,您建议使用解释语言启动单删除事务?我真诚地希望这不是解决所有数据库问题的方式。数据库是关于集合思考的!1º表示咨询是一个过程。2º有一个PHP标记,所以可以使用这种语言包含一个解决方案。还有什么吗?@Eric为了清理,这项任务必须完成一次,所以我认为速度不是这里的首要问题。这就是一个有效的答案,如果不是最好的答案。1º?2º? 什么是学位分数?我的意思并不是说要斯奈德……这就是某些语言写序数的方式吗?@andres:我认为你基于光标的解决方案可能是目前为止实现这一点的最佳方式——但我希望用“按ID排序,按CID排序”来排序数据。另请参阅我对主要问题的评论。这将仅删除最后一个副本,而不是所有副本。是的,您是对的,但您可以再次运行查询,直到删除所有副本。你的解决方案更优雅我已经投了你的票!感谢您的建议,但这会删除:| 2 | 7 |不要删除所有应删除的相同行,只删除按ID分组的一行之后的行。要正确执行此操作,您还必须有一个标准,即不存在具有不同数据值和相同ID值的行,并且在“当前行”和“具有相同数据值的较早行”之间没有CID。好吧,最多也只能这么说。嗨,我试过这个,它几乎删除了我桌上的所有东西。如果我有多个数据列,查询应该是什么样子?很好,非常感谢。乍一看似乎是对的。我将运行一些测试来验证!在最终结果集中,2,2和2,7之间也没有id 1。这是否意味着它们也应该被删除?如果没有,它们的区别是什么?它们之间没有ID 1,但它们有2,5,DA。ID应作为重复数据忽略,它应用于将行分组在一起。谈论两个ID可能会分散注意力。如果查看上一个表,您只会看到一个ID和该ID的预期结果。1、1和1、4之间有一个DO。那么为什么要删除1,4呢?如果采用ID=1的条目的CID的升序,则有:1,1,DA,1,4,DA,1,6,DA。由于这些行中的ID和数据值相同,因此只保留“重复”中的第一个。类似地,对于ID=2,序列是:2,2,DO,2,3,DO,2,5,DA,2,7,DA。CID=3和CID=2行中的ID和数据值相同,应删除CID=3;与CID=2相比,CID=5的行在数据中具有不同的值,应为ke[t,并且CID=7的行在数据中的值与CID=5的值不同,因此应保留该值。Quassnoi:因为DO不是来自同一ID。查询应始终按ID分组。我认为这根本不正确。它没有考虑按ID和CID排序的连续行之间的数据值。它实际上是这样的是的,我只是把数据标错了名字。我的错误。修复了!
// 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];
}