Remova linhas duplicadas no MySQL

375

Eu tenho uma tabela com os seguintes campos:

id (Unique)
url (Unique)
title
company
site_id

Agora, preciso remover as linhas que possuem o mesmo title, company and site_id. Uma maneira de fazer isso é usar o seguinte SQL junto com um script ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

Depois de executar esta consulta, posso remover duplicatas usando um script do lado do servidor.

Mas quero saber se isso pode ser feito apenas usando a consulta SQL.

Chetan
fonte
11
Pergunta rápida: você sempre quer que o duplicado (título, empresa, site_id) não exista? Nesse caso, eu configuraria uma restrição no banco de dados para aplicar título, empresa e site_id para serem únicos. O que significa que você não precisa de um processo de limpeza. E leva apenas uma única linha de SQL.
J. Polfer
11
Consulte este link do stackoverflow . Funcionou para mim como um encanto.
Posso recomendar esta solução (publicado em outro segmento): stackoverflow.com/a/4685232/195835
Simon Médio
Você também pode verificar esta resposta
Jose Rui Santos

Respostas:

607

Uma maneira realmente fácil de fazer isso é adicionar um UNIQUEíndice nas 3 colunas. Ao escrever a ALTERdeclaração, inclua a IGNOREpalavra - chave Igual a:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

Isso eliminará todas as linhas duplicadas. Como um benefício adicional, o futuro INSERTsduplicado terá erros. Como sempre, convém fazer um backup antes de executar algo assim ...

Chris Henry
fonte
8
Interessante , mas as suposições que a cláusula IGNORE faz para remover essas duplicatas é uma preocupação que pode não corresponder às necessidades. Valores incorretos sendo truncados para a correspondência aceitável mais próxima parecem bons para você?
OMG Ponies
75
Só para constar, se você estiver usando o InnoDB, pode haver um problema com ele, existe um erro conhecido sobre o uso do ALTER IGNORE TABLE com os bancos de dados do InnoDB.
DarkMantis
27
O bug acima mencionado @DarkMantis referido e sua solução .
Jordan Arseno
42
Para InnoDB mesas executar a consulta a seguir em primeiro lugar:set session old_alter_table=1;
shock_one
51
Isso não é mais suportado
Ray Baxter
180

Se você não deseja alterar as propriedades da coluna, use a consulta abaixo.

Como você possui uma coluna que possui IDs exclusivos (por exemplo, auto_incrementcolunas), é possível usá-la para remover as duplicatas:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

No MySQL, você pode simplificá-lo ainda mais com o operador igual a segurança NULL (também conhecido como "operador de nave espacial" ):

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;
repreender
fonte
3
esta solução não está funcionando corretamente, tentei fazer alguns registros duplicados e funciona algo como (20 linhas afetadas), mas se você executá-la novamente, ela será exibida (4 linhas afetadas) e assim por diante até chegar a (0 linhas afetadas) que é meio suspeito e aqui é o que funciona melhor para mim, é quase o mesmo, mas ele funciona em uma corrida, eu editei a solução
Nassim
11
@ Nassim: Você deve estar fazendo algo diferente desta resposta, porque funciona perfeitamente para mim (no MySQL).
Lawrence Dol
3
Para quem ficou confuso como eu, os termos de comparação NULL são necessários porque NULL não é igual a NULL no MySQL. Se for garantido que as colunas relevantes não sejam NULL, você poderá deixar esses termos de fora.
Ian
3
Sim, a resposta aceita não é mais válida, pois o MYSQL 5.7 deve ser realmente a resposta aceita, pois é universal e também não requer a criação temporária de tabelas.
that-ben
11
MUITO LENTO se houver MUITAS cópias de um determinado registro (por exemplo, 100 a serem reduzidas para 1) e muitos registros com essa condição. Recomende stackoverflow.com/a/4685232/199364 . IMHO, SEMPRE use a abordagem vinculada; é uma técnica inerentemente mais rápida.
Home
78

O MySQL tem restrições sobre a referência à tabela da qual você está excluindo. Você pode contornar isso com uma tabela temporária, como:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

