Другой возможный способ сделать это
;
--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
- оригинал и скопировать их обратно, чтобы минимизировать ведение журнала по сравнению с удалением очень высокая пропорция рядов.
DELETE FROM
напрямую использовать термин CTE. См. Stackoverflow.com/q/18439054/398670