1引言

在对数据库进行操作过程中我们可能会遇到这种情况,表中的数据可能重复出现,使我们对数据库的操作过程中带来读诸多不便,那么怎么删除这些重复没有用的数据呢?

平时工作中可能会遇到当试图对库表中的某一列或几列创建唯一索引时,系统提示 ORA-01452:不能创建唯一索引,发现重复记录。

2处理过程

重复的数据可能有这样两种情况:第一种是表中只有某些字段一样,第二种是两行记录完全一样。删除重复记录后的结果也分为2种,第一种是重复的记录全部删除,第二种是重复的记录中只保留最新的一条记录,一般业务中第二种的情况较多。

2.1删除重复记录的方法原理

(1)在Oracle中,每一条记录都有一个rowid,rowid在整个数据库中是唯一的,rowid确定了每条记录是在Oracle中的哪一个数据文件、块、行上。

(2)在重复的记录中,可能所有列的内容都相同,但rowid不会相同,所以只要确定出重复记录中那些具有最大rowid的就可以了,其余全部删除。

2.2删除部分字段重复数据2.2.1重复记录全部删除

想要删除部分字段重复的数据,可以使用下面语句进行删除,下面的语句是删除表中字段1和字段2重复的数据:

DELETEFROM表名 a

WHERE(字段1,字段2)

IN(SELECT字段1,字段2

FROM 表名

GROUPBY字段1,

字段2

HAVINGCOUNT(1)>1)

;

上面的语句非常简单,就是将查询到的数据删除掉。不过这种删除执行的效率非常低,对于大数据量来说,可能会将数据库吊死。所以建议先将查询到的重复的数据插入到一个临时表中,然后进行删除,这样,执行删除的时候就不用再进行一次查询了。如下:

CREATETABLE临时表AS(select字段1,字段2,count(*)from表名groupby字段1,字段2havingcount(*)>1);

上面这句话就是建立了临时表,并将查询到的数据插入其中。下面就可以进行这样的删除操作了:

deletefrom表名 awhere字段1,字段2in(select字段1,字段2from临时表);

这种先建临时表再进行删除的操作要比直接用一条语句进行删除要高效得多。

例子:

DELETEFROMtmp_lhr t

WHERE(t.accesscode,t.lastserviceordercode,t.serviceinstancecode)IN

(SELECT a.accesscode,a.lastserviceordercode,a.serviceinstancecode

FROM tmp_lhr a

GROUPBYa.accesscode,

a.lastserviceordercode,

a.serviceinstancecode

HAVINGCOUNT(1)>1);

2.2.2保留最新的一条记录

假如想保留重复数据中最新的一条记录啊!那怎么办呢?在oracle中,有个隐藏了自动rowid,里面给每条记录一个唯一的rowid,我们如果想保留最新的一条记录,我们就可以利用这个字段,保留重复数据中rowid最大的一条记录就可以了。

一、如何查找重复记录?

SELECT*

FROMTABLE_NAMEA

WHEREROWIDNOT IN(SELECTMAX(ROWID)

FROMTABLE_NAME D

WHEREA.COL1=D.COL1

ANDA.COL2=D.COL2);

二、如何删除重复记录?1、方法1

DELETEFROMTABLE_NAME

WHEREROWIDNOT IN(SELECTMAX(ROWID)

FROMTABLE_NAME D

groupbyd.col1,d.col2);

这种方法最简单!!!

2、方法2

DELETEFROMTABLE_NAMEA

WHEREROWIDNOT IN(SELECTMAX(ROWID)

FROMTABLE_NAME D

WHEREA.COL1=D.COL1

ANDA.COL2=D.COL2);

3、方法3临时表

由此,我们要删除重复数据,只保留最新的一条数据,就可以这样写了:

createtable临时表asselecta.字段1,a.字段2,MAX(a.ROWID)dataidfrom正式表 aGROUPBYa.字段1,a.字段2;

DELETEFROM正式表 a

wherea.rowidNOT IN(SELECTb.dataid

FROM 临时表 b

WHERE a.字段1=b.字段1

anda.字段2=b.字段2);

