Sql Server中不常用的表运算符之APPLY(2)
在Sql Server中不常用的表运算符之APPLY(1)中提到,SQL2005中新支持的APPLY的特性:
1.可以直接将表表达式(表值函数或者子查询)作为APPLY语句的右表连接左表。
2.由于使用APPLY是总是先计算左表达式表,所以右表表达式可以使用左表表达式中的列。
3.APPLY主要用于将表值函数运用在右表表达式中表的每一行。
有时也APPLY将一个子查询作为左表表达式。假设我们有以下的两张表
order:
customer:

选出customer C001最近的N个订单可以使用inner join
SELECT TOP (N) CustomName,OrderId,CreateTime
FROM dbo.Customer c
INNER JOIN dbo.[Order] o
ON o.CustomId=c.CustomId
AND o.CustomId='C001'
ORDER BY o.CreateTime DESC
但是要选出每个 customer最近的N个订单(TOP N per Group problem)单单靠inner
join就无能为力了,但是通过CTE和ROW_NUMBER()的辅助可以解决这个问题
WITH OrderedOrders AS
(
SELECT c.CustomName
,o.OrderId
,ROW_NUMBER() OVER (PARTITION BY c.CustomId ORDER BY o.CreateTime DESC) AS CustomOrder
FROM dbo.[Order] AS o
INNER JOIN dbo.Customer AS c
ON o.CustomId = c.CustomId
)
SELECT o1.OrderId,o2.CustomName
FROM dbo.[Order] AS o1
INNER JOIN OrderedOrders AS o2
ON o1.OrderId = o2.OrderId
WHERE o2.CustomOrder <= N
这个查询比较难读,而且不自然。下面来看看使用CROSS APPLY的版本
SELECT TopNOrder.OrderId,c.CustomName
FROM dbo.Customer AS c
CROSS APPLY(
SELECT TOP (N) o.OrderId
FROM dbo.[Order] o
WHERE c.CustomId=o.CustomId
ORDER BY o.CreateTime DESC
) AS TopNOrder
使用APPLY让这个查询看起来更加的自然。
而更自然的方式正如http://technet.microsoft.com/zh-cn/library/ms175156(v=sql.105).aspx提到的
“使用APLLY运算符可以为实现查询操作的外部表表达式返回的每个行调用表值函数。表值函数作为右输入,外部表表达式作为左输入。”
我们应该将TOP N的逻辑放在一个表值函数中,通过APPLY将这个表值函数运用在左输入中的每一行。
下面来创建一个内联的SQL Server函数
CREATE FUNCTION dbo.TopNOrder(@N int,@customerID varchar(50)) RETURNS TABLE
AS RETURN
(
SELECT TOP (@N) o.OrderId
FROM dbo.[Order] AS o
WHERE o.CustomId=@customerID
ORDER BY o.CreateTime DESC
);
然后我们可以这样使用,将返回和上面两个查询一样的结果
SELECT TopNOrder.OrderId,c.CustomName FROM
dbo.Customer AS c
CROSS APPLY dbo.TopNOrder(2,c.CustomId) AS TopNOrder
以上查询当N为2的结果为

此外APPLY还可以用OUTTER来修饰,效果类似于LEFT JOIN。
运行下面这个查询,将没有数据的customer Koo
SELECT TopNOrder.OrderId,c.CustomName FROM
dbo.Customer AS c
OUTER APPLY dbo.TopNOrder(2,c.CustomId) AS TopNOrder
使用OUTER APPLY的结果为

