Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否删除SQL Server中的重复记录?_Sql_Tsql_Duplicates_Delete Row - Fatal编程技术网

是否删除SQL Server中的重复记录?

是否删除SQL Server中的重复记录?,sql,tsql,duplicates,delete-row,Sql,Tsql,Duplicates,Delete Row,考虑一个名为EmployeeNametableEmployee的列。目标是根据EmployeeName字段删除重复记录 EmployeeName ------------ Anand Anand Anil Dipak Anil Dipak Dipak Anil 使用一个查询,我想删除重复的记录 如何在SQL Server中使用TSQL实现这一点?您可以尝试以下方法: delete T1 from MyTable T1, MyTable T2 where T1.dupField = T2.dup

考虑一个名为
EmployeeName
table
Employee
的列。目标是根据
EmployeeName
字段删除重复记录

EmployeeName
------------
Anand
Anand
Anil
Dipak
Anil
Dipak
Dipak
Anil
使用一个查询,我想删除重复的记录


如何在SQL Server中使用TSQL实现这一点?

您可以尝试以下方法:

delete T1
from MyTable T1, MyTable T2
where T1.dupField = T2.dupField
and T1.uniqueField > T2.uniqueField  
(假设您有一个基于整数的唯一字段)


就我个人而言,虽然我认为您最好在数据库出现之前纠正重复条目被添加到数据库中的事实,而不是作为后期修复操作。

假设您的Employee表也有一个唯一的列(
ID
,在下面的示例中),以下操作将起作用:

delete from Employee 
where ID not in
(
    select min(ID)
    from Employee 
    group by EmployeeName 
);
这将保留表中ID最低的版本

编辑
关于McGyver的评论-截至

MIN
可以与numeric、char、varchar、uniqueidentifier或datetime列一起使用,但不能与bit列一起使用

早在

MIN可以用于numeric、char、varchar或datetime列,但不能用于bit列(它也不能用于GUID)

对于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 
);


您可以使用窗口功能完成此操作。它将按empId对复制品进行排序,并删除除第一个以外的所有复制品

delete x from (
  select *, rn=row_number() over (partition by EmployeeName order by empId)
  from Employee 
) x
where rn > 1;
将其作为选择运行,以查看将删除的内容:

select *
from (
  select *, rn=row_number() over (partition by EmployeeName order by empId)
  from Employee 
) x
where rn > 1;
常用表表达式的魔力

DELETE
FROM MyTable
WHERE ID NOT IN (
     SELECT MAX(ID)
     FROM MyTable
     GROUP BY DuplicateColumn1, DuplicateColumn2, DuplicateColumn3)

试一试


如果您正在寻找删除重复项的方法,但是有一个外键指向包含重复项的表,那么可以使用一个缓慢但有效的游标采取以下方法

它将重新定位外键表上的重复键

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

请参见下面的删除方式

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
最后,我将创建一个带有以下3个注意事项的存储过程: 1.proc将采用必需的参数@tablename,该参数定义要从数据库中删除的表的名称。 2.proc有一个可选参数@columns,您可以使用它来定义组成要删除的主键的字段。如果此字段留空,则假定除标识列之外的所有字段构成所需的主键。 3.删除重复记录时,将保留其标识列中值最低的记录

以下是我的删除重复存储过程:

 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
一旦符合此要求,您可以通过运行程序删除所有重复记录。要在不定义所需主键的情况下删除重复,请使用此调用:

exec delete_dupes '_original'
declare @table1 as columnnames
insert @table1
values ('salesrepid'),('sale')
exec delete_dupes '_original' , @table1
要根据定义的所需主键删除重复,请使用此调用:

exec delete_dupes '_original'
declare @table1 as columnnames
insert @table1
values ('salesrepid'),('sale')
exec delete_dupes '_original' , @table1

您的意思是删除重复记录,对吗?您可以选择不同的值及其相关ID,并删除ID不在已选列表中的记录?您是否有唯一ID列?如果表中缺少唯一ID,您如何接受John Gibb给出的答案?John在您的示例中使用的
empId
列在哪里?如果您没有唯一的ID列,或者没有任何其他有意义的内容来执行订单,您也可以按employeename列进行订单。。。因此,您的rn将
行号()覆盖(按EmployeeName划分,按EmployeeName排序)
。。。这将为每个名称选择任意单个记录。此外,在Oracle中,如果没有其他唯一的id列,则可以使用“rowid”。+1即使没有id列,也可以添加一个作为标识字段。回答很好。敏锐而有效。即使表格没有ID;最好包含一个来执行此方法。我的表中没有唯一字段(ID)。那么,我如何执行该操作呢?SubPortal/a_horse_,带有_no_名称-这不应该是从实际表中选择的吗?另外,ROW_NUMBER应该是ROW_NUMBER(),因为它是一个函数,对吗?如果没有主键,可以使用
ORDER BY(选择NULL)
exec delete_dupes '_original'
declare @table1 as columnnames
insert @table1
values ('salesrepid'),('sale')
exec delete_dupes '_original' , @table1
delete from person 
where ID not in
(
        select t.id from 
        (select min(ID) as id from person 
         group by email 
        ) as t
);