Рассмотрим столбец с именем EmployeeName
table Employee
. Цель состоит в том, чтобы удалить повторяющиеся записи в зависимости от EmployeeName
поля.
EmployeeName
------------
Anand
Anand
Anil
Dipak
Anil
Dipak
Dipak
Anil
Используя один запрос, я хочу удалить повторяющиеся записи.
Как это можно сделать с помощью TSQL в SQL Server?
sql
tsql
duplicates
delete-row
usr021986
источник
источник
empId
столбец в вашем примере используется Джоном?row_number() over (partition by EmployeeName order by EmployeeName)
... это будет выбирать произвольную одиночную запись для каждого имени .Ответы:
Вы можете сделать это с помощью оконных функций. Он упорядочит дубликаты по empId и удалит все, кроме первого.
delete x from ( select *, rn=row_number() over (partition by EmployeeName order by empId) from Employee ) x where rn > 1;
Запустите его как select, чтобы увидеть, что будет удалено:
select * from ( select *, rn=row_number() over (partition by EmployeeName order by empId) from Employee ) x where rn > 1;
источник
ORDER BY (SELECT NULL)
stackoverflow.com/a/4812038Предполагая, что ваша таблица сотрудников также имеет уникальный столбец (
ID
в примере ниже), будет работать следующее:delete from Employee where ID not in ( select min(ID) from Employee group by EmployeeName );
Это оставит версию с наименьшим идентификатором в таблице.
Изменить
комментарий Ре МакГайвера - по состоянию на SQL 2012
Для 2008 R2 и более ранних версий
Для 2008R2 вам нужно будет привести
GUID
к типу, поддерживаемомуMIN
, напримерdelete from GuidEmployees where CAST(ID AS binary(16)) not in ( select min(CAST(ID AS binary(16))) from GuidEmployees group by EmployeeName );
SqlFiddle для различных типов в Sql 2008
SqlFiddle для различных типов в Sql 2012
источник
Вы можете попробовать что-то вроде следующего:
delete T1 from MyTable T1, MyTable T2 where T1.dupField = T2.dupField and T1.uniqueField > T2.uniqueField
(это предполагает, что у вас есть уникальное поле на основе целых чисел)
Лично я бы сказал, что вам было бы лучше попытаться исправить тот факт, что повторяющиеся записи добавляются в базу данных до того, как это произойдет, а не в качестве операции post fix-it.
источник
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
источник
WITH CTE AS ( SELECT EmployeeName, ROW_NUMBER() OVER(PARTITION BY EmployeeName ORDER BY EmployeeName) AS R FROM employee_table ) DELETE CTE WHERE R > 1;
Магия общих табличных выражений.
источник
Пытаться
DELETE FROM employee WHERE rowid NOT IN (SELECT MAX(rowid) FROM employee GROUP BY EmployeeName);
источник
Если вы ищете способ удалить дубликаты, но у вас есть внешний ключ, указывающий на таблицу с дубликатами, вы можете воспользоваться следующим подходом, используя медленный, но эффективный курсор.
Он переместит повторяющиеся ключи в таблицу внешних ключей.
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
источник
delete from person where ID not in ( select t.id from (select min(ID) as id from person group by email ) as t );
источник
См. Также способ удаления ниже.
Declare @Employee table (EmployeeName varchar(10)) Insert into @Employee values ('Anand'),('Anand'),('Anil'),('Dipak'), ('Anil'),('Dipak'),('Dipak'),('Anil') Select * from @Employee
Создал образец таблицы с именем
@Employee
и загрузил ее с заданными данными.Delete aliasName from ( Select *, ROW_NUMBER() over (Partition by EmployeeName order by EmployeeName) as rowNumber From @Employee) aliasName Where rowNumber > 1 Select * from @Employee
Результат:
Я знаю, что об этом спрашивают шесть лет назад, отправляйте на всякий случай, если это кому-то поможет.
источник
Вот хороший способ дедупликации записей в таблице, в которой есть столбец идентификаторов на основе желаемого первичного ключа, который вы можете определить во время выполнения. Прежде чем начать, я заполню образец набора данных для работы, используя следующий код:
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
Затем я создам Тип с именем ColumnNames:
create type ColumnNames AS table (Columnnames varchar(max))
Наконец, я создам сохраненную процедуру со следующими тремя предостережениями: 1. Процедура примет обязательный параметр @tablename, который определяет имя таблицы, из которой вы удаляете в своей базе данных. 2. У процедуры есть необязательный параметр @columns, который вы можете использовать для определения полей, составляющих желаемый первичный ключ, для которого вы удаляете. Если это поле оставить пустым, предполагается, что все поля, кроме столбца идентификации, составляют желаемый первичный ключ. 3. При удалении повторяющихся записей будет сохранена запись с наименьшим значением в столбце идентификаторов.
Вот моя сохраненная процедура 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
Как только это будет выполнено, вы можете удалить все повторяющиеся записи, запустив proc. Чтобы удалить дубликаты без определения желаемого первичного ключа, используйте этот вызов:
Чтобы удалить дубликаты на основе определенного желаемого первичного ключа, используйте этот вызов:
declare @table1 as columnnames insert @table1 values ('salesrepid'),('sale') exec delete_dupes '_original' , @table1
источник