Другой возможный способ сделать это -
;
--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3
ORDER BY ( SELECT 0)) RN
FROM #MyTable)
DELETE FROM cte
WHERE RN > 1;
Я использую ORDER BY (SELECT 0)
выше, так как это произвольно, какую строку сохранить в случае ничьей.
Чтобы сохранить последний в порядке RowID
, например, вы можете использовать ORDER BY RowID DESC
Планы выполнения
План выполнения этого часто проще и эффективнее, чем в принятом ответе, поскольку не требует самостоятельного соединения.
Однако это не всегда так. Единственное место, где решение GROUP BY
может быть предпочтительным, - это ситуации, когда хеш-агрегат будет выбран предпочтительнее агрегата потока.
Решение ROW_NUMBER
всегда дает один и тот же план, тогда как стратегия GROUP BY
более гибкая.
Факторы, которые могут благоприятствовать подходу агрегирования хэшей, будут
- Нет полезного индекса для столбцов разделения
- относительно меньше групп с относительно большим количеством дубликатов в каждой группе
В крайних версиях этого второго случая (если существует очень мало групп с большим количеством дубликатов в каждой), можно также подумать о том, чтобы просто вставить строки для сохранения в новую таблицу, а затем TRUNCATE
с оригиналом и скопировать его свести к минимуму ведение журнала по сравнению с удалением очень высокой пропорции строк.