Как удалить дубликаты строк в SQL Server?

Как я могу удалить повторяющиеся строки, где не существует unique row id?

Мой стол

col1  col2 col3 col4 col5 col6 col7
john  1    1    1    1    1    1 
john  1    1    1    1    1    1
sally 2    2    2    2    2    2
sally 2    2    2    2    2    2

Я хочу остаться со следующим после удаления дубликата:

john  1    1    1    1    1    1
sally 2    2    2    2    2    2

Я пробовал несколько запросов, но я думаю, что они зависят от наличия идентификатора строки, так как я не получаю желаемого результата. Например:

DELETE
FROM table
WHERE col1 IN (
    SELECT id
    FROM table
    GROUP BY id
    HAVING (COUNT(col1) > 1)
)

Ответ 1

Мне нравятся CTE и ROW_NUMBER как два комбинированных позволяют нам видеть, какие строки удалены (или обновлены), поэтому просто измените DELETE FROM CTE... на SELECT * FROM CTE:

WITH CTE AS(
   SELECT [col1], [col2], [col3], [col4], [col5], [col6], [col7],
       RN = ROW_NUMBER()OVER(PARTITION BY col1 ORDER BY col1)
   FROM dbo.Table1
)
DELETE FROM CTE WHERE RN > 1

DEMO (результат другой, я предполагаю, что он из-за опечатки с вашей стороны)

COL1    COL2    COL3    COL4    COL5    COL6    COL7
john    1        1       1       1       1       1
sally   2        2       2       2       2       2

Этот пример определяет дубликаты одного столбца col1 из-за PARTITION BY col1. Если вы хотите включить несколько столбцов, просто добавьте их в PARTITION BY:

ROW_NUMBER()OVER(PARTITION BY Col1, Col2, ... ORDER BY OrderColumn)

Ответ 2

Я бы предпочел CTE для удаления повторяющихся строк из таблицы sql server

настоятельно рекомендую следовать этой статье :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

сохраняя оригинальные

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

без сохранения оригинала

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)

Ответ 3

Без использования CTE и ROW_NUMBER() вы можете просто удалить записи, просто используя группу с помощью функции MAX здесь и, например,

DELETE
FROM MyDuplicateTable
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM MyDuplicateTable
GROUP BY DuplicateColumn1, DuplicateColumn2, DuplicateColumn3)

Ответ 4

DELETE from search
where id not in (
   select min(id) from search
   group by url
   having count(*)=1

   union

   SELECT min(id) FROM search
   group by url
   having count(*) > 1
)

Ответ 5

У Microsoft есть очень аккуратное руководство по удалению дубликатов. Проверьте http://support.microsoft.com/kb/139444

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

SET rowcount 1;
DELETE FROM t1 WHERE myprimarykey=1;

myprimarykey - это идентификатор строки.

Я установил rowcount в 1, потому что у меня было только две строки, которые были продублированы. Если бы у меня было 3 дублированных строки, я бы установил rowcount в 2, чтобы он удалял первые две, которые он видит, и оставлял только одну в таблице t1.

Надеюсь, это кому-нибудь поможет

Ответ 6

Пожалуйста, смотрите ниже способ удаления тоже.

Declare @table table
(col1 varchar(10),col2 int,col3 int, col4 int, col5 int, col6 int, col7 int)
Insert into @table values 
('john',1,1,1,1,1,1),
('john',1,1,1,1,1,1),
('sally',2,2,2,2,2,2),
('sally',2,2,2,2,2,2)

Создал образец таблицы с именем @table и загрузил ее с заданными данными.

enter image description here

Delete  aliasName from (
Select  *,
        ROW_NUMBER() over (Partition by col1,col2,col3,col4,col5,col6,col7 order by col1) as rowNumber
From    @table) aliasName 
Where   rowNumber > 1

Select * from @table

enter image description here

Примечание: если вы даете все столбцы в Partition by, то order by не имеет большого значения.

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

Ответ 7

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

SELECT DISTINCT [col1],[col2],[col3],[col4],[col5],[col6],[col7]

INTO [newTable]

Войдите в проводник объектов и удалите старую таблицу.

Переименуйте новую таблицу со старым именем таблицы.

Ответ 8

Попробуйте использовать:

SELECT linkorder
    ,Row_Number() OVER (
        PARTITION BY linkorder ORDER BY linkorder DESC
        ) AS RowNum
FROM u_links

enter image description here

Ответ 9

