Rozważmy kolumnę o nazwie EmployeeName
table Employee
. Celem jest usunięcie powtarzających się rekordów na podstawie EmployeeName
pola.
EmployeeName
------------
Anand
Anand
Anil
Dipak
Anil
Dipak
Dipak
Anil
Za pomocą jednego zapytania chcę usunąć powtarzające się rekordy.
Jak można to zrobić za pomocą TSQL w SQL Server?
sql
tsql
duplicates
delete-row
usr021986
źródło
źródło
empId
w twoim przykładzie jest kolumna używana przez Johna?row_number() over (partition by EmployeeName order by EmployeeName)
z nazwiskiem pracownika ... więc twój rn byłby ... to by wybrać dowolny pojedynczy rekord dla każdego nazwiska .Odpowiedzi:
Możesz to zrobić za pomocą funkcji okna. Uporządkuje kopie według empId i usunie wszystkie oprócz pierwszego.
delete x from ( select *, rn=row_number() over (partition by EmployeeName order by empId) from Employee ) x where rn > 1;
Uruchom go jako opcję, aby zobaczyć, co zostanie usunięte:
select * from ( select *, rn=row_number() over (partition by EmployeeName order by empId) from Employee ) x where rn > 1;
źródło
ORDER BY (SELECT NULL)
stackoverflow.com/a/4812038Zakładając, że Twoja tabela Employee ma również unikalną kolumnę (
ID
w poniższym przykładzie), zadziała:delete from Employee where ID not in ( select min(ID) from Employee group by EmployeeName );
Spowoduje to pozostawienie wersji o najniższym identyfikatorze w tabeli.
Edytuj
komentarz Re McGyver - stan na SQL 2012
W przypadku wersji 2008 R2 i starszych
W przypadku 2008R2 musisz rzutować na
GUID
typ obsługiwany przezMIN
npdelete from GuidEmployees where CAST(ID AS binary(16)) not in ( select min(CAST(ID AS binary(16))) from GuidEmployees group by EmployeeName );
SqlFiddle dla różnych typów w Sql 2008
SqlFiddle dla różnych typów w Sql 2012
źródło
Możesz spróbować czegoś takiego:
delete T1 from MyTable T1, MyTable T2 where T1.dupField = T2.dupField and T1.uniqueField > T2.uniqueField
(przy założeniu, że masz pole unikalne oparte na liczbach całkowitych)
Osobiście powiedziałbym, że lepiej byłoby spróbować naprawić fakt, że zduplikowane wpisy są dodawane do bazy danych, zanim to nastąpi, niż jako operacja po naprawieniu.
źródło
DELETE FROM MyTable WHERE ID NOT IN ( SELECT MAX(ID) FROM MyTable GROUP BY DuplicateColumn1, DuplicateColumn2, DuplicateColumn3)
WITH TempUsers (FirstName, LastName, duplicateRecordCount) AS ( SELECT FirstName, LastName, ROW_NUMBER() OVER (PARTITIONBY FirstName, LastName ORDERBY FirstName) AS duplicateRecordCount FROM dbo.Users ) DELETE FROM TempUsers WHERE duplicateRecordCount > 1
źródło
WITH CTE AS ( SELECT EmployeeName, ROW_NUMBER() OVER(PARTITION BY EmployeeName ORDER BY EmployeeName) AS R FROM employee_table ) DELETE CTE WHERE R > 1;
Magia typowych wyrażeń tabelarycznych.
źródło
Próbować
DELETE FROM employee WHERE rowid NOT IN (SELECT MAX(rowid) FROM employee GROUP BY EmployeeName);
źródło
Jeśli szukasz sposobu na usunięcie duplikatów, ale masz obcy klucz wskazujący tabelę z duplikatami, możesz zastosować następujące podejście, używając powolnego, ale efektywnego kursora.
Spowoduje to przeniesienie zduplikowanych kluczy w tabeli kluczy obcych.
create table #properOlvChangeCodes( id int not null, name nvarchar(max) not null ) DECLARE @name VARCHAR(MAX); DECLARE @id INT; DECLARE @newid INT; DECLARE @oldid INT; DECLARE OLVTRCCursor CURSOR FOR SELECT id, name FROM Sales_OrderLineVersionChangeReasonCode; OPEN OLVTRCCursor; FETCH NEXT FROM OLVTRCCursor INTO @id, @name; WHILE @@FETCH_STATUS = 0 BEGIN -- determine if it should be replaced (is already in temptable with name) if(exists(select * from #properOlvChangeCodes where Name=@name)) begin -- if it is, finds its id Select top 1 @newid = id from Sales_OrderLineVersionChangeReasonCode where Name = @name -- replace terminationreasoncodeid in olv for the new terminationreasoncodeid update Sales_OrderLineVersion set ChangeReasonCodeId = @newid where ChangeReasonCodeId = @id -- delete the record from the terminationreasoncode delete from Sales_OrderLineVersionChangeReasonCode where Id = @id end else begin -- insert into temp table if new insert into #properOlvChangeCodes(Id, name) values(@id, @name) end FETCH NEXT FROM OLVTRCCursor INTO @id, @name; END; CLOSE OLVTRCCursor; DEALLOCATE OLVTRCCursor; drop table #properOlvChangeCodes
źródło
delete from person where ID not in ( select t.id from (select min(ID) as id from person group by email ) as t );
źródło
Zobacz również poniższy sposób usuwania.
Declare @Employee table (EmployeeName varchar(10)) Insert into @Employee values ('Anand'),('Anand'),('Anil'),('Dipak'), ('Anil'),('Dipak'),('Dipak'),('Anil') Select * from @Employee
Utworzono przykładową tabelę o nazwie
@Employee
i załadowano do niej podane dane.Delete aliasName from ( Select *, ROW_NUMBER() over (Partition by EmployeeName order by EmployeeName) as rowNumber From @Employee) aliasName Where rowNumber > 1 Select * from @Employee
Wynik:
Wiem, zadaje się to sześć lat temu, publikując tylko na wypadek, gdyby było to pomocne dla każdego.
źródło
Oto dobry sposób na deduplikację rekordów w tabeli, która ma kolumnę tożsamości opartą na żądanym kluczu podstawowym, który można zdefiniować w czasie wykonywania. Zanim zacznę, wypełnię przykładowy zestaw danych do pracy, używając następującego kodu:
if exists (select 1 from sys.all_objects where type='u' and name='_original') drop table _original declare @startyear int = 2017 declare @endyear int = 2018 declare @iterator int = 1 declare @income money = cast((SELECT round(RAND()*(5000-4990)+4990 , 2)) as money) declare @salesrepid int = cast(floor(rand()*(9100-9000)+9000) as varchar(4)) create table #original (rowid int identity, monthyear varchar(max), salesrepid int, sale money) while @iterator<=50000 begin insert #original select (Select cast(floor(rand()*(@endyear-@startyear)+@startyear) as varchar(4))+'-'+ cast(floor(rand()*(13-1)+1) as varchar(2)) ), @salesrepid , @income set @salesrepid = cast(floor(rand()*(9100-9000)+9000) as varchar(4)) set @income = cast((SELECT round(RAND()*(5000-4990)+4990 , 2)) as money) set @iterator=@iterator+1 end update #original set monthyear=replace(monthyear, '-', '-0') where len(monthyear)=6 select * into _original from #original
Następnie utworzę typ o nazwie ColumnNames:
create type ColumnNames AS table (Columnnames varchar(max))
Na koniec utworzę przechowywany proces z następującymi trzema zastrzeżeniami: 1. Proces pobierze wymagany parametr @ nazwa tabeli, który definiuje nazwę tabeli, z której usuwasz w swojej bazie danych. 2. Proces ma opcjonalny parametr @columns, którego możesz użyć do zdefiniowania pól składających się na żądany klucz podstawowy, dla którego usuwasz. Jeśli to pole pozostanie puste, zakłada się, że wszystkie pola poza kolumną tożsamości tworzą żądany klucz podstawowy. 3. Po usunięciu zduplikowanych rekordów zostanie zachowany rekord z najniższą wartością w kolumnie tożsamości.
Oto moje zapisane proce delete_dupes:
create proc delete_dupes (@tablename varchar(max), @columns columnnames readonly) as begin declare @table table (iterator int, name varchar(max), is_identity int) declare @tablepartition table (idx int identity, type varchar(max), value varchar(max)) declare @partitionby varchar(max) declare @iterator int= 1 if exists (select 1 from @columns) begin declare @columns1 table (iterator int, columnnames varchar(max)) insert @columns1 select 1, columnnames from @columns set @partitionby = (select distinct substring((Select ', '+t1.columnnames From @columns1 t1 Where T1.iterator = T2.iterator ORDER BY T1.iterator For XML PATH ('')),2, 1000) partition From @columns1 T2 ) end insert @table select 1, a.name, is_identity from sys.all_columns a join sys.all_objects b on a.object_id=b.object_id where b.name = @tablename declare @identity varchar(max)= (select name from @table where is_identity=1) while @iterator>=0 begin insert @tablepartition Select distinct case when @iterator=1 then 'order by' else 'over (partition by' end , substring((Select ', '+t1.name From @table t1 Where T1.iterator = T2.iterator and is_identity=@iterator ORDER BY T1.iterator For XML PATH ('')),2, 5000) partition From @table T2 set @iterator=@iterator-1 end declare @originalpartition varchar(max) if @partitionby is null begin select @originalpartition = replace(b.value+','+a.type+a.value ,'over (partition by','') from @tablepartition a cross join @tablepartition b where a.idx=2 and b.idx=1 select @partitionby = a.type+a.value+' '+b.type+a.value+','+b.value+') rownum' from @tablepartition a cross join @tablepartition b where a.idx=2 and b.idx=1 end else begin select @originalpartition=b.value +','+ @partitionby from @tablepartition a cross join @tablepartition b where a.idx=2 and b.idx=1 set @partitionby = (select 'OVER (partition by'+ @partitionby + ' ORDER BY'+ @partitionby + ','+b.value +') rownum' from @tablepartition a cross join @tablepartition b where a.idx=2 and b.idx=1) end exec('select row_number() ' + @partitionby +', '+@originalpartition+' into ##temp from '+ @tablename+'') exec( 'delete a from _original a left join ##temp b on a.'+@identity+'=b.'+@identity+' and rownum=1 where b.rownum is null') drop table ##temp end
Po wykonaniu tej czynności możesz usunąć wszystkie zduplikowane rekordy, uruchamiając proc. Aby usunąć duplikaty bez definiowania żądanego klucza podstawowego, użyj tego wywołania:
Aby usunąć duplikaty na podstawie zdefiniowanego pożądanego klucza podstawowego, użyj tego wywołania:
declare @table1 as columnnames insert @table1 values ('salesrepid'),('sale') exec delete_dupes '_original' , @table1
źródło