删除表中重复记录
LazyBee
最近由于要给旧系统的表中增加主键(SQL Server2000的表),由于旧表中存在重复记录所以导致增加不上,所以需要写一段SQL语句来删除所有的重复记录(就是必须保留重复记录中的一条,维持数据记录的唯一性),我知道园子里大虾多,所以在这里集思广益,看看大家都有什么好的办法:
方法一:
1 为了保证完整性,首先启动一个事务
2 声明一个表变量(在这里使用表变量主要是考虑重复的数据不是很多,同时为了获得更好的性能;当然如果重复的数据特别多,使用临时表是更
好的选择,因为表变量的数据都是存在内存中的,如果数据量大,可能导致内存吃紧。)用于存储重复性的数据,这个需要定义成和源表一样。
3 将重复记录的一条插入到表变量中。
4 删除所有有重复记录的记录
5 将表变量中的记录插入的源表中。
6 如果出错,回滚事务,否则提交事务
以下是相应的
sql
语句块:
1
Begin
Tran
LazyBee
2
declare
@tmp
Table
3
(lLIstHeader_id
int
,lEncounter_id
int
,dtLastUpdate_dt
datetime
,
4
sLastUpdate_id
char
(
10
),iConcurrency_id
int
)
5

6
Insert
@tmp
(lLIstHeader_id,lEncounter_id,dtLastUpdate_dt,sLastUpdate_id,iConcurrency_id)
7
select
lListHeader_id,lEncounter_id,dtLastUpdate_dt,sLastUpdate_id,iConcurrency_id
8
from
lstHeaderencounter
9
group
by
lListHeader_id,lEncounter_id,dtLastUpdate_dt,sLastUpdate_id,iConcurrency_id
10
having
count
(
*
)
>
1
11

12
delete
lstHeaderencounter
from
@tmp
d
13
where
d.lListHeader_id
=
lstHeaderencounter.lListHeader_id
and
14
d.lEncounter_id
=
lstHeaderencounter.lEncounter_id
15

16
insert
lstHeaderencounter(lLIstHeader_id,lEncounter_id,dtLastUpdate_dt,sLastUpdate_id,iConcurrency_id)
17
select
lListHeader_id,lEncounter_id,dtLastUpdate_dt,sLastUpdate_id,iConcurrency_id
18
from
@tmp
19

20
if
@@error
<>
0
21
Begin
22
print
'
roll back
'
23
RollBack
Tran
LazyBee
24
End
25
else
26
Begin
27
print
'
Success
'
28
Commit
Tran
LazyBee
29
End
30
我知道这个方法不够通用,因为如果有多个类似重复记录的表存在,将每次都要修改表定义和插入语句的字段内容,不知各位有没有好的方法或意见,大家讨论讨论:)
刚在网上找到另外一些解决方案,感觉也挺不错的
方法二:
1 创建一个临时表,这个临时表的结构和源表一样
2 给这个临时表增加一个唯一索引(根据需要),并且选中忽略重复值
3 将源表的记录全部插入临时表中,这时会因为重复记录出现3604的错误。
4 删除源表的记录,将临时表的记录插入源表中,然后删除临时表。
方法三(主要针对重复记录完全相同的情况):
1 利用distinct将唯一记录插入临时表中
2
然后将唯一记录再倒回源表中
Select
distinct
*
into
#Tmp
from
tableName
Drop
table
tableName
Select
*
into
tableName
from
#Tmp
Drop
table
#Tmp
方法四(主要针对记录部分字段相同的记录):
这种方法和方法一有点类似,不过实现方法不同而已。在这里使用了两个临时表.我们假设重复字段为lListHeader_id,lEncounter_id,要求得到这两
个字段的唯一结果集,我们保留重复记录的第一条,当然如果保留重复记录的最后一条可以使用
max
代替
min
:
Select
identity
(
int
,
1
,
1
)
as
autoID,
*
into
#Tmp
from
tableName
Select
min
(autoID)
as
autoID
into
#Tmp2
from
#Tmp
group
by
lListHeader_id,lEncounter_id
Select
*
from
#Tmp
where
autoID
in
(
Select
autoID
from
#Tmp2)
方法五(也是针对部分字段相同的记录)
纯
SQL
直接删除:
1
Delete
lstStructureItems
from
2
(
select
lStructure_id,lListHeader_id,lList_id,
max
(lParent_id)
as
lParent_id,
max
(lOrder_num)
as
lOrder_num,lDoctor_id
3
from
lstStructureItems
4
group
by
lStructure_id,lListHeader_id,lList_id,lDoctor_id
5
having
count
(
*
)
>
1
) d
6
where
7
lstStructureItems.lStructure_id
=
d.lStructure_id
and
8
lstStructureItems.lListHeader_id
=
d.lListHeader_id
and
9
lstStructureItems.lList_id
=
d.lList_id
and
10
lstStructureItems.lDoctor_id
=
d.lDoctor_id
and
11
(lstStructureItems.lParent_id
<>
d.lParent_id or
12
lstStructureItems.lOrder_num
<>
d.lOrder_num)
13
在这里我们为了给
lStructure_id,lListHeader_id,lList_id,lDoctor_id
四个字段增加一个唯一索引,所以需要只保留这四个字段保持唯一的值,其他的都需要删除。所以我们采用将这四个字段进行
group by
,然后保留
lParent_id
和
lOrder_num
最大值的记录(注:这里假设表中不存在两条完全相同的记录,如果存在的话只能通过前面的方法来进行删除)。