天天看點

你真的會玩SQL嗎?冷落的Top和Apply

你真的會玩SQL嗎?系列目錄

你真的會玩SQL嗎?之邏輯查詢處理階段

你真的會玩SQL嗎?和平大使 内連接配接、外連接配接

你真的會玩SQL嗎?三範式、資料完整性

你真的會玩SQL嗎?查詢指定節點及其所有父節點的方法

你真的會玩SQL嗎?讓人暈頭轉向的三值邏輯

你真的會玩SQL嗎?EXISTS和IN之間的差別

你真的會玩SQL嗎?無處不在的子查詢

你真的會玩SQL嗎?Case也瘋狂

你真的會玩SQL嗎?表表達式,排名函數

你真的會玩SQL嗎?簡單的 資料修改

你真的會玩SQL嗎?你所不知道的 資料聚合

你真的會玩SQL嗎?透視轉換的藝術

你真的會玩SQL嗎?冷落的Top和Apply

你真的會玩SQL嗎?實用函數方法彙總

你真的會玩SQL嗎?玩爆你的資料報表之存儲過程編寫(上)

你真的會玩SQL嗎?玩爆你的資料報表之存儲過程編寫(下)

本章預先想寫一些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    ---排序
       

作者:歡醉

公衆号【一個碼農的日常】 技術群:319931204 1号群: 437802986 2号群: 340250479

出處:http://zhangs1986.cnblogs.com/

碼雲:https://gitee.com/huanzui

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

Top