Oracle用rowid刪除同一張表的重復記錄


  經常有這樣一個業務場景,我們在同一張表中有重復的記錄,我們要刪除重復的記錄,這篇文章就是用來解決這個問題的,用的方法是我目前遇到的效率最高的方法(如果有更好的方法歡迎網友提供)。這個方法會用到了rowid,下面簡單介紹一下rowid的定義

1、ROWID定義

ROWID:數據庫中行的全局唯一地址

對於數據中的每一行,rowid偽列返回行的地址。rowid值主要包含以下信息:

  • 對象的數據對象編號
  • 該行所在的數據文件中的數據塊
  • 該行中數據塊的位置(第一行是0)
  • 數據行所在的數據文件(第一個文件是1)。該文件編號是相對於表空間。

通常來說,一個rowid值唯一標識數據中的一行。然而,存儲在同一聚簇中不同的表可以有相同的rowid。

2、實現的方法

方法一:

DELETE FROM hr.employees
WHERE ROWID IN (
                 SELECT ROWID
                 FROM (
                        SELECT first_name,
                               last_name,
                               ROWID,
                               ROW_NUMBER() OVER(PARTITION BY first_name,last_name ORDER BY employee_id) AS staff_row --按照保留的唯一字段進行分區,取row_number
                               FROM hr.employees
                      )
                 WHERE staff_row > 1
               );

 

  乍一看,我勒個去,這個是什么東西要,這么難懂!!沒關系,下面給您解釋一下,就很好懂了。

  針對的是oracle內置的示例用戶hr中的employees這張表,我們希望的是first_name和last_name沒有重復的項(如果你的業務需要時別的話可以相應的轉換,如在成績表中的學號就是唯一個,就partition by學號),所以對這兩個字段進行partition  by

  在子查詢的子查詢中我們選擇的主要目的是rowid和row_number(first_name和last_name只是用來輔助理解加進去的字段);子查詢中我們選擇了row_number > 1的rowid,這樣的話按照first_name和last_name分組中每一個分組只有一條記錄沒有被選擇;最外面的delete就直接把選擇出來的rowid進行了刪除。至此完成了hr.employees對於first_name和last_name的去重。

  有朋友會說,媽蛋這太難理解了吧!在這種情況下,往往有方法二~~~

方法二:

DELETE FROM hr.employees t1
WHERE t1.ROWID NOT IN (
                       SELECT MIN(t2.ROWID)
                       FROM hr.employees t2
                       GROUP BY t2.employee_id --按照想要唯一保留的字段進行分組
                      );

  這個明顯就比方法一好多了,子查詢中我們先選除了rowid,然后按照我們想要保留的唯一字段進行分組,並取每組最小的rowid(注意是子查詢表的rowid);然后在用not in刪除除開最小的rowid以外的所有記錄

  怎么樣,這個方法是不是瞬間解決並且非常好理解?但是你以為這樣就結束了?no no no

方法三:

DELETE FROM hr.employees t1
WHERE t1.rowid > (
                   SELECT MIN(t2.rowid)
                   FROM hr.employees t2
                   WHERE t1.employee_id = t2.employee_id --按照想要唯一保留的字段進行匹配
                 );

  這個方式看起來和方法二差不多,但是想要說的是,他用的是連接,他用的是連接,不敢說連接一定比group by快,但是基本上不會輸group by,而且在一般的情況下也是最快的了。而且外層的">"可以用到索引,就是各種快。

  方法也同樣說一下,子查詢中按照要保留的字段對t1和t2進行關聯,然后選擇出最小的rowid(注意是子查詢表的rowid),然后在外層用">"只保留每個匹配結果最小的一條記錄。然后就瞬間刪除重復的記錄

 

  此時有朋友以為這是最快的辦法了,但是,我想說,不是,不是!請看下面最快的方法!

--騙一下你的,上面已經是本人接觸到的最快的方法了
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM