利用SQL05特性刪除表中重復數據

作者: 姜敏  來源: 博客園  發布時間: 2009-12-09 10:29  閱讀: 1362 次  推薦: 0   原文鏈接   [收藏]  

  問題:一個表有自增的ID列,表中有一些記錄內容重復,也就是說這些記錄除了ID不同之外,其他的信息都相同。需要把重復的記錄保留一條,剩下的刪除。

  這種需求一般開發人員都會,我這里寫出兩個版本。

  版本一:由于記錄有自增列,所以自增列可以做為記錄的唯一標識,由此可見,重復的記錄的自增ID是一個遞增關系,這里我們可以只保留ID最小的那條記錄,其它的全部刪除。利用一個嵌套語句就非常容易寫出下面的SQL。其中的sname,saddress是記錄除了ID外的所有列。

DELETE  FROM a
WHERE   id NOT IN ( SELECT  MIN(id)
                    FROM    a
                    GROUP BY sname,
                            saddress )

  版本二:充分利用SQL05的幾個比較實用的特性。這里先簡單說說要用到的幾個特性。詳細用法可到網上搜索下。

  1:ROW_NUMBER,它的作用就是用來生成行號,默認是從1開始。

  2:公用表表達式(CTE),我這里并不會利用它的遞歸,而是用它來簡化嵌套查詢及對表自身引用功能。CTE的語法如下:

[ WITH <common_table_expression> [ ,n ] ]
<common_table_expression>::=
        expression_name [ ( column_name [ ,n ] ) ]
    AS
        ( CTE_query_definition )

 

  說明:

  1>CTE在某種程序上相當表變量或者臨時表的功能。但比起表變量來說它最大的優勢是對自身的引用,CTE語句后面緊跟的select ,update,delete等,操作的結果都會直接反應的實際物理表中。相比臨時表,最大優勢無非是性能,臨時表實際是一張物理存在的表,在對它進行操作時,會產生額外的IO開銷以及管理上的開銷

  2>CTE語法后面需要直接跟上使用CTE的相關語句select ,update,delete等,否則CTE會失效,下面的語句是錯誤的:

代碼
WITH   b AS ( SELECT   ROW_NUMBER() OVER ( PARTITION BY sname, saddress ORDER BY sname, saddress ) AS rn,
                        
*
               FROM     a
             )
    DELETE  FROM b
    WHERE   rn 
> 1
 SELECT * from a
 SELECT 
* FROM b WHERE rn>1

  3:PARTITION BY,分區函數。和聚合函數不同的地方在于它能返回一個分組中的多條記錄,聚合函數一般只有一條反映統計值的記錄,partition  by用于給結果集分組,如果沒有指定那么它把整個結果集作為一個分組 。

  經過上面的三個關鍵字的介紹后,下面給出三者相結合后的結果。

代碼
WITH   b AS ( SELECT   ROW_NUMBER() OVER ( PARTITION BY sname, saddress ORDER BY sname, saddress ) AS rn,
                        
*
               FROM     a
             )
    DELETE  FROM b
    WHERE   rn 
> 1

  版本一和版本二比較:
      1:版本二更加容易閱讀。

  2:版本二性能較版本一強。我們可以通過以以信息來看。可以看到版本一會發生兩次表掃描。

代碼
Table 'a'. Scan count 2, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 
'Worktable'. Scan count 1, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(
0 row(s) affected)
Table 
'a'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(
0 row(s) affected)
 
0
0
 
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()