Da sugestão de Kostanos nos comentários:
A única consulta lenta acima é DELETE, nos casos em que você possui um banco de dados muito grande. Esta consulta pode ser mais rápida:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Andomar
fonte
3
@andomar, isso funciona bem, exceto quando um dos campos na cláusula where contém nulos. Exemplo: sqlfiddle.com/#!2/983f3/1
um codificador
11
O Insert SQL é caro? Eu estou querendo saber, porque expira no meu banco de dados MySQL.
Cassio
4
A única consulta lenta aqui é a DELETE, caso você tenha um grande banco de dados. Esta consulta pode ser mais rápida:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
Kostanos
@ Kostanos Não apenas DELETE, mas também INSERTpara a mesa temporária, demorei muito tempo. Portanto, um índice para a tabela tmp poderia ajudar muito create index tmpTable_id_index on tmpTable (id), pelo menos para mim.
precisa saber é o seguinte
11
Se suas tabelas são grandes, vale a pena adicionar um índice com: -create temporary table tmpTable (id int, PRIMARY KEY (id));
Dallas Clarke
44

Se a IGNOREdeclaração não funcionar como no meu caso, você pode usar a declaração abaixo:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;
Kamil
fonte
11
funciona muito bem se você tiver a configuração do innoDB com restrição de chave estrangeira.
precisa saber é
@magdmartin, mas restrições estrangeiras não impedirão a exclusão da tabela?
Basilevs 16/09
11
A declaração IGNORE não funcionou para mim e isso funcionou muito bem na dedução de 5 milhões de registros. Felicidades.
Mauvis Ledford
32

A exclusão de duplicatas nas tabelas MySQL é um problema comum, geralmente o resultado de uma restrição ausente para evitar essas duplicatas com antecedência. Mas esse problema comum geralmente vem com necessidades específicas ... que exigem abordagens específicas. A abordagem deve ser diferente, dependendo, por exemplo, do tamanho dos dados, da entrada duplicada que deve ser mantida (geralmente a primeira ou a última), se existem índices a serem mantidos ou se queremos executar qualquer ação adicional. ação nos dados duplicados.

Também existem algumas especificidades no próprio MySQL, como não poder referenciar a mesma tabela em uma causa FROM ao executar uma tabela UPDATE (isso gerará o erro do MySQL # 1093). Essa limitação pode ser superada usando uma consulta interna com uma tabela temporária (conforme sugerido em algumas abordagens acima). Mas essa consulta interna não terá um desempenho especialmente bom ao lidar com fontes de big data.

No entanto, existe uma abordagem melhor para remover duplicatas, eficiente e confiável, e que pode ser facilmente adaptada a diferentes necessidades.

A idéia geral é criar uma nova tabela temporária, geralmente adicionando uma restrição exclusiva para evitar duplicatas adicionais e INSERIR os dados da tabela anterior na nova, enquanto cuida das duplicatas. Essa abordagem baseia-se em consultas simples do MySQL INSERT, cria uma nova restrição para evitar duplicatas adicionais e ignora a necessidade de usar uma consulta interna para procurar duplicatas e uma tabela temporária que deve ser mantida na memória (ajustando também fontes de big data).

É assim que isso pode ser alcançado. Dado que temos um funcionário da tabela , com as seguintes colunas:

employee (id, first_name, last_name, start_date, ssn)

Para excluir as linhas com uma coluna ssn duplicada e mantendo apenas a primeira entrada encontrada, o seguinte processo pode ser seguido:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

Explicação técnica

  • A linha 1 cria uma nova tabela tmp_eployee com exatamente a mesma estrutura que a tabela employee
  • A linha 2 adiciona uma restrição UNIQUE à nova tabela tmp_eployee para evitar outras duplicatas
  • A linha 3 varre a tabela original do funcionário por ID, inserindo novas entradas de funcionários na nova tabela tmp_eployee , ignorando as entradas duplicadas
  • A linha 4 renomeia as tabelas, para que a nova tabela de funcionários mantenha todas as entradas sem as duplicatas e uma cópia de backup dos dados anteriores seja mantida na tabela backup_employee

Usando essa abordagem, 1,6 milhões de registros foram convertidos em 6k em menos de 200s.

Chetan , seguindo esse processo, você pode remover rápida e facilmente todas as suas duplicatas e criar uma restrição ÚNICA executando:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

Obviamente, esse processo pode ser modificado ainda mais para adaptá-lo a diferentes necessidades ao excluir duplicatas. Alguns exemplos a seguir.

✔ Variação para manter a última entrada em vez da primeira

Às vezes, precisamos manter a última entrada duplicada em vez da primeira.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Na linha 3, a cláusula ORDER BY id DESC faz com que os últimos IDs tenham prioridade sobre o restante

✔ Variação para executar algumas tarefas nas duplicatas, por exemplo, mantendo uma contagem nas duplicatas encontradas

Às vezes, precisamos executar algum processamento adicional nas entradas duplicadas encontradas (como manter uma contagem das duplicatas).

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Na linha 3, uma nova coluna n_duplicates é criada
  • Na linha 4, a consulta INSERT INTO ... ON DUPLICATE KEY UPDATE é usada para executar uma atualização adicional quando uma duplicata é encontrada (neste caso, aumentando um contador) A consulta INSERT INTO ... ON DUPLICATE KEY UPDATE pode ser usado para executar diferentes tipos de atualizações para as duplicatas encontradas.

✔ Variação para regenerar o ID do campo auto-incremental

Às vezes, usamos um campo de incremento automático e, para manter o índice o mais compacto possível, podemos aproveitar a exclusão das duplicatas para gerar novamente o campo de incremento automático na nova tabela temporária.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • Na linha # 3, em vez de selecionar todos os campos da tabela, o campo de identificação é ignorado para que o mecanismo do banco de dados gere um novo automaticamente

✔ Outras variações

Muitas modificações adicionais também são possíveis, dependendo do comportamento desejado. Como exemplo, as consultas a seguir usarão uma segunda tabela temporária para, além de 1) manter a última entrada em vez da primeira; e 2) aumentar um contador nas duplicatas encontradas; também 3) regenere o ID do campo auto-incremental, mantendo a ordem de entrada como estava nos dados anteriores.

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;
César Revert-Gomar
fonte
27

Existe outra solução:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...
Mostafa -T
fonte
4
Como isso difere da resposta de @ rehriff, que ele enviou seis meses antes?
Lawrence Dol
@LawrenceDol Eu acho que é um pouco mais legível e também acho que a resposta dele não era a mesma no momento em que respondi e acho que a resposta foi editada.
Mostafa -T
11
Hmm. Leva muito tempo para mim, enquanto o número de registros não era grande!
SuB
8

se você tiver uma tabela grande com um grande número de registros, as soluções acima não funcionarão ou levarão muito tempo. Então nós temos uma solução diferente

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;
faisalbhagat
fonte
6

Eu tenho esse snipet de consulta para SQLServer, mas acho que ele pode ser usado em outros DBMS com pequenas alterações:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

Esqueci de lhe dizer que esta consulta não remove a linha com o ID mais baixo das linhas duplicadas. Se isso funcionar para você, tente esta consulta:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)
Eduardo Rascon
fonte
Isso não funcionará se houver mais de duas duplicatas de um grupo.
OMG Ponies
11
Infelizmente, o MySQL não permite que você selecione da tabela que você está excluindo #ERROR 1093: You can't specify target table 'Table' for update in FROM clause
Andomar
11
Para resolver o "You can't specify target table 'Table' for update in FROM..."erro, use: o DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)que força o MySQL a criar uma tabela temporalmente. No entanto, é muito lento em grandes conjuntos de dados ... nesses casos, vou recomendar o código do Andomar, que é muito mais rápido.
Lepe
6

A maneira mais rápida é inserir linhas distintas em uma tabela temporária. Usando delete, levei algumas horas para remover duplicatas de uma tabela de 8 milhões de linhas. Usando insert e distinto, levou apenas 13 minutos.

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  
Nav
fonte
11
Sua linha 4 deveria dizer TRUNCATE TABLE tableNamee 5ª linha deve dizerINSERT INTO tableName SELECT * FROM tempTableName;
Sana
5

Uma solução que é simples de entender e funciona sem chave primária:

1) adicione uma nova coluna booleana

alter table mytable add tokeep boolean;

2) adicione uma restrição nas colunas duplicadas E na nova coluna

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) defina a coluna booleana como true. Isso terá êxito apenas em uma das linhas duplicadas devido à nova restrição

update ignore mytable set tokeep = true;

4) excluir linhas que não foram marcadas como manutenção

delete from mytable where tokeep is null;

5) solte a coluna adicionada

alter table mytable drop tokeep;

Sugiro que você mantenha a restrição adicionada, para evitar novas duplicatas no futuro.

xtian
fonte
11
Isso funcionou muito bem no mysql 5.7where aceita solução trabalho does not mais
Robin31
5

Excluir linhas duplicadas usando a instrução DELETE JOIN O MySQL fornece a instrução DELETE JOIN que você pode usar para remover rapidamente linhas duplicadas.

