Как я могу удалить дубликаты строк? - PullRequest
1221 голосов
/ 21 августа 2008

Каков наилучший способ удаления повторяющихся строк из довольно большой таблицы SQL Server (т.е. 300 000+ строк)?

Строки, конечно, не будут идеальными дубликатами из-за существования поля идентификации RowID.

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

Ответы [ 37 ]

19 голосов
/ 29 декабря 2016

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

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

Чтобы удалить дубликаты строк:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      
16 голосов
/ 10 октября 2012
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable
14 голосов
/ 27 января 2014

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

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: при работе над такими вещами я всегда использую транзакцию, это не только гарантирует, что все выполняется в целом, но и позволяет мне тестировать, не рискуя чем-либо. Но, конечно, вы все равно должны сделать резервную копию, чтобы быть уверенным ...

14 голосов
/ 13 ноября 2014

Использование CTE. Идея состоит в том, чтобы объединить один или несколько столбцов, которые образуют дублирующуюся запись, а затем удалить то, что вам нравится:

;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;
13 голосов
/ 06 августа 2013

Еще одно простое решение можно найти по ссылке, вставленной здесь . Это легко понять и кажется эффективным для большинства подобных проблем. Это только для SQL Server, но используемая концепция более чем приемлема.

Вот соответствующие части со связанной страницы:

Рассмотрим эти данные:

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

Итак, как мы можем удалить эти дубликаты данных?

Сначала вставьте столбец идентификаторов в эту таблицу, используя следующий код:

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

Используйте следующий код для его разрешения:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 
13 голосов
/ 10 декабря 2014

Этот запрос показал очень хорошую производительность для меня:

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

он удалил 1M строк за чуть более 30 секунд из таблицы 2M (50% дубликатов)

12 голосов
/ 21 августа 2008

Вот еще одна хорошая статья о удалении дубликатов .

Здесь объясняется, почему его сложно: " SQL основан на реляционной алгебре, и дубликаты не могут встречаться в реляционной алгебре, поскольку дубликаты не допускаются в наборе. "

Решение временной таблицы и два примера mysql.

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

12 голосов
/ 21 августа 2008

О, конечно. Используйте временную таблицу. Если вам нужен один, не очень производительный оператор, который «работает», вы можете использовать:

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)

По сути, для каждой строки в таблице подвыбор находит верхний RowID всех строк, которые в точности соответствуют рассматриваемой строке. Таким образом, вы получите список RowID, которые представляют «оригинальные» недублированные строки.

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

У меня была таблица, где мне нужно было сохранить неповторяющиеся строки. Я не уверен в скорости или эффективности.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )
10 голосов
/ 18 сентября 2013

Другой способ - Создать новую таблицу с теми же полями и с уникальным индексом . Затем переместить все данные из старой таблицы в новую таблицу . Автоматически SQL SERVER игнорирует (есть также вариант, что делать, если будет повторяющееся значение: игнорировать, прерывать или sth) повторяющихся значений. Итак, у нас одна и та же таблица без повторяющихся строк. Если вам не нужен уникальный индекс, после передачи данных вы можете удалить его .

Особенно для больших таблиц вы можете использовать DTS (пакет SSIS для импорта / экспорта данных), чтобы быстро перенести все данные в вашу новую уникально проиндексированную таблицу. Для 7 миллионов подряд это займет всего несколько минут.

...