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

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

Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (1,'Cinthol','cosmetic soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (1,'Cinthol','cosmetic soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (1,'Cinthol','cosmetic soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (1,'Lux','cosmetic soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (1,'Crowning Glory','cosmetic soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (2,'Cinthol','nice soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (3,'Lux','nice soap','soap');
Insert Into tblProduct (ProductId,ProductName,Description,Category) Values (3,'Lux','nice soap','soap');

Я хочу, чтобы в моей таблице присутствовал только 1 экземпляр каждой строки. Таким образом, 2nd, 3rd and last row, которые полностью идентичны, должны быть удалены. Какой запрос я могу написать для этого? Можно ли это сделать без создания временных таблиц? Только одним запросом?

Заранее спасибо :)


person TCM    schedule 27.07.2010    source источник
comment
Первая запись на основе порядка размещения? Для какой версии SQL Server?   -  person OMG Ponies    schedule 27.07.2010
comment
Я собираюсь предположить, что вы имеете в виду 3-ю нормальную форму, когда говорите 3-й класс. Если он разрешает полные дубликаты в таблице, он не находится в 3NF по определению;)   -  person Tom H    schedule 27.07.2010


Ответы (4)


Попробуйте это - он удалит все дубликаты из вашей таблицы:

;WITH duplicates AS
(
    SELECT 
       ProductID, ProductName, Description, Category,
       ROW_NUMBER() OVER (PARTITION BY ProductID, ProductName
                          ORDER BY ProductID) 'RowNum'
    FROM dbo.tblProduct
)
DELETE FROM duplicates
WHERE RowNum > 1
GO

SELECT * FROM dbo.tblProduct
GO

Теперь ваши дубликаты должны исчезнуть: вывод:

ProductID   ProductName   DESCRIPTION        Category
   1          Cinthol         cosmetic soap      soap
   1          Lux             cosmetic soap      soap
   1          Crowning Glory  cosmetic soap      soap
   2          Cinthol         nice soap          soap
   3          Lux             nice soap          soap
person marc_s    schedule 27.07.2010
comment
Хорошо, Marc_s, это CTE-запрос? Если да, то не обязательно ли в запросе CTE иметь предложение union? - person TCM; 27.07.2010
comment
@Nitesh Panchal: да, CTE - одна из недостаточно используемых функций SQL Server, как и предложение OVER() :-) - person marc_s; 27.07.2010
comment
+1: я не был уверен, что вы можете удалить такое CTE, и прежде чем я смог его проверить, вы опубликовали свой ответ :) - person Tom H; 27.07.2010
comment
@ Том Х. Даже я не был уверен, что Delete может быть выпущено в CTE. У меня сложилось впечатление, что CTE используются только для рекурсивных запросов. - person TCM; 27.07.2010

DELETE tblProduct 
FROM tblProduct 
LEFT OUTER JOIN (
   SELECT MIN(ProductId) as ProductId, ProductName, Description, Category
   FROM tblProduct 
   GROUP BY ProductName, Description, Category
) as KeepRows ON
   tblProduct.ProductId= KeepRows.ProductId
WHERE
   KeepRows.ProductId IS NULL

Украдено из Как удалить повторяющиеся строки?

ОБНОВЛЕНИЕ:

Это будет работать только в том случае, если ProductId является первичным ключом (а это не так). Вам лучше использовать метод @marc_s, но я оставлю это на тот случай, если кто-то, использующий ПК, наткнется на этот пост.

person Abe Miessler    schedule 27.07.2010
comment
@Abe: rowid был первичным ключом для таблицы; На мгновение я подумал, что это синтаксис Oracle, пока не увидел ссылку. - person OMG Ponies; 27.07.2010
comment
Я предполагал, что ProductId был первичным ключом в его таблице. Я обновил его именами столбцов, чтобы избежать путаницы. - person Abe Miessler; 27.07.2010
comment
@Abe Miessler, я думал, что это сработает, но мне это показалось странным. Итак, я проверил в Managemenet Studio, и он действительно не работает. Пишет, что удалено 0 строк. Можете ли вы исправить запрос? - person TCM; 27.07.2010
comment
@Nitesh, я предположил (ошибочно), что ProductId будет уникальным идентификатором. Поскольку это не так, вам лучше использовать метод @marc_s. Извините за путаницу! - person Abe Miessler; 27.07.2010

Мне пришлось сделать это несколько недель назад... какую версию SQL Server вы используете? В SQL Server 2005 и выше вы можете использовать Row_Number как часть вашего выбора и выбирать только там, где Row_Number равен 1. Я забыл точный синтаксис, но он хорошо документирован... что-то вроде строк:

Select t0.ProductID, 
       t0.ProductName, 
       t0.Description, 
       t0.Category
Into   tblCleanData
From   (
    Select ProductID, 
           ProductName, 
           Description, 
           Category, 
           Row_Number() Over (
               Partition By ProductID, 
                            ProductName, 
                            Description, 
                            Category
               Order By     ProductID,
                            ProductName,
                            Description,
                            Category
           ) As RowNumber
    From   MyTable
) As t0
Where t0.RowNumber = 1

Посетите http://msdn.microsoft.com/en-us/library/ms186734.aspx, это поможет вам двигаться в правильном направлении.

person BenAlabaster    schedule 27.07.2010

Сначала используйте SELECT... INTO:

SELECT DISTINCT ProductID, ProductName, Description, Category
    INTO tblProductClean
    FROM tblProduct

Удаление первой таблицы.

person eykanal    schedule 27.07.2010
comment
Из ОП: можно ли это сделать без создания временных таблиц? Только одним запросом? - person dcp; 27.07.2010