2015-11-20 2 views
2

У меня есть SQL Server db с довольно большим количеством обмановков. Удаление дубликатов вручную просто не будет забавным, поэтому мне было интересно, есть ли какое-либо программирование или скрипты sql, которые я могу сделать, чтобы автоматизировать его.Петля через результирующий набор sql и удаляем [n] дубликаты

Ниже приведен мой запрос, который возвращает идентификатор и код дубликатов.

select a.ID, a.Code 
from Table1 a 
inner join (
SELECT Code 
FROM Table1 GROUP BY Code HAVING COUNT(Code)>1) 
x on x.Code= a.Code 

я получить отдачу, как это, например:

5163 51727 
5164 51727 
5165 51727 
5166 51728 
5167 51728 
5168 51728 

Этот фрагмент кода показывает три возвращения для каждого идентификатора/кода (так первичку «хорошо» запись и два обманутые). Однако это не всегда так. Там может быть до [n] обманов, хотя 2-3 кажется нормой.

Я просто хочу как-то пройти через этот результирующий набор и удалить все, кроме одной записи. ЗАПИСИ УДАЛИТЬСЯ АРБИТРАЖНЫМИ, так как любой из них может быть «сохранен».

ответ

3

Вы можете использовать row_number для удаления вашего удаления. т.е.

CREATE TABLE #table1 
(id INT, 
code int 
); 

WITH cte AS 
(select a.ID, a.Code, ROW_NUMBER() OVER(PARTITION by COdE ORDER BY ID) AS rn 
from #Table1 a 
) 
DELETE x 
FROM #table1 x 
JOIN cte ON x.id = cte.id 
WHERE cte.rn > 1 

Но ... Если вы собираетесь делать много удалений из очень большой таблицы, которую вы могли бы быть лучше, чтобы выбрать из строки, нужно в временную таблицу & затем обрезает СВОЙ таблицу и повторно вставьте нужные строки. Сохраняет журнал транзакций от забивания, ваш CI получает Fragged и должен быть быстрее!

0

Самостоятельное решение с испытанием на производительность VS cte.

create table codes(
id int IDENTITY(1,1) NOT NULL, 
code int null, 
CONSTRAINT [PK_codes_id] PRIMARY KEY CLUSTERED 
(
    id ASC 
)) 

declare @counter int, @code int 
set @counter = 1 
set @code = 1 
while (@counter <= 1000000) 
begin 
    print ABS(Checksum(NewID()) % 1000) 
    insert into codes(code) select ABS(Checksum(NewID()) % 1000) 
    set @counter = @counter + 1 
end 
GO 

set statistics time on; 
    delete a 
    from codes a left join(
    select MIN(id) as id from codes 
    group by code) b 
    on a.id = b.id 
    where b.id is null 
set statistics time off; 

--set statistics time on; 
-- WITH cte AS 
-- (select a.id, a.code, ROW_NUMBER() OVER(PARTITION by code ORDER BY id) AS rn 
-- from codes a 
-- ) 
-- delete x 
-- FROM codes x 
-- JOIN cte ON x.id = cte.id 
-- WHERE cte.rn > 1 
--set statistics time off; 

Производительность Результаты тестов: С Регистрация:

SQL Server Execution Times: 
    CPU time = 3198 ms, elapsed time = 3200 ms. 

(999000 row(s) affected) 

С КТР:

SQL Server Execution Times: 
    CPU time = 4197 ms, elapsed time = 4229 ms. 

(999000 row(s) affected) 
+0

Почему производительность иметь важное значение для проблемы, как это? Похоже на 1, сделанный администратором. – JBrooks

+0

Важно знать, что CTE медленны. Другие люди могут смотреть на этот вопрос в будущем, и у них могут быть разные проблемы для решения. –

0

Это в основном делается так:

WITH CTE_Dup AS 
(
SELECT*, 
ROW_NUMBER()OVER (PARTITIONBY SalesOrderno, ItemNo ORDER BY SalesOrderno, ItemNo) 
AS ROW_NO 
from dbo.SalesOrderDetails 
) 
DELETEFROM CTE_Dup WHERE ROW_NO > 1; 

ВНИМАНИЕ: ДОЛЖЕН БЫТЬ ВСЕ ПЛОЩАДКА !!

Вот еще один пример:

CREATE TABLE #Table (C1 INT,C2 VARCHAR(10)) 

INSERT INTO #Table VALUES (1,'SQL Server') 
INSERT INTO #Table VALUES (1,'SQL Server') 
INSERT INTO #Table VALUES (2,'Oracle') 

SELECT * FROM #Table 

;WITH Delete_Duplicate_Row_cte 
    AS (SELECT ROW_NUMBER()OVER(PARTITION BY C1, C2 ORDER BY C1,C2) ROW_NUM,* 
     FROM #Table) 
DELETE FROM Delete_Duplicate_Row_cte WHERE ROW_NUM > 1 

SELECT * FROM #Table 
1

Это на самом деле очень просто:

DELETE FROM Table1 
WHERE ID NOT IN 
     (SELECT MAX(ID) 
      FROM Table1 
      GROUP BY CODE) 
+0

Похоже, что это сработает, но я бы изменил первую строку на SELECT a.ID, a.Code FROM Table1 и проверил, что результаты и подсчет совпадают с тем, что вы ожидаете от вашего существующего запроса. :) – Quantumplate

+0

Я согласен и всегда сделайте это или даже SELECT * INTO # Table1Backup FROM Table1; перед рукой. – JBrooks

Смежные вопросы