最后,APLLY还有更多可以发掘的用法,在某些时候,可以用APPLY来处理复杂的查询和提高查询的性能。但暂时先在这里告一段落。
详情可以查看以下链接:
http://sqlmag.com/sql-server-2005/sql-server-2005s-apply-part-1
http://sqlmag.com/sql-server-2005/sql-server-2005s-apply-part-2
http://sqlblog.com/blogs/rob_farley/archive/2011/04/13/the-power-of-t-sql-s-apply-operator.aspx
Sql Server中不常用的表运算符之APPLY(2)的更多相关文章
- Sql Server中不常用的表运算符之APPLY(1)
写在这个系列的前面: 就像他们的名字一样,作为一个表运算,他们用来运算左表和右表.JOIN也是一个表运算符,不过他太常用了. APPLY: 将右表表达式应用在左表的每一行上. APPLY是Sql200 ...
- Sql Server中不常用的表运算符之UNPIVOT
在Sql Server中不常用的表运算符之PIVOT中,介绍了PIVOT表运算符,现在来说说与之相对应的另一个表运算符UNPIVOT. 从名字可以看出,这个运算符的作用与PIVOT刚好相反,是将一行的 ...
- Sql Server中不常用的表运算符之PIVOT
PIVOT是SQL Server2005新添加的一个表运算符,作用在于将行转为列. 先来看看他的基本语法: 来自http://technet.microsoft.com/zh-cn/library/m ...
- SQL Server中,常用的全局变量
在SQL Server中,全局变量是一种特殊类型的变量,服务器将维护这些变量的值.全局变量以@@前缀开头,不必进行声明,它们属于系统定义的函数.下表就是SQL Server中一些常用的全局变量. 全局 ...
- SQL Server中查询数据库及表的信息语句
/* -- 本文件主要是汇总了 Microsoft SQL Server 中有关数据库与表的相关信息查询语句. -- 下面的查询语句中一般给出两种查询方法, -- A方法访问系统表,适应于SQL 20 ...
- SQL Server中的临时表和表变量
SQL Server中的临时表和表变量 作者:DrillChina出处:blog2008-07-08 10:05 在SQL Server的性能调优中,有一个不可比拟的问题:那就是如何在一段需要长时间的 ...
- sql Server中临时表与数据表的区别
sql server 中临时表与数据表的区别 1.如何判断临时表和数据表已生成 --如何判断临时表是否已创建--- if exists(select * from tempdb..sysobjects ...
- 转:Sql Server中清空所有数据表中的记录
如果要删除数据表中所有数据只要遍历一下数据库再删除就可以了,清除所有数据我们可以使用搜索出所有表名,构造为一条SQL语句进行清除了,这里我一一给各位同学介绍. 使用sql删除数据库中所有表是不难的 ...
- Sql Server中清空所有数据表中的记录
Sql Server中清空所有数据表中的记录 清空所有数据表中的记录: 代码如下:exec sp_msforeachtable @Command1 ='truncate table ?'删除所有数据 ...
随机推荐
- randomAccess接口
http://www.blogjava.net/lzqdiy/archive/2007/04/22/112578.html
- c++ 调用模板函数时加template什么意思?
看到这么一句stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAll ...
- eclipse插件
#eclipse market http://www.eclipse.org/mpc/archive.php http://download.eclipse.org/mpc/mars/ #文件路径 p ...
- XUtils 3 使用
源代码:https://github.com/wyouflf/xUtils 基本使用:http://blog.csdn.net/abc6368765/article/details/50699334 ...
- Windows下Python连接数据库(mysql, mongodb)
一 实验平台 1 os: win7 64位旗舰版sp1 2 python: 2.7.10 x64 二 连接数据库 1 连接 mysql数据库 (1)下载mysql(5.6.25-winx64) 建议下 ...
- SSH配置免密码登陆
1.使用SSH-keygen,然后一路回车使之生成id_rsa何id_rsa.pub文件,id_rsa.pub为公匙文件. 2.使用命令:cat ~/.ssh/id_rsa.pub >> ...
- [Linux编程] module_param()函数学习笔记
在读TCP cubic源码中,遇到了module_param(),网上查到的资料如下: 在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递 ...
- 尚学堂Spring视频教程(五):Spring AOP
在第一节中,我们自己模拟了一个Spring,实现一个保存用户的操作,假如现在有一个需求,在保存的时候记录日志,该怎么做呢? 暂且将记录日志操作就简单的变为在保存用户前输出一句话“save start. ...
- 6410实现网卡(DM9000A)收发功能及ARP协议实现
1. 网卡硬件结构(DM9000A) 网卡的实质就是MAC通过MII接口控制PHY的过程. MAC主要负责数据帧的构建.数据差错检查.传送控制等. PHY是物理接口收发器,属于物理层,当它收到MAC过 ...
- oracle查询中文数据出现乱码
首先,在oracle中,输入select userenv('language') from dual,查询出oracle使用的编码方式,我的是SIMPLIFIED CHINESE_CHINA.ZHS1 ...