你真的會玩SQL嗎?系列目錄html
本章預先想寫一些Top和Apply基本的用法,但好像沒什麼意義,因此刪掉了一些無用的東西,只留下幾個示例,以保證系列的完整性。
Top和Apply解決的常見問題,如返回每一個僱員的3個最新訂單,訂單的時間越新優先級就越高,但還須要引入一個決勝屬性,以肯定時間楨的訂單的優先級,如可用id做爲決勝屬性。這裏提供的解決方案比其它方案要簡單得多,且執行速度更快。
返回每一個僱員的3個最新訂單:
SELECT empid , orderid , custid , orderdate , requireddate FROM sales.orders AS o1 WHERE orderid IN ( SELECT TOP 3 orderid FROM sales.orders AS o2 WHERE o2.empid = o1.empid ORDER BY orderdate DESC , orderid DESC )
運用APPLY解決:
SELECT e.empid , a.orderid , a.custid , a.orderdate , a.requireddate FROM hr.employees AS e CROSS APPLY ( SELECT TOP 3 orderid , custid , orderdate , requireddate FROM sales.orders AS o WHERE o.empid = e.empid ORDER BY orderdate DESC , orderid DESC ) AS a
先掃描employees 得到empid,對每一個empid值對orders表查詢返回 該僱員的3個最新訂單。這裏能夠返回多個屬性。
還有一種解決方案在特定狀況下居然比使用APPLY運算符的方法還要快,使用ROW_NUMBER函數。先爲每一個訂單計算行號,按empid進行分區,並按orderdate desc, orderid desc 順序排序。而後在外部查詢中,只篩選行號小於或等於3的行。
以下:
SELECT orderid , custid , orderdate , requireddate FROM ( SELECT orderid , custid , orderdate , requireddate , ROW_NUMBER() OVER ( PARTITION BY empid ORDER BY orderdate DESC , orderid DESC ) AS rownum FROM sales.orders ) AS d WHERE rownum <= 3
練習:
從學生表中選取對應班級的前num名學生成績
--顯示結果 /* bj xh name cj ---------- ---- ---------- ----------- 一班 A006 A6 100 一班 A005 A5 99 一班 A001 A1 89 一班 A002 A2 89 二班 B001 B7 100 二班 B001 B6 99 二班 B001 B9 97 二班 B001 B8 90 二班 B001 B5 88 */
-- 建立測試表 declare @student table( ---學生表 bj varchar(10), -- 班級 xh char(4), -- 學號 name varchar(10), -- 姓名 cj int) -- 成績 declare @tj table( ---統計表 bj varchar(10), -- 班級 num int) -- 人數 :從學生表中選取對應班級的前num名學生成績 set nocount on -- 添加測試數據 insert @student select '一班' ,'A001','A1',89 insert @student select '一班' ,'A002','A2',89 insert @student select '一班' ,'A003','A3',59 insert @student select '一班' ,'A004','A4',80 insert @student select '一班' ,'A005','A5',99 insert @student select '一班' ,'A006','A6',100 insert @student select '一班' ,'A007','A7',82 insert @student select '二班' ,'B001','B1',19 insert @student select '二班' ,'B001','B2',81 insert @student select '二班' ,'B001','B3',69 insert @student select '二班' ,'B001','B4',86 insert @student select '二班' ,'B001','B5',88 insert @student select '二班' ,'B001','B6',99 insert @student select '二班' ,'B001','B7',100 insert @student select '二班' ,'B001','B8',90 insert @student select '二班' ,'B001','B9',97 insert @tj select '一班',3 insert @tj select '二班',5
參考SQL:
-- 2005.T-SQL select t.bj,s.xh,s.name,s.cj from @tj t cross apply ( SELECT TOP(t.num) with ties -- 加 with ties,一班將選出4我的(2我的並列第三名) xh,name,cj from @student where t.bj=bj -- 加where 功能相似於 inner join ;不加相似於 cross join order by cj desc )s order by case when t.bj='一班' then 1 else 2 end asc,s.cj desc,s.xh asc ---排序