commit;

例子:

DELETEFROMtmp_lhr t

WHERE t.rowidnotin(SELECTMAX(ROWID)

FROM tmp_lhr a

GROUPBYa.accesscode,

a.lastserviceordercode,

a.serviceinstancecode);

DELETEFROMtmp_lhr t

WHERE t.rowid!=

(SELECTMAX(ROWID)

FROM tmp_lhr a

WHERE a.accesscode=t.accesscode

AND a.lastserviceordercode=t.lastserviceordercode

AND a.serviceinstancecode=t.serviceinstancecode);

2.2.3删除以某个字段为准的记录

----任意保留一条记录

DELETEFROMods_entity_info_full_lhr_01 T

WHERE T.ROWIDNOTIN(SELECTMAX(A.ROWID)

FROM ods_entity_info_full_lhr_01 A

GROUPBYentity_code,

entity_type);

---保留 entity_id 最大的一条记录

DELETEFROMods_entity_info_full_lhr_01 a

WHERE a.rowidNOTIN

(SELECTt.rowid

FROM ods_entity_info_full_lhr_01 t

WHERE(t.entity_code,t.entity_type,t.entity_id)IN

(SELECTentity_code,

entity_type,

MAX(entity_id)

FROM ods_entity_info_full_lhr_01

GROUPBYentity_code,

entity_type));

2.3删除完全重复记录

对于表中两行记录完全一样的情况,可以用下面三种方式获取到去掉重复数据后的记录:

1.selectdistinct*from表名;

2.select * from表名group by列名1,列名2,... having count(*)>1

3.select * from表名a where rowid<(select max(rowid) from表名b where a.列名1=b.列名2 and ...)

2.3.1方法1

DELETEFROMtmp_lhr t

WHERE t.rowidnotin(SELECTMAX(ROWID)

FROM tmp_lhr a

GROUPBYa.accesscode,

a.lastserviceordercode,

a.serviceinstancecode);

2.3.2方法2

可以将查询的记录放到临时表中,然后再将原来的表记录删除,最后将临时表的数据导回原来的表中。如下:

CREATETABLE临时表AS(selectdistinct*from表名);

truncatetable正式表;

insertinto正式表(select*from临时表);

droptable临时表;

2.3.3方法3

DELETEFROMxr_maintainsite E

WHERE E.ROWID>(SELECTMIN(X.ROWID)

FROM xr_maintainsite X

WHERE X.Maintainid=E.Maintainid

AND x.siteid=e.siteid);--这里被更新表中所有字段都需要写全

2.4采用row_number分析函数取出重复的记录然后删除序号大于1的记录

给出一个例子:

delete from aa where rowid in(select rid from(select rowid rid,row_number() over (partition by name order by id) as seq from aa) where seq>1);

3测试案例

SYS@raclhr1> CREATE TABLE T_ROWS_LHR_20160809 AS SELECT * FROM SCOTT.EMP;

Table created.

SYS@raclhr1> INSERT INTO T_ROWS_LHR_20160809 SELECT * FROM T_ROWS_LHR_20160809;

14 rows created.

SYS@raclhr1> COMMIT;

Commit complete.

SYS@raclhr1> INSERT INTO T_ROWS_LHR_20160809 SELECT * FROM T_ROWS_LHR_20160809;

28 rows created.

SYS@raclhr1> COMMIT;

Commit complete.

SYS@raclhr1> SELECT COUNT(1) FROM T_ROWS_LHR_20160809;

COUNT(1)

----------

56

SYS@raclhr1> DELETE FROM T_ROWS_LHR_20160809

2 WHERE ROWID NOT IN (SELECT MAX(ROWID)

3 FROM T_ROWS_LHR_20160809 D

4 group by D.EMPNO,D.ENAME,D.JOB,D.MGR,D.DEPTNO);

42 rows deleted.

SYS@raclhr1> SELECT COUNT(1) FROM T_ROWS_LHR_20160809;

COUNT(1)

----------

14

SYS@raclhr1> COMMIT;

Commit complete.