Как удалить дубликаты записей в базе данных MySQL? - PullRequest
13 голосов
/ 18 марта 2009

Каков наилучший способ удаления повторяющихся записей в базе данных mysql с использованием rails или запросов mysql?

Ответы [ 15 ]

10 голосов
/ 18 марта 2009

Что вы можете сделать, это скопировать отдельные записи в новую таблицу:

 select distinct * into NewTable from MyTable
8 голосов
/ 16 июня 2010

Вот еще одна идея без какого-либо конкретного языка:

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

Edit:

Слава Олаф за этот "имеющий" намек:)

7 голосов
/ 16 сентября 2011

Проверка на наличие повторяющихся записей:

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 - должно работать без проблем.

7 голосов
/ 19 марта 2009

ну, если это маленький стол, из консоли 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)
4 голосов
/ 18 марта 2009

плохо знаком с 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)
1 голос
/ 14 апреля 2011

предположим, что у нас есть имя таблицы 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;

после этого мы видим, что все дубликаты в поле удалены

1 голос
/ 13 октября 2010

Если у вас есть PK (id) в таблице (EMP) и вы хотите удалить старые записи с именем столбца более старых. Для больших данных может подойти следующий запрос.

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;
0 голосов
/ 21 сентября 2015

Во-первых, делайте группу за столбцом, для которого вы хотите удалить дубликаты. Но я не делаю это с группой по. Я пишу самостоятельное соединение.

Вам не нужно создавать временную таблицу.

Удалить дубликаты, кроме одной записи: В этой таблице должен быть столбец автоинкремента. Возможное решение, с которым я только что столкнулся:

DELETE n1 FROM names n1, names n2 WHERE n1.id > n2.id AND n1.name = n2.name

, если вы хотите сохранить строку с наименьшим значением идентификатора автоинкремента ИЛИ

DELETE n1 FROM names n1, names n2 WHERE n1.id < n2.id AND n1.name = n2.name

, если вы хотите сохранить в строке самое высокое значение идентификатора автоматического приращения.

Вы можете перепроверить ваше решение, снова найти дубликат:

SELECT * FROM `names` GROUP BY name, id having count(name) > 1;

Если возвращается 0 результатов, значит, ваш запрос выполнен успешно.

0 голосов
/ 17 апреля 2015

Вот решение рельсов, которое я придумал. Может быть не самым эффективным, но не имеет большого значения, если его перенос один раз.

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, но вы можете иметь больше или меньше

Во-вторых, выбирает инверсию этой группы ... все остальные записи

В-третьих, удаляет все эти записи.

0 голосов
/ 11 декабря 2012

Я использовал ответ @ 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...