【发布时间】:2010-10-14 04:18:48
【问题描述】:
使用 rails 或 mysql 查询删除 mysql 数据库中重复记录的最佳方法是什么?
【问题讨论】:
-
您需要一个关键字段来查找以使记录与众不同,这样您就可以知道要删除什么
标签: mysql ruby-on-rails ruby
使用 rails 或 mysql 查询删除 mysql 数据库中重复记录的最佳方法是什么?
【问题讨论】:
标签: mysql ruby-on-rails ruby
Delete t1 from table1 inner join table1 t2 where t1.id < t2.id and t1.name = t2.name
更多详情请查看以下 YouTube 链接:
【讨论】:
首先对要删除重复项的列进行分组。但我没有使用分组。我正在写自我加入。
您不需要创建临时表。
删除除一条记录之外的重复项: 在这个表中它应该有自动增量列。 我刚刚遇到的可能的解决方案:
DELETE n1 FROM names n1, names n2 WHERE n1.id > n2.id AND n1.name = n2.name
如果您想保留自动增量 id 值最低的行或
DELETE n1 FROM names n1, names n2 WHERE n1.id < n2.id AND n1.name = n2.name
如果您想保留具有最高自动增量 id 值的行。
您可以交叉检查您的解决方案,再次找到重复项:
SELECT * FROM `names` GROUP BY name, id having count(name) > 1;
如果返回0结果,则查询成功。
【讨论】:
这是我想出的 Rails 解决方案。可能不是最有效的,但如果是一次性迁移,则没什么大不了的。
distinct_records = MyTable.all.group(:distinct_column_1, :distinct_column_2).map {|mt| mt.id}
duplicates = MyTable.all.to_a.reject!{|mt| distinct_records.include? mt.id}
duplicates.each(&:destroy)
首先,按确定唯一性的所有列分组,示例显示 2,但您可以有更多或更少
其次,选择该组的倒数...所有其他记录
第三,删除所有这些记录。
【讨论】:
我使用上面@krukid 的答案在大约 70,000 个条目的表格上执行以下操作:
rs = 'select a, b, count(*) as c from table group by 1, 2 having c > 1'
# get a hashmap
dups = MyModel.connection.select_all(rs)
# convert to array
dupsarr = dups.map { |i| [i.a, i.b, i.c] }
# delete dups
dupsarr.each do |a,b,c|
ActiveRecord::Base.connection.execute("delete from table_name where a=#{MyModel.sanitize(a)} and b=#{MyModel.sanitize(b)} limit #{c-1}")
end
【讨论】:
假设我们有一个表名 tbl_product 并且在字段 p_pi_code 和 p_nats_id 的最大计数中存在重复
首先创建一个新表,从现有表中插入数据...
即从 tbl_product 到 newtable1,如果还有其他内容,则从 newtable1 到 newtable2
CREATE TABLE `newtable2` (
`p_id` int(10) unsigned NOT NULL auto_increment,
`p_status` varchar(45) NOT NULL,
`p_pi_code` varchar(45) NOT NULL,
`p_nats_id` mediumint(8) unsigned NOT NULL,
`p_is_special` tinyint(4) NOT NULL,
PRIMARY KEY (`p_id`)
) ENGINE=InnoDB;
INSERT INTO newtable1 (p_status, p_pi_code, p_nats_id, p_is_special) SELECT
p_status, p_pi_code, p_nats_id, p_is_special FROM tbl_product group by p_pi_code;
INSERT INTO newtable2 (p_status, p_pi_code, p_nats_id, p_is_special) SELECT
p_status, p_pi_code, p_nats_id, p_is_special FROM newtable1 group by p_nats_id;
之后我们看到该字段中的所有重复项都被删除了
【讨论】:
我正在使用Alter Table
ALTER IGNORE TABLE jos_city ADD UNIQUE INDEX(`city`);
【讨论】:
ERROR 1062 (23000): Duplicate entry '14190-2089' for key 'vid'
如果您在表 (EMP) 中有 PK (id) 并且想要较旧地删除具有名称列的重复记录。对于大数据,以下查询可能是不错的方法。
DELETE t3
FROM (
SELECT t1.name, t1.id
FROM (
SELECT name
FROM EMP
GROUP BY name
HAVING COUNT(name) > 1
) AS t0 INNER JOIN EMP t1 ON t0.name = t1.name
) AS t2 INNER JOIN EMP t3 ON t3.name = t2.name
WHERE t2.id < t3.id;
【讨论】:
SELECT DISTINCT(req_field) AS field, COUNT(req_field) AS fieldCount FROM
table_name GROUP BY req_field HAVING fieldCount > 1
DELETE FROM table_name
USING table_name, table_name AS vtable
WHERE
(table_name.id > vtable.id)
AND (table_name.req_field=req_field)
替换 req_field 和 table_name - 应该可以正常工作。
【讨论】:
DELETE FROM table_name USING table_name AS vtable WHERE (table_name.id > vtable.id) AND (table_name.req_field=req_field)
在 MySql 中,当我放置类似
的内容时delete from A where IDA in (select IDA from A )
mySql 说了类似“你不能在删除操作的选择部分使用同一张表。”
我只需要删除一些重复的记录,并且我已经成功使用了类似的 .php 程序
<?php
...
$res = hacer_sql("SELECT MIN(IDESTUDIANTE) as IDTODELETE
FROM `estudiante` group by `LASTNAME`,`FIRSTNAME`,`CI`,`PHONE`
HAVING COUNT(*) > 1 )");
while ( $reg = mysql_fetch_assoc($res) ) {
hacer_sql("delete from estudiante where IDESTUDIANTE = {$reg['IDTODELETE']}");
}
?>
【讨论】:
这是另一个没有特定语言的想法:
rs = `select a, b, count(*) as c from entries group by 1, 2 having c > 1`
rs.each do |a, b, c|
`delete from entries where a=#{a} and b=#{b} limit #{c - 1}`
end
编辑:
感谢Olaf 的“有”提示:)
【讨论】:
如果您的表有一个 PK(或者您可以轻松地给它一个),您可以使用以下查询指定表中任意数量的列相等(限定为重复)(可能有点乱看起来但它有效):
DELETE FROM table WHERE pk_id IN(
SELECT DISTINCT t3.pk_id FROM (
SELECT t1.* FROM table AS t1 INNER JOIN (
SELECT col1, col2, col3, col4, COUNT(*) FROM table
GROUP BY col1, col2, col3, col4 HAVING COUNT(*)>1) AS t2
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2 AND t1.col3 = t2.col3 AND
t1.col4 = t2.col4)
AS t3, (
SELECT t1.* FROM table AS t1 INNER JOIN (
SELECT col1, col2, col3, col4, COUNT(*) FROM table
GROUP BY col1, col2, col3, col4 HAVING COUNT(*)>1) AS t2
ON t1.col1 = t2.col1 AND t1.col2 = t2.col2 AND t1.col3 = t2.col3 AND
t1.col4 = t2.col4)
AS t4
WHERE t3.col1 = t4.col1 AND t3.pk_id > t4.pk_id
)
这将保留输入数据库的第一条记录,删除“最新”重复项。如果要保留最后一条记录,请将 > 切换为
【讨论】:
SQL 新手 :-) 这是一个经典问题——在面试中经常被问到:-) 我不知道它是否适用于 MYSQL,但它适用于大多数数据库 -
> create table t(
> a char(2),
> b char(2),
> c smallint )
> select a,b,c,count(*) from t
> group by a,b,c
> having count(*) > 1
a b c
-- -- ------ -----------
(0 rows affected)
> insert into t values ("aa","bb",1)
(1 row affected)
> insert into t values ("aa","bb",1)
(1 row affected)
> insert into t values ("aa","bc",1)
(1 row affected)
> select a,b,c,count(*) from t group by a,b,c having count(*) > 1
a b c
-- -- ------ -----------
aa bb 1 2
(1 row affected)
【讨论】:
你可以使用:
http://lenniedevilliers.blogspot.com/2008/10/weekly-code-find-duplicates-in-sql.html
获取重复项,然后通过 Ruby 代码或 SQL 代码删除它们(我会在 SQL 代码中执行,但这取决于你 :-)
【讨论】:
好吧,如果它是一张小桌子,你可以从 rails 控制台做
class ActiveRecord::Base
def non_id_attributes
atts = self.attributes
atts.delete('id')
atts
end
end
duplicate_groups = YourClass.find(:all).group_by { |element| element.non_id_attributes }.select{ |gr| gr.last.size > 1 }
redundant_elements = duplicate_groups.map { |group| group.last - [group.last.first] }.flatten
redundant_elements.each(&:destroy)
【讨论】:
我必须do this recently on Oracle,但在 MySQL 上的步骤是相同的。这是很多数据,至少与我习惯使用的数据相比,所以我的重复数据删除过程是相对重量级的。我将其包括在此处,以防其他人遇到类似问题。
我的重复记录有不同的 ID、不同的 updated_at 次、可能不同的 updated_by ID,但所有其他列都相同。我想保留任何重复集的最新更新。
我结合使用 Rails 逻辑和 SQL 来完成它。
第一步:使用模型逻辑运行 rake 脚本来识别重复记录的 ID。 ID 保存在文本文件中。
第二步:创建一个临时表,其中包含一列、要删除的 ID,从文本文件中加载。
第三步:创建另一个临时表,其中包含我要删除的所有记录(以防万一!)。
CREATE TABLE temp_duplicate_models
AS (SELECT * FROM models
WHERE id IN (SELECT * FROM temp_duplicate_ids));
第四步:实际删除。
DELETE FROM models WHERE id IN (SELECT * FROM temp_duplicate_ids);
【讨论】:
您可以通过以下方式将不同的记录复制到新表中:
select distinct * into NewTable from MyTable
【讨论】: