Como posso remover linhas duplicadas?

1285

Qual é a melhor maneira de remover linhas duplicadas de uma SQL Servertabela bastante grande (ou seja, mais de 300.000 linhas)?

As linhas, é claro, não serão duplicatas perfeitas devido à existência do RowIDcampo de identidade.

Minha mesa

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
Seibar
fonte
13
Dica rápida para usuários do PostgreSQL que leem isso (lotes, dependendo da frequência com que está vinculado): Pg não expõe os termos CTE como visualizações atualizáveis, portanto você não pode DELETE FROMusá-lo diretamente. Veja stackoverflow.com/q/18439054/398670
Craig Ringer
@CraigRinger, o mesmo vale para a Sybase - eu coletei as soluções restantes aqui (também devem ser válidas para PG e outras: stackoverflow.com/q/19544489/1855801 (substitua a ROWID()função pela coluna RowID, se houver)
maf-soft
12
Apenas para adicionar uma ressalva aqui. Ao executar qualquer processo de deduplicação, verifique sempre o que você está excluindo primeiro! Essa é uma daquelas áreas em que é muito comum excluir acidentalmente bons dados.
Jeff Davis

Respostas:

1142

Assumindo que não há nulos, GROUP BYas colunas exclusivas e SELECTo MIN (or MAX)RowId são a linha a ser mantida. Em seguida, exclua tudo o que não tinha um ID de linha:

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

Caso você tenha um GUID em vez de um número inteiro, poderá substituir

MIN(RowId)

com

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))
Mark Brackett
fonte
327
Isso funcionaria também? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly 23/09/10
10
@Andriy - No SQL Server LEFT JOINé menos eficiente que NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/... O mesmo site também compara NOT INvs NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in Fora dos 3, acho que tem o NOT EXISTSmelhor desempenho. Todos os três irão gerar um plano com uma associação automática, embora isso possa ser evitado.
Martin Smith
12
@ Martin, @ Georg: Então, eu fiz um pequeno teste. Uma tabela grande foi criada e preenchida conforme descrito aqui: sqlinthewild.co.za/index.php/2010/03/23/… Dois SELECTs foram produzidos, um usando a técnica LEFT JOIN + WHERE IS NULL, o outro usando o NOT Em um. Então eu continuei com os planos de execução, e adivinhem? Os custos de consulta foram de 18% para LEFT JOIN contra 82% para NOT IN, uma grande surpresa para mim. Eu poderia ter feito algo que não deveria ou vice-versa, o que, se for verdade, eu realmente gostaria de saber.
precisa
16
@ GeorgSchölly forneceu uma resposta elegante. Eu o usei em uma tabela em que um erro meu do PHP criou linhas duplicadas.
Philip Kearns
12
Desculpe, mas por que DELETE MyTable FROM MyTablea sintaxe correta? Não vejo como colocar o nome da tabela logo após a DELETEopção como na documentação aqui . Desculpe se isso é óbvio para os outros; Eu sou um novato no SQL apenas tentando aprender. Mais importante do que por que funciona: qual é a diferença entre incluir o nome da tabela ou não?
levininja
760

Outra maneira possível de fazer isso é

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

Estou usando ORDER BY (SELECT 0)acima, pois é arbitrário qual linha preservar em caso de empate.

Para preservar o mais recente RowID, por exemplo, você pode usarORDER BY RowID DESC

Planos de Execução

O plano de execução para isso geralmente é mais simples e mais eficiente do que o da resposta aceita, pois não requer a auto-junção.

Planos de Execução

Nem sempre é esse o caso. Um local em que a GROUP BYsolução pode ser preferida são as situações em que um agregado de hash seria escolhido em preferência a um agregado de fluxo.

A ROW_NUMBERsolução sempre dará praticamente o mesmo plano, enquanto a GROUP BYestratégia é mais flexível.

Planos de Execução

Fatores que podem favorecer a abordagem agregada de hash seriam

  • Nenhum índice útil nas colunas de particionamento
  • relativamente poucos grupos com relativamente mais duplicatas em cada grupo

Nas versões extremas desse segundo caso (se houver muito poucos grupos com muitas duplicatas em cada um), também seria possível inserir simplesmente as linhas para manter em uma nova tabela e, em seguida, inserir TRUNCATEo original e copiá-las para minimizar o registro em comparação com a exclusão de um proporção muito alta das linhas.

Martin Smith
fonte
28
Se posso acrescentar: A resposta aceita não funciona com tabelas que usam uniqueidentifier. Este é muito mais simples e funciona perfeitamente em qualquer mesa. Obrigado Martin.
BrunoLM
15
Esta é uma resposta incrível! Funcionou o evento quando eu removi o PK antigo antes de perceber onde havia duplicatas. +100
Mikael Eliasson
12
Sugiro perguntar e responder a essa pergunta (com esta resposta) no DBA.SE. Em seguida, podemos adicioná-lo à nossa lista de respostas canônicas .
precisa
16
Diferentemente da resposta aceita, isso também funcionava em uma tabela que não tinha chave ( RowId) para comparar.
precisa saber é o seguinte
8
Este não funciona em todas as versões do servidor SQL, por outro lado
David
150

Há um bom artigo sobre como remover duplicatas no site de suporte da Microsoft. É bastante conservador - eles fazem tudo em etapas separadas - mas devem funcionar bem em grandes mesas.

Eu usei auto-junções para fazer isso no passado, embora provavelmente possa ser usado com uma cláusula HAVING:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField
Jon Galloway
fonte
perfeito! Descobri que esta é a maneira mais eficiente de remover linhas duplicadas na minha versão antiga do mariadb 10.1.xx. obrigado!
Drunken M
Muito mais simples e fácil de entender!
Marc
98

A consulta a seguir é útil para excluir linhas duplicadas. A tabela neste exemplo tem IDcomo coluna de identidade e as colunas com dados duplicados são Column1, Column2e Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

A seguir mostra de script uso GROUP BY, HAVING, ORDER BYem uma consulta, e retorna os resultados com coluna duplicado e sua contagem.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 
gngolakia
fonte
1
Erro MySQL com o primeiro script 'Você não pode especificar a tabela de destino 'TableName' para atualização na cláusula FROM'
D.Rosado
Além do erro que D.Rosado já relatou, sua primeira consulta também é muito lenta. A consulta SELECT correspondente demorou em minha configuração + - 20 vezes mais que a resposta aceita.
parvus
8
@parvus - A pergunta está marcada como SQL Server e não MySQL. A sintaxe está correta no SQL Server. Além disso, o MySQL é notoriamente ruim em otimizar subconsultas, veja por exemplo aqui . Esta resposta está correta no SQL Server. De fato, NOT INmuitas vezes tem um desempenho melhor que OUTER JOIN ... NULL. Eu gostaria de acrescentar um HAVING MAX(ID) IS NOT NULLpara a consulta que embora semanticamente não deve ser necessário como que pode melhorar o plano exemplo de que aqui
Martin Smith
2
Funciona muito bem no PostgreSQL 8.4.
nortalmente
63
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid
SoftwareGeek
fonte
Por que postar uma solução do Postgres em uma pergunta do SQL Server?
precisa saber é o seguinte
2
@Lankymart Porque os usuários do postgres também estão vindo para cá. Veja a pontuação desta resposta.
Gabriel
2
Eu já vi isso em algumas perguntas populares sobre SQL, como aqui , aqui e aqui . O OP recebeu sua resposta e todo mundo também recebeu ajuda. Não há problema IMHO.
Gabriel
44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 
Jithin Shaji
fonte
1
Recebo esta mensagem no SQL DW azul do Azure: atualmente, uma cláusula FROM não é suportada em uma instrução DELETE.
Amit
40

Isso excluirá linhas duplicadas, exceto a primeira linha

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

Consulte ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )

Syed Mohamed
fonte
10
Para o mysql, ocorrerá um erro: Código do erro: 1093. Você não pode especificar a tabela de destino 'Mytable' para atualização na cláusula FROM. mas esta pequena alteração funcionará para o mysql: DELETE FROM Mytable WHERE RowID NOT IN (SELECT ID FROM (SELECT MIN (RowID) como ID FROM Mytable GROUP BY Col1, Col2, Col3) AS TEMP)
Ritesh
35

Eu preferiria o CTE para excluir linhas duplicadas da tabela do servidor sql

é altamente recomendável seguir este artigo :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

mantendo original

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

sem manter o original

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)
Shamseer K
fonte
24

Para buscar linhas duplicadas:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

Para excluir as linhas duplicadas:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      
Shaini Sinha
fonte
Para usuários do MySQL, observe que, em primeiro lugar, tem que ser DELETE FROM, em segundo lugar, não funcionará, porque você não pode SELECTda mesma tabela da qual você é DELETE. No MySQL, isso dispara MySQL error 1093.
Íhor Mé 9/08/19
23

Rápido e Sujo para excluir linhas duplicadas exatas (para tabelas pequenas):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;
JuanJo
fonte
3
Observe que a pergunta realmente especifica duplicação não exata (id da linha do dueto).
Dennis Jaheruddin
21

Prefiro a subconsulta \ tendo a solução count (*)> 1 à junção interna porque achei mais fácil ler e foi muito fácil transformar uma instrução SELECT para verificar o que seria excluído antes da execução.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)
James Errico
fonte
Não exclui todos os registros que aparecem na consulta interna. Precisamos remover apenas duplicatas e preservar o original.
Sandy
3
Você está retornando apenas aquele com o ID mais baixo, com base no min (ID) na cláusula de seleção.
James Errico
2
Remova o comentário da primeira, segunda e última linhas da consulta.
James Errico
7
Isso não limpará todas as duplicatas. Se você tiver três linhas duplicadas, ela somente selecionará a linha com o MIN (id) e excluirá aquela, deixando duas linhas restantes duplicadas.
Chloe
2
No entanto, acabei usando essa declaração repetidas vezes sem conta, para que realmente fizesse progresso em vez de o tempo limite da conexão expirar ou o computador entrar no modo de suspensão. Eu mudei MAX(id)para eliminar as últimas duplicatas e adicionei LIMIT 1000000à consulta interna para que não fosse necessário verificar a tabela inteira. Isso mostrou um progresso muito mais rápido do que as outras respostas, que pareceriam travar por horas. Depois que a tabela foi removida para um tamanho gerenciável, você poderá concluir as outras consultas. Dica: verifique se col1 / col2 / col3 possui índices para agrupar por.
Chloe
17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable
heta77
fonte
5
Truncar não funcionará se você tiver referências de chave estrangeira ao myTable.
Sameer Alibhai
15

Eu pensei em compartilhar minha solução, pois ela funciona em circunstâncias especiais. No meu caso, a tabela com valores duplicados não tinha uma chave estrangeira (porque os valores foram duplicados de outro banco de dados).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

PS: ao trabalhar em coisas como essa, eu sempre uso uma transação, isso não apenas garante que tudo seja executado como um todo, mas também me permite testar sem arriscar nada. Mas é claro que você deve fazer um backup de qualquer maneira apenas para ter certeza ...

Ruben Verschueren
fonte
14

Esta consulta mostrou um desempenho muito bom para mim:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

excluiu 1 milhão de linhas em pouco mais de 30 segundos de uma tabela de 2 milhões (50% de duplicatas)

Draško
fonte
14

Usando CTE. A idéia é ingressar em uma ou mais colunas que formam um registro duplicado e remover o que você quiser:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;
Ostati
fonte
1
Eu acho que você está faltando um AND em seu JOIN.
Justin R.
13

Ainda outra solução fácil pode ser encontrada no link colado aqui . Este é fácil de entender e parece ser eficaz para a maioria dos problemas semelhantes. É para o SQL Server, mas o conceito usado é mais do que aceitável.

Aqui estão as partes relevantes da página vinculada:

Considere estes dados:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

Então, como podemos excluir esses dados duplicados?

Primeiro, insira uma coluna de identidade nessa tabela usando o seguinte código:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

Use o seguinte código para resolvê-lo:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 
Nitish Pareek
fonte
1
"Fácil de entender", "parece ser eficaz", mas nem uma palavra sobre o que o método consiste. Imagine que o link se torna inválido, qual seria a utilidade de saber que o método era fácil de entender e eficaz? Considere adicionar partes essenciais da descrição do método em sua postagem, caso contrário, isso não é uma resposta.
Andriy M
Este método é útil para tabelas em que você ainda não tem uma identidade definida. Muitas vezes, você precisa se livrar das duplicatas para definir a chave primária!
Jeff Davis
@JeffDavis - A ROW_NUMBERversão funciona bem para esse caso, sem a necessidade de adicionar uma nova coluna antes de começar.
Martin Smith
12

Aqui está outro bom artigo sobre como remover duplicatas .

Ele discute por que é difícil: "O SQL é baseado em álgebra relacional e duplicatas não podem ocorrer na álgebra relacional, porque duplicatas não são permitidas em um conjunto " .

