1. 程式人生 > >oracle中按指定欄位排序刪除重複記錄

oracle中按指定欄位排序刪除重複記錄

       今天看了一下專案上的DBA針對某一模組中的業務寫的儲存過程,裡面資料清洗的過程中時常會進行排重操作,自己總結了一下oracle中排重的思路

1,使用rowid來作為限制條件排重

rowidrownum的區別
兩者都是偽列,rowid是物理結構上的,而rownum是邏輯結構上的,rowid是用於定位資料庫中某條記錄的相對唯一的地址

通常情況下資料在插入資料庫中時就已經被確定且唯一,使用rowid可以定位該行的實體地址資訊,rownum是動態的,查詢   語句的不同,rownum是不同的,當查詢語句為以empno升序時SMITH的rownum是1,而當以降序排列時,SMITH的    rownum就是14,由於rowid的唯一性,所以使用rowid來實現排重,即在根據條件查詢後的結果上加上rowid<>1就行了

2,使用row_number() over(partition by column1 order by column2) 來實現排重

上面這句語句的意思是在以column1分組後並且組內以column2排序的條件下分級:

over:  在什麼條件之上。
partition by e.deptno:  按部門編號劃分(分割槽)。
order by e.sal desc:  按工資從高到低排序(使用rank()/dense_rank()/row_number() 時,必須要帶order by否則非法);
rank()/dense_rank()/row_number() :  分級
整個語句的意思就是:
在按部門劃分的基礎上,按工資從高到低對僱員進行分級,“級別”由從小到大的數字表示(最小值一定為1)
row_number(),rank(),dense_rank()的區別:
在'分級時',如果有兩個記錄按照當前的篩選條件是相同的排名,那麼,rank()會有兩個分級為一 的記錄,接下來為第三級,

跳躍排序,而dense_rank()則是有兩個第一級後接下來還是第二級,即連續排序,row_number()則是第一級後會按照預設的規則排序後顯示第二級

舉例說明:

1,以部門編號分組,並且組內以工資降序排列後分級:

select e.deptno, e.empno,e.ename,e.sal,rank() over(partition by deptno order by sal desc) from emp e;

結果如下:

部門號為20 的部門中有兩個工資為3500的員工,在分級時使用的是rank(),所以兩個3500的分級都是1,接著是3

2,使用dense_rank() 分級

select e.deptno, e.empno,e.ename,e.sal,dense_rank() over(partition by deptno order by sal desc) from emp e;

結果如下:


兩個工資為3500的員工的分級依舊是1,但是接下來的員工的分級是2

3,使用row_number()分級

select e.deptno, e.empno,e.ename,e.sal,row_number() over(partition by deptno order by sal desc) from emp e;

結果如下:


按照員工的工資來分級出現重複後,會按照預設的順序來分級,但是不會出現相同的級別

我們就可以利用row_number()的這個特性來

delete from t_visit_customer p where p.rowid in (
select e.rowid from 
(select t.rowid,row_number() over(partition by t.credential_no order by t.is_gen_self desc nulls last) rw
from t_visit_customer t where t.branch_code = in_branch_code) e where e.rw<>1;
) and p.branch_code = in_branch_code;

可以分解為以下三個步驟:

-- 使用row_number()  over(partiton by ...)實現排重
-- 其中t_visit_customer為表名,in_branch_code為儲存過程中的輸入引數
-- 1,查詢記錄行的rowid和使用row_number() over(partition by...)來查詢對應分組條件和排序條件下的順序
select t.rowid,row_number() over(partition by t.credential_no order by t.is_gen_self desc nulls last) rw
from t_visit_customer t where t.branch_code = in_branch_code;
-- 2,查詢重複的資料的rowid
select e.rowid from 
(select t.rowid,row_number() over(partition by t.credential_no order by t.is_gen_self desc nulls last) rw
from t_visit_customer t where t.branch_code = in_branch_code) e where e.rw<>1;
-- 3,刪除原表中rowid為重複資料的rowid的列進行排重
delete from t_visit_customer p where p.rowid in (
select e.rowid from 
(select t.rowid,row_number() over(partition by t.credential_no order by t.is_gen_self desc nulls last) rw
from t_visit_customer t where t.branch_code = in_branch_code) e where e.rw<>1;
) and p.branch_code = in_branch_code;

即:去除公司程式碼為in_branch_code的公司中credential_no相同的記錄並且留下的是is_gen_self最大的記錄

小弟是菜鳥,如有錯誤,歡迎大佬們指教!