我有一个包含以下字段的表:
id (Unique)
url (Unique)
title
company
site_id
现在,我需要删除具有相同 title, company and site_id
的行 . 一种方法是使用以下SQL和脚本( PHP ):
SELECT title, site_id, location, id, count( * )
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1
运行此查询后,我可以使用服务器端脚本删除重复项 .
但是,我想知道是否只能使用SQL查询来完成 .
17 回答
还有另一种解决方案:
我随时随地访问此页面谷歌“删除重复的形式mysql”但我的theIGNORE解决方案不起作用,因为我有一个InnoDB mysql表
此代码随时可以更好地工作
tableToclean =您需要清理的表的名称
tableToclean_temp =创建和删除的临时表
删除MySQL表上的重复项是一个常见的问题,这通常是缺少约束的结果,以避免事先重复这些重复 . 但这个常见问题通常伴随着特定的需求......确实需要特定的方法 . 该方法应该根据,例如,数据的大小,应保留的重复条目(通常是第一个或最后一个),是否存在索引,或者我们是否要执行任何其他对重复数据采取行动 .
MySQL本身也有一些特殊性,例如在执行表UPDATE时无法在FROM原因上引用同一个表(它会引发MySQL错误#1093) . 通过使用具有临时表的内部查询(如上面的一些方法所建议的),可以克服此限制 . 但是,在处理大数据源时,这种内部查询不会特别好 .
然而,确实存在一种更好的方法来消除重复,这既是高效又可靠的,并且可以很容易地适应不同的需求 .
一般的想法是创建一个新的临时表,通常添加一个唯一的约束来避免进一步的重复,并将前一个表中的数据插入到新表中,同时处理重复项 . 这种方法依赖于简单的MySQL INSERT查询,创建一个新的约束以避免进一步的重复,并且跳过使用内部查询来搜索重复项的需要以及应该保存在内存中的临时表(因此也适合大数据源) .
这是如何实现的 . 鉴于我们有一个表 employee ,包含以下列:
要删除具有重复 ssn 列的行,并仅保留找到的第一个条目,可以执行以下过程:
技术说明
第1行创建一个新的 tmp_eployee 表,其结构与 employee 表完全相同
第2行为新的 tmp_eployee 表添加了一个UNIQUE约束,以避免任何进一步的重复
第3行按ID扫描原始 employee 表,将新员工条目插入新的 tmp_eployee 表,同时忽略重复的条目
第4行重命名表,以便新的 employee 表保存所有没有重复项的条目,并且前一数据的备份副本保存在 backup_employee 表中
⇒使用这种方法,1.6M寄存器在不到200s的时间内转换为6k .
Chetan,按照此过程,您可以快速轻松地删除所有重复项并通过运行以下命令创建UNIQUE约束:
当然,在删除重复项时,可以进一步修改此过程以使其适应不同的需要 . 一些例子如下 .
✔保留最后一个条目而不是第一个条目的变化
有时我们需要保留最后一个重复的条目而不是第一个条目 .
✔对重复项执行某些任务的变化,例如对发现的重复项进行计数
有时我们需要对找到的重复条目执行一些进一步处理(例如保留重复项的计数) .
在第3行,创建了一个新列 n_duplicates
在第4行, INSERT INTO ... ON DUPLICATE KEY UPDATE 查询用于在找到重复项时执行其他更新(在这种情况下,增加计数器) INSERT INTO ... ON DUPLICATE KEY UPDATE 查询可用于对找到的重复项执行不同类型的更新 .
✔重新生成自动增量字段ID的变化
有时我们使用自动增量字段,为了使索引保持尽可能紧凑,我们可以利用删除重复项来重新生成新临时表中的自动增量字段 .
✔进一步的变化
根据所需的行为,许多进一步的修改也是可行的 . 例如,以下查询将使用第二个临时表,除了1)保留最后一个条目而不是第一个条目; 2)在找到的副本上增加一个计数器;3)重新生成自动增量字段id,同时保持在前一数据上的输入顺序 .
如果您不想更改列属性,则可以使用下面的查询 .
由于您的列具有唯一ID(例如,
auto_increment
列),因此您可以使用它来删除重复项:在MySQL中,您可以使用NULL-safe equal operator(aka "spaceship operator")进一步简化它:
MySQL对引用要删除的表有限制 . 您可以使用临时表解决此问题,例如:
From Kostanos' suggestion in the comments:
对于您拥有非常大的数据库的情况,上面唯一的慢查询是DELETE . 此查询可能更快:
如果
IGNORE
语句不能像我的情况那样工作,您可以使用以下语句:如果你有一个包含大量记录的大表,那么以上解决方案将无法工作或占用太多时间 . 然后我们有不同的解决方案
所有情况都简单快捷:
我有这个查询snipet for SQLServer但我认为它可以在其他DBMS中使用,几乎没有变化:
我忘了告诉你这个查询不会删除重复行id最低的行 . 如果这适用于您尝试此查询:
您可以轻松地从此代码中删除重复记录 .
一个非常简单的方法是在3列上添加
UNIQUE
索引 . 编写ALTER
语句时,请包含IGNORE
关键字 . 像这样:这将删除所有重复的行 . 作为一个额外的好处,未来
INSERTs
是重复的将错误 . 与往常一样,您可能希望在运行此类内容之前进行备份...一个易于理解且无需主键的解决方案:
1)添加一个新的布尔列
2)在重复列和新列上添加约束
3)将布尔列设置为true . 由于新约束,这将仅在其中一个重复行上成功
4)删除尚未标记为维护的行
5)删除添加的列
我建议您保留您添加的约束,以便将来阻止新的重复项 .
我必须使用文本字段执行此操作,并且在索引上遇到了100个字节的限制 .
我通过添加一个列,执行字段的md5哈希以及执行alter来解决了这个问题 .
此解决方案将 move the duplicates into one table 和 uniques into another .
我想更具体一点,我删除了哪些记录,所以这里是我的解决方案:
更快的方法是将不同的行插入临时表 . 使用删除,我花了几个小时从一个800万行的表中删除重复项 . 使用insert和distinct,只花了13分钟 .
使用DELETE JOIN语句删除重复行MySQL为您提供了DELETE JOIN语句,您可以使用该语句快速删除重复的行 .
以下语句删除重复行并保留最高ID: