Как я могу удалить дубликаты строк? - 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 ]

6 голосов
/ 01 января 2015

Если вы хотите просмотреть строки, которые вы собираетесь удалить, и сохранить контроль над тем, какие из повторяющихся строк оставить. Смотри 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
1 голос
/ 13 апреля 2017

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

    CREATE PROCEDURE sp_DeleteDuplicate @tableName varchar(100), @DebugMode int =1
AS 
BEGIN
SET NOCOUNT ON;

IF(OBJECT_ID('tempdb..#tableMatrix') is not null) DROP TABLE #tableMatrix;

SELECT ROW_NUMBER() OVER(ORDER BY name) as rn,name into #tableMatrix FROM sys.columns where [object_id] = object_id(@tableName) ORDER BY name

DECLARE @MaxRow int = (SELECT MAX(rn) from #tableMatrix)
IF(@MaxRow is null)
    RAISERROR  ('I wasn''t able to find any columns for this table!',16,1)
ELSE 
    BEGIN
DECLARE @i int =1 
DECLARE @Columns Varchar(max) ='';

WHILE (@i <= @MaxRow)
BEGIN 
    SET @Columns=@Columns+(SELECT '['+name+'],' from #tableMatrix where rn = @i)

    SET @i = @i+1;
END

---DELETE LAST comma
SET @Columns = LEFT(@Columns,LEN(@Columns)-1)

DECLARE @Sql nvarchar(max) = '
WITH cteRowsToDelte
     AS (
SELECT ROW_NUMBER() OVER (PARTITION BY '+@Columns+' ORDER BY ( SELECT 0)) as rowNumber,* FROM '+@tableName
+')

DELETE FROM cteRowsToDelte
WHERE  rowNumber > 1;
'
SET NOCOUNT OFF;
    IF(@DebugMode = 1)
       SELECT @Sql
    ELSE
       EXEC sp_executesql @Sql
    END
END

Итак, если вы создадите таблицу следующим образом:

IF(OBJECT_ID('MyLitleTable') is not null)
    DROP TABLE MyLitleTable 


CREATE TABLE MyLitleTable
(
    A Varchar(10),
    B money,
    C int
)
---------------------------------------------------------

    INSERT INTO MyLitleTable VALUES
    ('ABC',100,1),
    ('ABC',100,1), -- only this row should be deleted
    ('ABC',101,1),
    ('ABC',100,2),
    ('ABCD',100,1)

    -----------------------------------------------------------

     exec sp_DeleteDuplicate 'MyLitleTable',0

Он удалит все дубликаты из вашей таблицы. Если вы запустите его без второго параметра, он вернет оператор SQL для запуска.

Если вам нужно исключить какой-либо столбец, просто запустите его в режиме отладки, получите код и измените его по своему усмотрению.

1 голос
/ 07 июня 2016

Иногда используется механизм мягкого удаления, где записывается дата, чтобы указать удаленную дату. В этом случае оператор UPDATE может использоваться для обновления этого поля на основе повторяющихся записей.

UPDATE MY_TABLE
   SET DELETED = getDate()
 WHERE TABLE_ID IN (
    SELECT x.TABLE_ID
      FROM MY_TABLE x
      JOIN (SELECT min(TABLE_ID) id, COL_1, COL_2, COL_3
              FROM MY_TABLE d
             GROUP BY d.COL_1, d.COL_2, d.COL_3
            HAVING count(*) > 1) AS d ON d.COL_1 = x.COL_1
                                     AND d.COL_2 = x.COL_2
                                     AND d.COL_3 = x.COL_3
                                     AND d.TABLE_ID <> x.TABLE_ID
             /*WHERE x.COL_4 <> 'D' -- Additional filter*/)

Этот метод хорошо мне подошел для довольно умеренных таблиц, содержащих ~ 30 миллионов строк с большим и низким количеством дубликатов.

1 голос
/ 16 декабря 2015
alter table MyTable add sno int identity(1,1)
    delete from MyTable where sno in
    (
    select sno from (
    select *,
    RANK() OVER ( PARTITION BY RowID,Col3 ORDER BY sno DESC )rank
    From MyTable
    )T
    where rank>1
    )

    alter table MyTable 
    drop  column sno
0 голосов
/ 29 октября 2018

Если все столбцы в повторяющихся строках совпадают, то для удаления повторяющихся записей можно использовать запрос ниже.

SELECT DISTINCT * INTO #TemNewTable FROM #OriginalTable
TRUNCATE TABLE #OriginalTable
INSERT INTO #OriginalTable SELECT * FROM #TemNewTable
DROP TABLE #TemNewTable
0 голосов
/ 10 июня 2018

Я думаю, это было бы полезно. Здесь ROW_NUMBER () OVER (PARTITION BY res1.Title ORDER BY res1.Id) как num используется для различения дублирующихся строк.

delete FROM
(SELECT res1.*,ROW_NUMBER() OVER(PARTITION BY res1.Title ORDER BY res1.Id)as num
 FROM 
(select * from [dbo].[tbl_countries])as res1
)as res2
WHERE res2.num > 1
0 голосов
/ 11 января 2016

Теперь давайте посмотрим таблицу elasticalsearch, в которой в этих таблицах есть дублирующиеся строки, а Id - это идентичное поле uniq. Мы знаем, если какой-то идентификатор существует по групповым критериям, тогда мы можем удалить другие строки вне этой группы. Моя манера показывает этот критерий.

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

DELETE 
FROM elasticalsearch
WHERE Id NOT IN 
               (SELECT min(Id)
                     FROM elasticalsearch
                     GROUP BY FirmId,FilterSearchString
                     ) 

ура

...