Как удалить дубликаты строк в 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
Попробовав предложенное решение выше, это работает для небольших средних таблиц. Я могу предложить это решение для очень больших таблиц. поскольку он работает в итерациях.
-
LargeSourceTable
все виды зависимостей LargeSourceTable
- вы можете найти зависимости, используя студию управления sql, щелкните правой кнопкой мыши по таблице и нажмите "View Dependencies",
- Переименуйте таблицу:
-
sp_rename 'LargeSourceTable', 'LargeSourceTable_Temp'; GO
- Создайте
LargeSourceTable
раз, но теперь добавьте первичный ключ со всеми столбцами, которые определяют дублирование, добавьте WITH (IGNORE_DUP_KEY = ON)
-
Например:
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
-
Создайте снова те виды, которые вы сбросили в первую очередь для новой созданной таблицы.
-
Теперь, запустите следующий sql-скрипт, вы увидите результаты в 1000 000 строк на странице, вы можете изменить номер строки на странице, чтобы чаще видеть результаты.
-
Обратите внимание, что я установил 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