我有一个包含以下字段的表:
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查询来完成。
25条答案
按热度按时间vddsk6oq1#
mysql对引用要从中删除的表有限制。您可以使用临时表来解决此问题,例如:
根据科斯塔诺斯在评论中的建议:
上面唯一慢的查询是delete,用于数据库非常大的情况。此查询可以更快:
0kjbasz62#
您可以轻松地从此代码中删除重复记录。。
ma8fv8wu3#
我有一个表,它忘记在id行中添加主键。虽然它的id是自动递增的,但是有一天,一个东西在数据库上重放mysql bin日志,其中插入了一些重复的行。
我删除重复的行
选择唯一的重复行并导出它们
select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;
按id删除重复行插入导出数据中的行。
然后在id上添加主键
kokeuurv4#
删除mysql表上的重复项是一个常见的问题,这通常是因为缺少一个约束来避免这些重复项。但这个共同的问题通常伴随着特定的需要。。。这确实需要具体的方法。方法应该有所不同,例如,取决于数据的大小、应保留的重复条目(通常是第一个或最后一个条目)、是否要保留索引,或者是否要对重复数据执行任何其他操作。
mysql本身也有一些特殊性,比如在执行表更新时不能引用from上的同一个表(这将引发mysql错误#1093)。这个限制可以通过使用带有临时表的内部查询来克服(正如上面一些方法所建议的)。但在处理大数据源时,这种内部查询的性能不会特别好。
但是,确实存在一种更好的方法来删除重复项,这种方法既高效又可靠,并且可以很容易地适应不同的需要。
一般的想法是创建一个新的临时表,通常添加一个唯一的约束以避免进一步的重复,并将以前表中的数据插入到新表中,同时处理重复项。这种方法依赖于简单的mysql insert查询,创建一个新的约束以避免进一步的重复,并且不需要使用内部查询来搜索重复项和应该保存在内存中的临时表(因此也适合大数据源)。
这就是如何实现的。假设我们有一个表employee,包含以下列:
要删除具有重复ssn列的行,并仅保留找到的第一个条目,可以执行以下过程:
技术说明
第1行创建一个新的tmp#u eployee表,其结构与employee表完全相同
第2行为新的tmp#u eployee表添加了一个惟一的约束,以避免任何重复
第3行按id扫描原始employee表,将新的employee条目插入新的tmp#u eployee表,同时忽略重复的条目
第#4行重命名表,这样新的employee表将保留所有条目,而不保留重复项,并且在backup#employee表中保留前一个数据的备份副本
⇒ 使用这种方法,160万个寄存器在不到200秒内转换成6k。
chetan,按照此过程,您可以快速轻松地删除所有重复项,并通过运行以下命令创建唯一约束:
当然,这个过程可以进一步修改,以适应删除重复项时的不同需要。下面是一些例子。
✔ 保留最后一个条目而不是第一个条目的变体
有时我们需要保留最后一个重复条目而不是第一个条目。
在第3行,orderbyid desc子句使最后一个id优先于其余的id
✔ 对重复项执行某些任务的变体,例如对找到的重复项进行计数
有时我们需要对找到的重复条目执行一些进一步的处理(例如保持重复条目的计数)。
在第#3行中,将创建一个新列n#u duplicates
在第4行,插入到。。。在重复密钥更新查询是用来执行一个额外的更新时,重复发现(在这种情况下,增加计数器)插入到。。。在重复密钥更新查询可用于执行不同类型的更新找到的重复。
✔ 用于重新生成自动增量字段id的变体
有时我们使用一个自动增量字段,为了使索引尽可能紧凑,我们可以利用删除重复项的机会在新的临时表中重新生成自动增量字段。
在第3行,不再选择表中的所有字段,而是跳过id字段,以便db引擎自动生成一个新字段
✔ 进一步的变化
根据期望的行为,许多进一步的修改也是可行的。例如,以下查询将使用第二个临时表来保存最后一个条目,而不是第一个条目;对发现的重复项增加计数器;另外3)重新生成自动增量字段id,同时保持输入顺序与前一个数据相同。
ia2d9nvy5#
删除表中的重复记录。
或
wxclj1h56#
我找到了一个简单的方法(保持最新)
9rbhqvlz7#
此解决方案将把重复项移到一个表中,把唯一项移到另一个表中。
pvabu6sv8#
如果您有一个包含大量记录的大表,那么上述解决方案将不起作用或花费太多时间。然后我们有一个不同的解决方案
nr9pn0ug9#
zlwx9yxi10#
从版本8.0(2018)开始,mysql最终支持窗口功能。
窗口功能既方便又高效。下面是一个演示如何使用它们来解决此分配的解决方案。
在子查询中,我们可以使用
ROW_NUMBER()
为表中的每个记录指定一个位置column1/column2
组,排序方式id
. 如果没有重复项,则记录将获得行号1
. 如果存在重复项,它们将按升序编号id
(从1
).一旦记录在子查询中正确编号,外部查询只会删除行号不是1的所有记录。
查询:
ki1q1bka11#
更快的方法是将不同的行插入到临时表中。使用delete,我花了几个小时从一个800万行的表中删除重复项。使用insert和distinct,只花了13分钟。
mi7gmzs612#
一个非常简单的方法是添加一个
UNIQUE
3列上的索引。当你写下ALTER
声明,包括IGNORE
关键字。像这样:这将删除所有重复的行。作为一个额外的好处,未来
INSERTs
重复的将出错。像往常一样,您可能希望在运行这样的操作之前进行备份。。。cedebl8k13#
如果不想更改列属性,那么可以使用下面的查询。
因为您有一个具有唯一ID的列(例如。,
auto_increment
列),可以使用它删除重复项:在mysql中,可以使用空安全相等运算符(又称“spaceship运算符”)进一步简化它:
qgelzfjb14#
为了复制具有唯一列的记录,例如col1、col2、col3不应该被复制(假设我们在表结构中遗漏了3列unique,并且表中有多个重复条目)
希望能帮助德夫。
kq0g1dla15#
简单易懂且无主键的解决方案:
1) 添加新的布尔列
2) 在复制列和新列上添加约束
3) 将布尔列设置为true。由于新的约束,这将只在一个重复的行上成功
4) 删除尚未标记为保留的行
5) 删除添加的列
我建议您保留添加的约束,以便将来防止新的重复。