A instrução a seguir exclui linhas duplicadas e mantém o ID mais alto:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;
Saad Mirza
fonte
5

Eu encontrei uma maneira simples. (mantenha o mais recente)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;
Rico Nguyen
fonte
4

Simples e rápido para todos os casos:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);
artemiuz
fonte
Código de erro: 1055. A expressão nº 2 da lista SELECT não está na cláusula GROUP BY e contém a coluna não agregada 'dub.id', que não depende funcionalmente das colunas na cláusula GROUP BY; esta é incompatível com sql_mode = ONLY_FULL_GROUP_BY
Swoogan
você pode desativar o "controle rígido" com sql_mode, consulte stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz
4

Isso excluirá as linhas duplicadas com os mesmos valores para título, empresa e site. A primeira ocorrência será mantida e o restante de todas as duplicatas serão excluídas

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;
Dhrumil Panchal
fonte
é lento (5w + linhas, tempo de espera de bloqueio), mas funcionou
yurenchen 16/04
3

Eu continuo visitando esta página sempre que eu google "remover duplicados do formulário mysql", mas para minhas soluções theIGNORE não funcionam porque eu tenho uma tabela mysql do InnoDB

esse código funciona melhor a qualquer momento

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = o nome da tabela que você precisa limpar

tableToclean_temp = uma tabela temporária criada e excluída

Francesco
fonte
2

Essa solução moverá as duplicatas para uma tabela e os únicos para outra .

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs
Anthony Vipond
fonte
Por que você tomou a união e não apenas SELECT * FROM jobs GROUP BY site_id, company, title, location?
timctran
2

A partir da versão 8.0 (2018), o MySQL finalmente suporta funções de janela .

As funções da janela são práticas e eficientes. Aqui está uma solução que demonstra como usá-los para resolver essa tarefa.

Em uma subconsulta, podemos usar ROW_NUMBER()para atribuir uma posição a cada registro na tabela dentro de column1/column2grupos, ordenados por id. Se não houver duplicatas, o registro obterá o número da linha 1. Se existir duplicado, eles serão numerados por ascensão id(começando em 1).

Depois que os registros são numerados corretamente na subconsulta, a consulta externa exclui todos os registros cujo número da linha não é 1.

Inquerir :

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)
GMB
fonte
1

Para excluir o registro duplicado em uma tabela.

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

ou

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);
Arun Salomão
fonte
1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;
Duy Hoang
fonte
0

Para duplicar registros com colunas exclusivas, por exemplo, COL1, COL2, COL3 não devem ser replicados (suponha que tenhamos perdido três colunas exclusivas na estrutura da tabela e que várias entradas duplicadas tenham sido feitas na tabela)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

A esperança ajudará o desenvolvedor.

Abdul Rehman
fonte
0

TL; TR;

Um tutorial muito descrito para solucionar esse problema pode ser encontrado no site mysqltutorial.org :

Como excluir linhas duplicadas no MySQL

É mostrado claramente como excluir linhas duplicadas de três maneiras diferentes :

A) Usando DELETE JOINdeclaração

B) Usando uma tabela intermediária

C) Usando a ROW_NUMBER()função

Espero que ajude alguém.

simhumileco
fonte
0

Eu tenho uma tabela que se esqueça de adicionar uma chave primária na linha de identificação. Embora seja, tem auto_increment no id. Mas um dia, algumas coisas repetem o log do mysql bin no banco de dados, que insere algumas linhas duplicadas.

Eu removo a linha duplicada por

  1. selecione as linhas duplicadas exclusivas e exporte-as

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;

  1. exclua as linhas duplicadas por id

  2. insira a linha dos dados exportados.

  3. Em seguida, adicione a chave primária no id

Kris Roofe
fonte
-2

Eu gosto de ser um pouco mais específico sobre quais registros excluo, então aqui está minha solução:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)
Michael Tel
fonte
-4

Você pode excluir facilmente os registros duplicados desse código.

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}
Syed Amir Bukhari
fonte
3
Isso é péssimo - as tarefas do banco de dados devem ser feitas no banco de dados, onde são muito mais rápidas, em vez de enviar dados constantemente entre o php / mysql, porque você conhece um melhor que o outro.
Max
-4

Eu tive que fazer isso com campos de texto e me deparei com o limite de 100 bytes no índice.

Resolvi isso adicionando uma coluna, fazendo um hash md5 dos campos e fazendo o alter.

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
Sunil
fonte