Попробовав предложенное решение выше, это работает для небольших средних таблиц. Я могу предложить это решение для очень больших таблиц. поскольку он работает в итерациях.

  1. LargeSourceTable все виды зависимостей LargeSourceTable
  2. вы можете найти зависимости, используя студию управления sql, щелкните правой кнопкой мыши по таблице и нажмите "View Dependencies",
  3. Переименуйте таблицу:
  4. sp_rename 'LargeSourceTable', 'LargeSourceTable_Temp'; GO
  5. Создайте LargeSourceTable раз, но теперь добавьте первичный ключ со всеми столбцами, которые определяют дублирование, добавьте WITH (IGNORE_DUP_KEY = ON)
  6. Например:

    CREATE TABLE [dbo].[LargeSourceTable] ( ID int IDENTITY(1,1), [CreateDate] DATETIME CONSTRAINT [DF_LargeSourceTable_CreateDate] DEFAULT (getdate()) NOT NULL, [Column1] CHAR (36) NOT NULL, [Column2] NVARCHAR (100) NOT NULL, [Column3] CHAR (36) NOT NULL, PRIMARY KEY (Column1, Column2) WITH (IGNORE_DUP_KEY = ON) ); GO

  7. Создайте снова те виды, которые вы сбросили в первую очередь для новой созданной таблицы.

  8. Теперь, запустите следующий sql-скрипт, вы увидите результаты в 1000 000 строк на странице, вы можете изменить номер строки на странице, чтобы чаще видеть результаты.

  9. Обратите внимание, что я установил IDENTITY_INSERT и выключил, потому что один из столбцов содержит автоинкрементный id, который я также копирую

SET IDENTITY_INSERT LargeSourceTable ON DECLARE @PageNumber AS INT, @RowspPage AS INT DECLARE @TotalRows AS INT declare @dt varchar(19) SET @PageNumber = 0 SET @RowspPage = 1000000 select @TotalRows = count (*) from LargeSourceTable_TEMP

While ((@PageNumber - 1) * @RowspPage < @TotalRows )
Begin
    begin transaction tran_inner
        ; with cte as
        (
            SELECT * FROM LargeSourceTable_TEMP ORDER BY ID
            OFFSET ((@PageNumber) * @RowspPage) ROWS
            FETCH NEXT @RowspPage ROWS ONLY
        )

        INSERT INTO LargeSourceTable 
        (
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        )       
        select 
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        from cte

    commit transaction tran_inner

    PRINT 'Page: ' + convert(varchar(10), @PageNumber)
    PRINT 'Transfered: ' + convert(varchar(20), @PageNumber * @RowspPage)
    PRINT 'Of: ' + convert(varchar(20), @TotalRows)

    SELECT @dt = convert(varchar(19), getdate(), 121)
    RAISERROR('Inserted on: %s', 0, 1, @dt) WITH NOWAIT
    SET @PageNumber = @PageNumber + 1
End

SET IDENTITY_INSERT LargeSourceTable OFF

Ответ 10

  • ВЫБЕРИТЕ записи DISTINCT в новую таблицу
  • ПРОВЕРИТЬ старую таблицу
  • СЛУШАЙТЕ новую таблицу обратно в старую таблицу

Ответ 11

-- this query will keep only one instance of a duplicate record.
;WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY col1, col2, col3-- based on what? --can be multiple columns
                                       ORDER BY ( SELECT 0)) RN
         FROM   Mytable)



delete  FROM cte
WHERE  RN > 1

Ответ 12

with myCTE
as

(
select productName,ROW_NUMBER() over(PARTITION BY productName order by slno) as Duplicate from productDetails
)
Delete from myCTE where Duplicate>1

Ответ 13

Что касается https://support.microsoft.com/en-us/help/139444/how-to-remove-duplicate-rows-from-a-table-in-sql-server

Идея удаления дубликата включает

  • a) Защита строк, которые не дублируются
  • b) Сохраните одну из многих строк, которые квалифицируются вместе как дубликаты.

Шаг за шагом

  • 1) Сначала определите строки, которые удовлетворяют определению дубликата и вставьте их в таблицу temp, скажем #tableAll.
  • 2) Выберите не дубликаты (однострочные) или отдельные строки в таблицу temp скажем #tableUnique.
  • 3) Удалить из исходной таблицы, соединяющей #tableAll, чтобы удалить дубликаты.
  • 4) Вставьте в исходную таблицу все строки из #tableUnique.
  • 5) Drop #tableAll и #tableUnique

Ответ 14

Если у вас есть возможность временно добавить столбец в таблицу, это было решением, которое сработало для меня:

ALTER TABLE dbo.DUPPEDTABLE ADD RowID INT NOT NULL IDENTITY(1,1)

Затем выполните DELETE, используя комбинацию MIN и GROUP BY

DELETE b
FROM dbo.DUPPEDTABLE b
WHERE b.RowID NOT IN (
                     SELECT MIN(RowID) AS RowID
                     FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
                     GROUP BY a.ITEM_NUMBER,
                              a.CHARACTERISTIC,
                              a.INTVALUE,
                              a.FLOATVALUE,
                              a.STRINGVALUE
                 );

Убедитесь, что DELETE выполнено правильно:

SELECT a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE, COUNT(*)--MIN(RowID) AS RowID
FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
GROUP BY a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE
ORDER BY COUNT(*) DESC 

В результате не должно быть строк со счетом больше 1. Наконец, удалите столбец rowid:

ALTER TABLE dbo.DUPPEDTABLE DROP COLUMN RowID;

Ответ 15

Вам нужно сгруппировать дубликаты записей в соответствии с полями, затем сохранить одну из записей и удалить остальные. Например:

DELETE prg.Person WHERE Id IN (
SELECT dublicateRow.Id FROM
(
select MIN(Id) MinId, NationalCode
 from  prg.Person group by NationalCode  having count(NationalCode ) > 1
 ) GroupSelect
 JOIN  prg.Person dublicateRow ON dublicateRow.NationalCode = GroupSelect.NationalCode 
 WHERE dublicateRow.Id <> GroupSelect.MinId)

Ответ 16

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

--REWRITING YOUR CODE(TAKE NOTE OF THE 3RD LINE) WITH CTE AS(SELECT NAME,ROW_NUMBER() 
OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB) SELECT * INTO #unique_records FROM 
CTE WHERE ID =1;

Ответ 17

Другой способ удаления дублированных строк без потери информации за один шаг выглядит следующим образом:

delete from dublicated_table t1 (nolock)
join (
    select t2.dublicated_field
    , min(len(t2.field_kept)) as min_field_kept
    from dublicated_table t2 (nolock)
    group by t2.dublicated_field having COUNT(*)>1
) t3 
on t1.dublicated_field=t3.dublicated_field 
    and len(t1.field_kept)=t3.min_field_kept

Ответ 18

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

И все, что я сделал для его работы, просто агрегировал столбец идентификаторов с помощью MAX.

DELETE FROM table WHERE col1 IN (
    SELECT MAX(id) FROM table GROUP BY id HAVING ( COUNT(col1) > 1 )
)

ПРИМЕЧАНИЕ. Возможно, вам придется запустить его несколько раз, чтобы удалить дубликат, поскольку это приведет к удалению только одного набора повторяющихся строк за раз.

Ответ 19

delete from table t1 where rowid > (SELECT min(rowid) FROM table t2 group by 
  t2.col1,t2.col2,t2.col3,t2.col4,t2.col5,t2.col6,t2.col7);

Ответ 20

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

select distinct * into #tmp From table
   delete from table
   insert into table
   select * from #tmp drop table #tmp

   select * from table

Удалите повторяющиеся строки, используя Common Table Expression (CTE)

With CTE_Duplicates as

(выберите id, name, row_number() over (разбиение по id, порядок имен по id, name) rownumber из таблицы) delete from CTE_Duplicates где rownumber! = 1

Ответ 21

DECLARE @TB TABLE(NAME VARCHAR(100));
INSERT INTO @TB VALUES ('Red'),('Red'),('Green'),('Blue'),('White'),('White')
--**Delete by Rank**
;WITH CTE AS(SELECT NAME,DENSE_RANK() OVER (PARTITION BY NAME ORDER BY NEWID()) ID FROM @TB)
DELETE FROM CTE WHERE ID>1
SELECT NAME FROM @TB;
--**Delete by Row Number** 
;WITH CTE AS(SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB)
DELETE FROM CTE WHERE ID>1;
SELECT NAME FROM @TB;

Ответ 22

     SELECT DISTINCT * FROM TABLE;

Это удалит все повторяющиеся строки и предоставит вам только отдельные значения (строки).

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

Ответ 23

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

SET rowcount n-1
DELETE FROM your_table
WHERE (spacial condition)

для получения дополнительной информации я предлагаю this