2010年10月15日 星期五

SQL_刪除資料表的相同資料

系統在設計資料庫時,有時候會出現一種流水帳的設計,所謂流水帳的設計就是我們把全部更改的內容都不斷新增進資料表內,在需要查詢的時候才使用SQL語法來篩選需要的內容,當然透過篩選就可以做出很多不一樣的變化,可能單純只是想知道最大最小值、最新最舊值,或是某個時間區間內的數值變化等等。

而這樣的流水帳資料表會有兩種需求,第一個想法就是我才不理他,就讓他一直記,一直記,一直一直一直記下去;另一種就是資料表將因為某些原因,去刪除某屬性相同的資料。舉例來說:

上面這張資料表以ID為主鍵,分別記載各區域不同時間的數值,也就是A區域在10月13日為20,到了10月15日為30。有時我們會有一個需求:「我希望以AreaName這個欄位為基礎只留下一份各區域的記載資料」。

那麼,要怎麼達成呢?需求是要留下每一個最新版本的資料,單純的想法就是我們要刪除那些舊的,而舊的資料可能有很多筆,我們或許無法一一列出這些舊有資料,所以應當先篩出MAX(ID)的資料,再反向取得其他舊資料,最後刪掉他們!

所以組SQL語法的順序應該是:
1. 建立依照AreaName欄位選取最大ID的列表的子查詢。(請參考舊文章)

2. 利用上述子查詢以反向選取的方式取得"AreaName有重複的舊資料"(利用NOT IN)。

3. 刪掉第二步驟所列出的子查詢項目。

執行結果:

當然,這種流水帳的資料表可能不會只留下最新資料,我們也許會去刪除5年以前的舊資料,那麼可能會問"如果刪除5年以前的舊資料就直接下刪除2005年以前資料的SQL語法就好了呀?",原因是如果你有1000個區域,而這五年以來只有50個區域更新過,那如果直接刪除2005以前的資料,將會造成有另外50筆的唯一資料一併刪除,造成......不知道會怎麼樣的事情發生。XD

所以我們再增加兩筆A區域的資料,一個為2007年,一個為2004年的資料,來進行上述的刪除動作:

也就是多增加一個時間的篩選,讓他篩出既是舊的而且又在2005年1月1日以前的資料,然後刪掉。


最後還是方便複製,貼上語法:
delete dbo.Table1 where ID in
(Select ID from dbo.Table1 where ID Not IN
(Select MAX(ID) as ID from dbo.Table1 group by AreaName)
AND dbo.Table1.Date <='2005/1/1')

第1句:刪除ID有被第2、3句子查詢所查出的資料。
第2句:列出不被第3句子查詢所查出的項目。
第3句:列出以AreaName群組的最大ID值。
第4句:額外的判斷語句。

沒有留言:

張貼留言