A solução da tabela temporária e dois exemplos de mysql.

No futuro, você evitará isso no nível do banco de dados ou da perspectiva do aplicativo. Eu sugeriria o nível do banco de dados porque seu banco de dados deve ser responsável por manter a integridade referencial; os desenvolvedores apenas causarão problemas;)

Craig
fonte
1
O SQL é baseado em vários conjuntos. Mas mesmo que fosse baseado em conjuntos, essas duas tuplas (1, a) e (2, a) são diferentes.
18711 Andrew
12

Ah com certeza. Use uma tabela temporária. Se você deseja uma declaração única e de baixo desempenho que "funcione", você pode:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

Basicamente, para cada linha da tabela, a sub-seleção localiza o RowID superior de todas as linhas exatamente iguais à linha em consideração. Então você acaba com uma lista de RowIDs que representam as linhas não duplicadas "originais".

Jacob Proffitt
fonte
11

Eu tinha uma tabela em que precisava preservar linhas não duplicadas. Não tenho certeza da velocidade ou eficiência.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )
chrismar035
fonte
7
Isso pressupõe que haja no máximo 1 duplicado.
Martin Smith
Por que não HAVING COUNT(*) > 1?
Philipp M
11

Usa isto

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1
Haris
fonte
10

A outra maneira é criar uma nova tabela com os mesmos campos e com índice exclusivo . Em seguida, mova todos os dados da tabela antiga para a nova tabela . Automaticamente, o SQL SERVER ignora (há também uma opção sobre o que fazer se houver um valor duplicado: ignorar, interromper ou sth) valores duplicados. Portanto, temos a mesma tabela sem linhas duplicadas. Se você não deseja um Índice Único, após a transferência dos dados, você pode soltá-lo .

Especialmente para tabelas maiores, você pode usar o DTS (pacote SSIS para importar / exportar dados) para transferir todos os dados rapidamente para sua nova tabela indexada exclusivamente. Para 7 milhões de linhas, leva apenas alguns minutos.

İsmail Yavuz
fonte
9

Usando a consulta abaixo, podemos excluir registros duplicados com base na coluna única ou na coluna múltipla. a consulta abaixo é excluída com base em duas colunas. o nome da tabela é: testinge os nomes das colunasempno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
Sudhakar NV
fonte
9
  1. Criar nova tabela em branco com a mesma estrutura

  2. Executar consulta como esta

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Em seguida, execute esta consulta

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1
shA.t
fonte
9

Esta é a maneira mais fácil de excluir registros duplicados

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105

Harikesh Yadav
fonte
Por que alguém está votando nisso? Se você tiver mais de dois da mesma identificação, isso NÃO funcionará. Em vez disso escrever: delete from tblemp onde id não in (select min (id) do grupo tblemp por título)
crellee
7

Eu mencionaria essa abordagem da melhor maneira possível e funciona em todos os servidores SQL: Muitas vezes, há apenas uma - duas duplicatas, e os IDs e a contagem de duplicatas são conhecidos. Nesse caso:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0
Evgueny Sedov
fonte
7

Do nível do aplicativo (infelizmente). Concordo que a maneira correta de impedir a duplicação é no nível do banco de dados através do uso de um índice exclusivo, mas no SQL Server 2005, um índice tem permissão para ter apenas 900 bytes, e meu campo varchar (2048) deixa isso de lado.

Não sei como seria o desempenho, mas acho que você poderia escrever um gatilho para impor isso, mesmo que não pudesse fazê-lo diretamente com um índice. Algo como:

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

Além disso, varchar (2048) me parece suspeito (algumas coisas na vida são 2048 bytes, mas é bastante incomum); realmente não deveria ser varchar (max)?

DrPizza
fonte
7

Outra maneira de fazer isso: -

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 
yuvi
fonte
O que há de diferente nesta resposta existente em 20 de agosto de 2008? - stackoverflow.com/a/18934/692942
Lankymart
7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );
Teena
fonte
Olá, Teena, você perdeu a tabela Alice name T1 após o comentário de exclusão, caso contrário, ocorrerá uma exceção de sintaxe.
Nagaraj M
6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)
AnandPhadke
fonte
6

Você deseja visualizar as linhas que está prestes a remover e manter o controle sobre quais linhas duplicadas devem ser mantidas. Consulte http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1
Lauri Lubi
fonte