分類
Database

用CTE來取出指定筆數 – SQL2005

SQL2005中有個CTE (Common Table Expression)功能十分強大, 可以用來做遞迴式的參考, 藉以達成複雜的查詢邏輯並簡化查詢指令, 是 SQL2005的一個新的重要功能.

在使用 MySQL 時, 可以容易地利用 limit m, n 的語法進行指定筆數的取得, 然而在 SQL Server這裡一直沒有這種功能. 這樣的需求通常是應用在分頁上會用到. 不過SQL Server可以利用 ADO存取方式內的分頁方法來進行, 也就避開了這個問題. 但無論如何, 仍是將所有的資料帶到查詢端(如客戶端或是中間層)後, 再進行分頁, 效能仍然不佳.

以往在 SQL2000之前要達成這樣的功能, 通常是配合temp table並配合 identity 欄位達成, 但是仍需要將所有資料從第一筆到第 n 筆寫入 temp table 後, 再取 top 的方式來操作, 效能仍舊不理想.

MySQL 由於沒有查詢端的存取模型好用, 所以分頁通常都由程式自己來, 在查詢指令下 limit 後, 即可將要指定的分頁資料傳回, 不會浪費 network io 在傳遞資料上, 所以是蠻好的一個功能. 現在我們看看 CTE 要如何完成這樣的一件事.

單靠 CTE 是無法完成的, 還需要一個行號函數 ROW_NUMBER() 來協助, 以下為一個 sample:

查詢訂單資料表(orders), 依訂單金額由大而小排序, 取出第301到第400筆資料:

MySQL:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
select orderid, orderdate, orderamount from orders order by orderamount desc limit 301, 400
select orderid, orderdate, orderamount from orders order by orderamount desc limit 301, 400
select orderid, orderdate, orderamount from orders order by orderamount desc limit 301, 400

SQL2005:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
with myorder as (
select row_number() over (order by orderamount desc) as sn, orderid, orderdate, orderamount from orders )
select orderid, orderdate, orderamount from myorder where sn between 301 and 400
with myorder as ( select row_number() over (order by orderamount desc) as sn, orderid, orderdate, orderamount from orders ) select orderid, orderdate, orderamount from myorder where sn between 301 and 400
with myorder as (
select row_number() over (order by orderamount desc) as sn, orderid, orderdate, orderamount from orders )
select orderid, orderdate, orderamount from myorder where sn between 301 and 400

看起來雖然指令長了一些, 但是確實能達成查詢指定筆數的功能, 也大幅提高效能了, 如此一來, 利用 CTE 加上 row_number() 函數後, SQL2005 也能和 MySQL 一樣有指定筆數的查詢方法囉.

CTE 的功能很強大, 之後再介紹遞迴式查詢的強大功能囉!

參考資料:
http://msdn2.microsoft.com/zh-tw/library/ms175972.aspx

繼續閱讀:
http://blog.roodo.com/rocksaying/archives/2346392.html

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Buy Me A Coffee
Thank you for visiting. You can now buy me a coffee!