Как удалить повторяющиеся строки в таблице

У меня есть таблица с тремя столбцами. Нет первичного ключа, поэтому могут быть повторяющиеся строки. Мне нужно просто сохранить его и удалить остальных. Любая идея, как это сделать, это Sql Server?

Ответы

Ответ 1

Я бы выбрал строку DISTINCT и бросил их во временную таблицу, затем отменил исходную таблицу и скопировал данные из temp. EDIT: теперь с фрагментом кода!

INSERT INTO TABLE_2 
SELECT DISTINCT * FROM TABLE_1
GO
DELETE FROM TABLE_1
GO
INSERT INTO TABLE_1
SELECT * FROM TABLE_2
GO

Ответ 2

Добавьте столбец идентификатора, чтобы действовать как суррогатный первичный ключ, и используйте его для идентификации двух из трех строк, которые нужно удалить.

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

Ответ 3

Следующий пример также работает, когда ваш ПК является всего лишь подмножеством всех столбцов таблицы.

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

Сначала найдите повторяющиеся строки:

SELECT col1, col2, count(*)
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1

Если их немного, вы можете удалить их вручную:

set rowcount 1
delete from t1
where col1=1 and col2=1

Значение "rowcount" должно быть в n-1 раз больше количества дубликатов. В этом примере есть 2 дубликаты, поэтому rowcount равно 1. Если вы получаете несколько повторяющихся строк, вы должны сделать это для каждого уникального первичного ключа.

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

SELECT col1, col2, col3=count(*)
INTO holdkey
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1

Затем скопируйте ключи, но устраните дубликаты.

SELECT DISTINCT t1.*
INTO holddups
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1
AND t1.col2 = holdkey.col2

В ваших ключах теперь есть уникальные ключи. Проверьте, нет ли результата:

SELECT col1, col2, count(*)
FROM holddups
GROUP BY col1, col2

Удалить дубликаты из исходной таблицы:

DELETE t1
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1
AND t1.col2 = holdkey.col2

Вставить исходные строки:

INSERT t1 SELECT * FROM holddups

btw и для полноты: в Oracle есть скрытое поле, которое вы можете использовать (rowid):

DELETE FROM our_table
WHERE rowid not in
(SELECT MIN(rowid)
FROM our_table
GROUP BY column1, column2, column3... ;

см. ниже: Сайт знаний Microsoft

Ответ 4

Здесь метод, который я использовал когда я задал этот вопрос -

DELETE MyTable 
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

Ответ 5

Это способ сделать это с помощью Common Table Expressions, CTE. Он не содержит циклов, никаких новых столбцов или чего-либо еще и не вызывает никаких нежелательных триггеров (из-за удаления + вставки).

Вдохновленный в этой статье.

CREATE TABLE #temp (i INT)

INSERT INTO #temp VALUES (1)
INSERT INTO #temp VALUES (1)
INSERT INTO #temp VALUES (2)
INSERT INTO #temp VALUES (3)
INSERT INTO #temp VALUES (3)
INSERT INTO #temp VALUES (4)

SELECT * FROM #temp

;
WITH [#temp+rowid] AS
(SELECT ROW_NUMBER() OVER (ORDER BY i ASC) AS ROWID, * FROM #temp)
DELETE FROM [#temp+rowid] WHERE rowid IN 
(SELECT MIN(rowid) FROM [#temp+rowid] GROUP BY i HAVING COUNT(*) > 1)

SELECT * FROM #temp

DROP TABLE #temp   

Ответ 6

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

Ответ 7

После очистки текущего беспорядка вы можете добавить первичный ключ, который включает все поля в таблице. это заставит вас снова войти в беспорядок. Конечно, это решение может очень сильно нарушить существующий код. Это также нужно будет обработать.

Ответ 8

Можете ли вы добавить поле идентификации первичного ключа в таблицу?

Ответ 9

Manrico Corazzi - я специализируюсь на Oracle, а не на MS SQL, поэтому вам нужно сказать мне, возможно ли это в качестве повышения производительности: -

  • Оставьте то же, что и ваш первый шаг - вставьте различные значения в таблицу TABLE2 из таблицы.
  • Снимите ТАБЛИЦУ1. (Drop должен быть быстрее, чем delete, я предполагаю, так же, как и усечение быстрее, чем удаление).
  • Переименуйте ТАБЛИЦУ2 как ТАБЛИЦА 1 (экономит ваше время, поскольку вы переименовываете объект, а не копируете данные из одной таблицы в другую).

Ответ 10

Здесь другой способ, с тестовыми данными

create table #table1 (colWithDupes1 int, colWithDupes2 int)
insert into #table1
(colWithDupes1, colWithDupes2)
Select 1, 2 union all
Select 1, 2 union all
Select 2, 2 union all
Select 3, 4 union all
Select 3, 4 union all
Select 3, 4 union all
Select 4, 2 union all
Select 4, 2 


select * from #table1

set rowcount 1
select 1

while @@rowcount > 0
delete #table1  where 1 < (select count(*) from #table1 a2 
   where #table1.colWithDupes1 = a2.colWithDupes1
and #table1.colWithDupes2 = a2.colWithDupes2
)

set rowcount 0

select * from #table1

Ответ 11

Как насчет:

select distinct * into #t from duplicates_tbl

truncate duplicates_tbl

insert duplicates_tbl select * from #t

drop table #t

Ответ 12

Как насчет этого решения:

Сначала вы выполните следующий запрос:

  select 'set rowcount ' + convert(varchar,COUNT(*)-1) + ' delete from MyTable where field=''' + field +'''' + ' set rowcount 0'  from mytable group by field having COUNT(*)>1

И тогда вам просто нужно выполнить возвращенный набор результатов

set rowcount 3 delete from Mytable where field='foo' set rowcount 0
....
....
set rowcount 5 delete from Mytable where field='bar' set rowcount 0

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

Ответ 13

Я не уверен, что это работает с операторами DELETE, но это способ найти повторяющиеся строки:

 SELECT *
 FROM myTable t1, myTable t2
 WHERE t1.field = t2.field AND t1.id > t2.id

Я не уверен, что вы можете просто изменить "SELECT" на "DELETE" (кто-нибудь хочет сообщить мне?), но даже если вы не можете, вы можете просто сделать его в подзапрос.