在對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作過(guò)程中我們可能會(huì)遇到這種情況,表中的數(shù)據(jù)可能重復(fù)出現(xiàn),使我們對(duì)數(shù)據(jù)庫(kù)的操作過(guò)程中帶來(lái) 讀諸 多不便,那么怎么刪除這些重復(fù)沒(méi)有用的數(shù)據(jù)呢 ?
創(chuàng)新互聯(lián)網(wǎng)站建設(shè)由有經(jīng)驗(yàn)的網(wǎng)站設(shè)計(jì)師、開(kāi)發(fā)人員和項(xiàng)目經(jīng)理組成的專業(yè)建站團(tuán)隊(duì),負(fù)責(zé)網(wǎng)站視覺(jué)設(shè)計(jì)、用戶體驗(yàn)優(yōu)化、交互設(shè)計(jì)和前端開(kāi)發(fā)等方面的工作,以確保網(wǎng)站外觀精美、網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站易于使用并且具有良好的響應(yīng)性。
平時(shí)工作中可能會(huì)遇到當(dāng)試圖對(duì)庫(kù)表中的某一列或幾列創(chuàng)建唯一索引時(shí),系統(tǒng)提示 ORA-01452 :不能創(chuàng)建唯一索引,發(fā)現(xiàn)重復(fù)記錄。
重復(fù)的數(shù)據(jù)可能有這樣兩種情況 : 第一種 是 表中只有某些字段一樣,第二種是兩行記錄完全一樣 。刪除重復(fù)記錄后的結(jié)果也分為 2 種, 第一種 是重復(fù)的記錄全部刪除 ,第二種是 重復(fù)的記錄中只保留最新的一條記錄,一般業(yè)務(wù)中第二種的情況較多。
(1) 在Oracle 中,每一條記錄都有一個(gè)rowid ,rowid 在整個(gè)數(shù)據(jù)庫(kù)中是唯一的,rowid 確定了每條記錄是在Oracle 中的哪一個(gè)數(shù)據(jù)文件、塊、行上。
(2) 在重復(fù)的記錄中,可能所有列的內(nèi)容都相同,但rowid 不會(huì)相同,所以只要確定出重復(fù)記錄中那些具有最大rowid 的就可以了,其余全部刪除。
想要?jiǎng)h除 部分 字段 重復(fù)的數(shù)據(jù),可以使用下面語(yǔ)句進(jìn)行刪除 ,下面的語(yǔ)句是刪除 表中字段1 和字段2 重復(fù)的數(shù)據(jù) :
DELETE FROM 表名 a
WHERE ( 字段1 , 字段2 )
IN ( SELECT 字段1 , 字段2
FROM 表名
GROUP BY 字段1 ,
字段2
HAVING COUNT ( 1 ) > 1 )
;
上面的語(yǔ)句非常簡(jiǎn)單,就是將查詢到的數(shù)據(jù)刪除掉。不過(guò)這種刪除執(zhí)行的效率非常低,對(duì)于大數(shù)據(jù)量來(lái)說(shuō),可能會(huì)將數(shù)據(jù)庫(kù)吊死。所以建議先將查詢到的重復(fù)的數(shù)據(jù)插入到一個(gè)臨時(shí)表中,然后進(jìn)行刪除,這樣,執(zhí)行刪除的時(shí)候就不用再進(jìn)行一次查詢了。如下:
CREATE TABLE 臨時(shí)表 AS ( select 字段1 , 字段2 , count (*) from 表名 group by 字段1 , 字段2 having count (*) > 1 ) ;
上面這句話就是建立了臨時(shí)表,并將查詢到的數(shù)據(jù)插入其中。下面就可以進(jìn)行這樣的刪除操作了:
delete from 表名 a where 字段1 , 字段2 in ( select 字段1,字段2 from 臨時(shí)表 );
這種先建臨時(shí)表再進(jìn)行刪除的操作要比直接用一條語(yǔ)句進(jìn)行刪除要高效得多。
例子:
DELETE FROM tmp_lhr t
WHERE ( t.accesscode , t.lastserviceordercode , t.serviceinstancecode ) IN
( SELECT a.accesscode , a.lastserviceordercode , a.serviceinstancecode
FROM tmp_lhr a
GROUP BY a.accesscode ,
a.lastserviceordercode ,
a.serviceinstancecode
HAVING COUNT ( 1 ) > 1 );
假如 想保留重復(fù)數(shù)據(jù)中最新的一條記錄啊! 那怎么辦呢? 在oracle 中,有個(gè)隱藏了自動(dòng)rowid ,里面給每條記錄一個(gè)唯一的rowid ,我們?nèi)绻氡A糇钚碌囊粭l記錄,我們就可以利用這個(gè)字段,保留重復(fù)數(shù)據(jù)中r o wid 最大的一條記錄就可以了。
一、 如何查找重復(fù)記錄?
SELECT *
FROM TABLE_NAME A
WHERE ROWID NOT IN ( SELECT MAX ( ROWID )
FROM TABLE_NAME D
WHERE A .COL1 = D.COL1
AND A .COL2 = D.COL2 );
二、 如何刪除重復(fù)記錄? 1、 方法1
DELETE FROM TABLE_NAME
WHERE ROWID NOT IN ( SELECT MAX ( ROWID )
FROM TABLE_NAME D
group by d.col1 , d.col2 );
這種方法最簡(jiǎn)單?。?!
2、 方法2
DELETE FROM TABLE_NAME A
WHERE ROWID NOT IN ( SELECT MAX ( ROWID )
FROM TABLE_NAME D
WHERE A .COL1 = D.COL1
AND A .COL2 = D.COL2 );
3、 方法3 臨時(shí)表
由此,我們要?jiǎng)h除重復(fù)數(shù)據(jù),只保留最新的一條數(shù)據(jù),就可以這樣寫了:
create table 臨時(shí)表 as select a.字段1 , a.字段2 , MAX ( a.ROWID ) dataid from 正式表 a GROUP BY a.字段1 , a.字段2 ;
DELETE FROM 正式 表 a
where a.rowid NOT IN ( SELECT b.dataid
FROM 臨時(shí)表 b
WHERE a.字段1 = b.字段1
and a.字段2 = b.字段2 );
commit ;
例子:
DELETE FROM tmp_lhr t
WHERE t.rowid not in ( SELECT MAX ( ROWID )
FROM tmp_lhr a
GROUP BY a.accesscode ,
a.lastserviceordercode ,
a.serviceinstancecode );
DELETE FROM tmp_lhr t
WHERE t.rowid !=
( SELECT MAX ( ROWID )
FROM tmp_lhr a
WHERE a.accesscode = t.accesscode
AND a.lastserviceordercode = t.lastserviceordercode
AND a.serviceinstancecode = t.serviceinstancecode );
----任意保留一條記錄
DELETE FROM ods_entity_info_full_lhr_01 T
WHERE T.ROWID NOT IN ( SELECT MAX ( A.ROWID )
FROM ods_entity_info_full_lhr_01 A
GROUP BY entity_code ,
entity_type );
---保留 entity_id 最大的一條記錄
DELETE FROM ods_entity_info_full_lhr_01 a
WHERE a.rowid NOT IN
( SELECT t.rowid
FROM ods_entity_info_full_lhr_01 t
WHERE ( t.entity_code , t.entity_type , t.entity_id ) IN
( SELECT entity_code ,
entity_type ,
MAX ( entity_id )
FROM ods_entity_info_full_lhr_01
GROUP BY entity_code ,
entity_type ));
對(duì)于表中兩行記錄完全一樣的情況,可以用下面 三種方式 獲取到去掉重復(fù)數(shù)據(jù)后的記錄:
1. select distinct * 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 ...)
DELETE FROM tmp_lhr t
WHERE t.rowid not in ( SELECT MAX ( ROWID )
FROM tmp_lhr a
GROUP BY a.accesscode ,
a.lastserviceordercode ,
a.serviceinstancecode );
可以將查詢的記錄放到臨時(shí)表中,然后再將原來(lái)的表記錄刪除,最后將臨時(shí)表的數(shù)據(jù)導(dǎo)回原來(lái)的表中。如下:
CREATE TABLE 臨時(shí)表 AS ( select distinct * from 表名 );
truncate table 正式表 ;
insert into 正式表 ( select * from 臨時(shí)表 );
drop table 臨時(shí)表 ;
DELETE FROM xr_maintainsite E
WHERE E.ROWID > ( SELECT MIN ( X.ROWID )
FROM xr_maintainsite X
WHERE X.Maintainid = E.Maintainid
AND x.siteid = e.siteid ); -- 這里被更新表中所有字段都需要寫全
給出一個(gè)例子:
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 測(cè)試案例
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.