学习 APPLY 和 TOP 用法

本文通过一个具体的例子展示了如何使用SQL Server中的APPLY和TOP子句来筛选指定数量的记录。具体应用场景为从学生表中根据班级选择指定数量的高分学生。

-- 学习 APPLY 和 TOP 用法

-----------------------------------------------------------------------
--
SQL 版本:
--
-----------
--
Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86)
--
    Oct 14 2005 00:33:37
--
    Copyright (c) 1988-2005 Microsoft Corporation
--
    Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 3)
--
---------------------------------------------------------------------

--> 创建测试表
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

-- 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    ---排序


/*
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
*/
 

### ### SQL 中 `OUTER APPLY` 的用法详解及示例 `OUTER APPLY` 是 SQL Server 中的一个运算符,用于将左表的每一行与右表表达式(可以是一个表、子查询、函数等)进行匹配,并返回左表的所有行,即使右表没有匹配的记录。在右表没有匹配的情况下,右表的列将返回 `NULL` 值。这种行为与 `LEFT JOIN` 类似,但 `OUTER APPLY` 更加灵活,因为它支持右表表达式依赖于左表的字段,从而实现更复杂的查询逻辑[^2]。 #### `OUTER APPLY` 的特点 - **返回左表所有行**:无论右表是否有匹配,左表的每一行都会出现在结果集中。 - **支持相关子查询**:右表表达式可以引用左表的列,形成一种“行级”处理机制。 - **右表为空时返回 NULL**:当右表表达式没有结果时,右表的列在结果集中显示为 `NULL`。 #### `OUTER APPLY` 与 `LEFT JOIN` 的区别 虽然 `OUTER APPLY` 与 `LEFT JOIN` 在某些情况下可以实现相同的结果,但它们的处理方式不同: - `LEFT JOIN` 是基于两个表之间的连接条件进行匹配。 - `OUTER APPLY` 是为左表的每一行执行右表表达式,类似于逐行处理。 #### 示例说明 假设有两张表:`Categories` `Products`,结构如下: ```sql -- Categories 表 categroyid | categoryname ------------------------ 1 | Beverages 2 | Condiments 3 | Confections -- Products 表 productid | productname | categoryid ----------------------------------- 101 | Tea | 1 102 | Coffee | 1 103 | Mustard | 2 ``` 现在我们想查询所有分类,并列出每个分类下的产品数量,即使某些分类下没有产品。可以使用 `OUTER APPLY` 实现如下: ```sql SELECT c.categroyid, c.categoryname, p.productcount FROM Categories c OUTER APPLY ( SELECT COUNT(*) AS productcount FROM Products p WHERE p.categoryid = c.categroyid ) p; ``` **结果如下:** ``` categroyid | categoryname | productcount ---------------------------------------- 1 | Beverages | 2 2 | Condiments | 1 3 | Confections | 0 ``` 在这个例子中,`OUTER APPLY` 为每个分类执行一次子查询,统计该分类下的产品数量。即使 `Confections` 分类下没有产品,它仍然出现在结果集中,且 `productcount` 为 `0`。 #### 更复杂的 `OUTER APPLY` 示例 假设我们有一个函数 `GetTopProductsByCategory(@categoryid INT)`,它可以返回某个分类下销量最高的产品。我们想列出所有分类,并显示每个分类下销量最高的产品(如果没有产品,则显示 `NULL`): ```sql SELECT c.categroyid, c.categoryname, t.productname, t.sales FROM Categories c OUTER APPLY ( SELECT TOP 1 productname, sales FROM Products p WHERE p.categoryid = c.categroyid ORDER BY sales DESC ) t; ``` 这个查询会为每个分类调用一次子查询,返回销量最高的产品。如果没有产品,则 `productname` `sales` 为 `NULL`。 #### `OUTER APPLY` 的适用场景 - **动态子查询**:当右表表达式需要根据左表的每一行动态生成时。 - **TOP N 每组**:例如查询每个分类中销量最高的产品。 - **复杂计算**:右表可以是一个函数或复杂的子查询,处理左表的每一行数据。 - **保持左表完整性**:即使右表没有匹配,仍然需要返回左表的数据。 #### `OUTER APPLY` 与 `CROSS APPLY` 的区别 - `CROSS APPLY` 只返回左表中与右表表达式匹配的行,类似于 `INNER JOIN`。 - `OUTER APPLY` 返回左表的所有行,即使右表没有匹配,此时右表列返回 `NULL`,类似于 `LEFT JOIN`[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值