前言

其实有些新的特性在SQL Server早就已经出现过,但是若非系统的去学习数据库你会发现在实际项目中别人的SQL其实是比较复杂的,其实利用新的SQL Server语法会更加方便和简洁,从本节开始我们将讲述一些SQL Server中早已出现的新语法,简短的内容,深入的理解,Always to reivew the basics。

初探APPLY运算符

APPLY运算符是一个非常强大的表运算符,但是APPLY不是标准的,相对应的标准叫做LATERAL,但是此标准并未在SQL Server中实现。像所有表运算符一样,该运算符用于查询的FROM子句中。APPLY运算符支持的类型是CROSS APPLY和OUTER APPLY。CROSS APPY仅仅实施一个逻辑查询处理阶段,而OUTER APPLY实施了两个阶段,APPLY运算符对两个输入表进行操作,第二个可以是一个表表达式,我们将APPLY两侧的表分别叫做左侧表和右侧表,右侧表通常是一个派生表或TVF(内嵌表值函数)。CROSS APPLY运算符实施一个逻辑查询处理阶段-它将右侧的表表达式应用到左侧表的每一行,并生成一个组合结果集的结果表。CROSS APPLYl类似于交叉联接中的CROSS JOIN,但是使用CROSS APPLY运算符,右侧的表表达式可以对来自左侧表的每一行表示一个不同的行集,这是与联接的不同之处。当在右侧使用一个派生表,并且派生表查询中引用来自左侧表的属性,就可以实现此目标,或者是在右侧使用一个内嵌TVF,可以传递左侧的属性作为输入参数,同样可以实现此目的-摘抄自SQL Server 2012基础教程。下面我们看一个简单的例子。

USE TSQL2012
GOSELECT C.custid, A.orderid, A.orderdate
FROM Sales.Customers AS CCROSS APPLY(SELECT TOP(3) orderid, empid, orderdate, requireddate FROM Sales.Orders AS OWHERE O.custid = C.custidORDER BY orderdate DESC, orderid DESC) AS A;

上述完成的是返回每个客户最近的3个订单。我们可以将右侧的表表达式看做是一个相关子查询,右侧的表表达式通过引用custid对来自Customers表的每一行进行处理并返回每个客户的最近的3个订单,是不是看起来很清爽呢,下面我们将进一步探讨APPLY运算符的作用。

进一步探讨APPLY运算符

上面我们看到通过相关子查询来进行查询显得代码有点丑陋,我们再来看一个例子。查询每个单价最高的订单,我们通过子查询来实现。

CROSS APPLY

USE AdventureWorks2012
GOSELECT SalesOrderID,OrderDate,MaxUnitPrice =(SELECT MAX(sod.UnitPrice) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID)
FROM Sales.SalesOrderHeader AS soh

如上操作看似代码比较简洁也能完成我们的查询诉求,但是我们用派生表来进行查询又是怎样的呢?

USE AdventureWorks2012
GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price
FROM Sales.SalesOrderHeader AS soh
JOIN
(SELECT max_unit_price = MAX(sod.UnitPrice),SalesOrderIDFROM Sales.SalesOrderDetail AS sodGROUP BY sod.SalesOrderID
) sod
ON sod.SalesOrderID = soh.SalesOrderID

此时由于两个表完全不相关,我们需要通过GROUP BY完成再进行JOIN,代码不是显得非常臃肿吗,这还是简单的,当有多个表时就比较复杂了,导致代码就不再具有可读性。但是自从在SQL Server 2005中有了APPLY妈妈再也不用担心我读不懂复杂的代码了,我们看看CROSS APPLY是怎样实现的。

USE AdventureWorks2012
GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price
FROM Sales.SalesOrderHeader AS soh
CROSS APPLY
(SELECT max_unit_price = MAX(sod.UnitPrice)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID
) sod

当我们利用内部联接时此时JOIN中的查询是独立的所以需要进行GROUP BY,而对于CROSS APPLY它本身就是对来自左侧的表中每一行就行处理并返回,同时利用CROSS APPLY它也超越了相关子查询,比如说我们还需要查出每个订单的总价呢,我们利用相关子查询需要再次嵌入SELECT子句。

SELECT SalesOrderID           ,OrderDate              ,MaxUnitPrice           = (SELECT MAX(sod.UnitPrice) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID),SumLineTotal           = (SELECT SUM(LineTotal) FROM Sales.SalesOrderDetail sod WHERE soh.SalesOrderID = sod.SalesOrderID)
FROM Sales.SalesOrderHeader AS soh

而利用CROSS APPLY只需添加集合函数SUM即可

USE AdventureWorks2012
GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price,sod.sum_line_total
FROM Sales.SalesOrderHeader AS soh
CROSS APPLY
(SELECT max_unit_price = MAX(sod.UnitPrice),sum_line_total = SUM(sod.LineTotal)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID
) sod 

OUTER APPLY

对于OUTER APPLY,如果右侧的表表达式返回一个空集合,CROSS APPLY运算符不会返回相应的左侧行,也就是说OUTER APPLY和在派生表上进行LEFT JOIN是等同的,如下:

SELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price
FROM Sales.SalesOrderHeader AS soh
LEFT JOIN
(SELECT max_unit_price = MAX(sod.UnitPrice),SalesOrderIDFROM Sales.SalesOrderDetail AS sodGROUP BY sod.SalesOrderID
) sod
ON sod.SalesOrderID = soh.SalesOrderID

此时我们利用OUTER APPLY则是如下:

USE AdventureWorks2012
GOSELECT soh.SalesOrderID,soh.OrderDate,sod.max_unit_price
FROM Sales.SalesOrderHeader AS soh
OUTER APPLY
(SELECT max_unit_price = MAX(sod.UnitPrice)FROM Sales.SalesOrderDetail AS sodWHERE soh.SalesOrderID = sod.SalesOrderID
) sod

上述对于APPLY右侧表表达式是一个派生表,此时为了封装,我们可以使用TVF内嵌表值函数来实现。其实将内嵌表值函数来代替派生表实现每个客户最近的3个订单。首先我们封装一个表值函数

USE TSQL2012
GOIF OBJECT_ID('dbo.TopOrders') IS NOT NULLDROP FUNCTION dbo.TopOrders;
GOCREATE FUNCTION dbo.TopOrders(@custid  AS INT, @n  AS  INT)RETURNS TABLE
AS RETURNSELECT  orderid, empid, orderdate, requireddateFROM Sales.OrdersWHERE  custid = @custidORDER BY orderdate DESC, orderid DESCOFFSET 0 ROWS FETCH FIRST @n ROWS ONLY;
GO

接着利用CROSS APPLY进行查询。

USE TSQL2012
GOSELECT C.custid, C.companyname, A.orderid, A.empid, A.requireddate
FROM Sales.Customers AS CCROSS APPLY dbo.TopOrders(C.custid, 3) AS A;

上面我们通过封装内嵌表值函数代替派生表使代码更具可读性和可维护性。到此我们可以得出一点基本结论。

APPLY运算符使用分析结论:当需要对表中的每一行进行应用时,且需要将所有结果集组合到一个结果集表中时,此时我们应该使用APPLY运算符,至于是使用CROSS APPLY还是OUTER APPLY根据场景而定,虽然APPLY右侧表可以用相关子查询或者派生表来实现,但是使得代码臃肿和可维护性差,通过封装内嵌表值函数来实现可以说是对右侧表通过相关子查询或者派生表来实现的完美替代者。

总结

本节我们讲解了APPLY运算符中两种类型的使用,下一节我们来分析下关于CROSS APPLY VS INNER JOIN的性能问题,同时也说明下CROSS APPLY和OUTER APPLY的应用场景。简短的内容,深入的理解,我们下节再会。

转载于:https://www.cnblogs.com/CreateMyself/p/6193183.html

SQL Server-聚焦APPLY运算符(二十七)相关推荐

  1. SQL Server里PIVOT运算符的”红颜祸水“

    概述 SQL Server里PIVOT运算符背后的基本思想是在T-SQL查询期间,你可以旋转行为列.运算符本身是SQL Server 2005后引入的,主要用在基于建立在实体属性值模型(Entity ...

  2. Microsoft SQL Server 数据库使用(二)

    ##Microsoft SQL Server 数据库使用(二) 数据库练习使用可以在我的资源下载中下载数据库脚本文件. 一.查询数据 注:下面使用 Microsoft SQL Server 2019 ...

  3. SQL Server 高级技术(二)—— 安全

    SQL Server 高级技术(二)-- 安全 一.概述 SQL Server 广泛使用安全主体和安全对象管理安全,一个请求.服务器.数据库或架构资源的实体称为安全主体,每一个安全主体有唯一的安全标识 ...

  4. SQL Server数据库开发的二十一条军规

    如果你正在负责一个基于SQL Server的项目,或者你刚刚接触SQL Server,你都有可能要面临一些数据库性能的问题,这篇文章会为你提供一些有用的指导(其中大多数也可以用于其它的DBMS). 在 ...

  5. SQL server学习日志(二)创建表!手把手教你创建表,修改表,了解数据类型!超详细!

    一.简单了解表(创建表之前一定要先了解数据类型与约束哦,这样我们才能创建正确的表!) 1.定义:基本表是数据库中组织和管理数据的基本单位,数据库的数据保存在一个个基本表中. 对于关系型数据库系统而言, ...

  6. sql server 索引阐述系列二 索引存储结构

    "流光容易把人抛,红了樱桃,绿了芭蕉" 转眼又年中了,感叹生命的有限,知识的无限.在后续讨论索引之前,先来了解下索引和表数据的内部结构,这一节将介绍页的存储,页分配单元类型,区的存 ...

  7. [SQL Server玩转Python] 二.T-SQL查询表格值及Python实现数据分析

    在开发项目过程中,更多的是通过Python访问SQL Server数据库接口,进行数据挖掘的操作:而SQL Server2016版本之后,嵌入了强大的R.Python.Machine Learning ...

  8. sql server中UNION 运算符随笔(几个需要注意的地方小总结)

    UNION 运算符是将两个或更多查询的结果组合为单个结果集 该结果集包含联合查询中的所有查询的全部行.这与使用联接组合两个表中的列不同. 使用 UNION 组合查询的结果集有两个最基本的规则: 1.所 ...

  9. Sql Server数据库事务介绍(二)---Sql语句,SqlTransaction和TransactionScope的使用方法

    本节主要介绍Sql语句,SqlTransaction和TransactionScope这三种使用事务的方法. 本节的所有例子都在sql server 2008和vs 2008环境下运行通过,如果没有s ...

最新文章

  1. R语言广义线性模型泊松回归(Poisson Regression)模型
  2. PKI/CA (6)双证书
  3. boost::stl_interfaces::reverse_iterator相关的测试程序
  4. VMware-workstation-full-8.0.0-471780.exe
  5. PHP中基本符号及使用方法
  6. 【入门】Spring-Boot项目配置Mysql数据库
  7. net 进阶学习 WebApi (2)
  8. 好工具推荐系列:Github客户端GitHub Desktop使用方法
  9. 干净卸载VS2015
  10. 夏普S2 android one,夏普S2内部做工怎么样?夏普AQUOS S2拆机评测图解
  11. “高定美学”品牌矩阵:「莲玉芳华」「琢我」「佐我」佐我气运系列之进击
  12. 前端怎么画三角形_用CSS画一个三角形
  13. 网络安全专家齐成岳:如何隐蔽你的C2
  14. Django - ContentType
  15. js 伪造referer_javascript操作referer详细解析
  16. 用MATLAB的函数scatter()绘制散点图
  17. polarion alm 2021
  18. 2018中国互联网企业100强,有你想进的吗?
  19. E420笔记本升级固态硬盘
  20. 【FFMPEG】华为新老两手机平台编码的视频,在同一车机上投屏解码时间慢的问题分析

热门文章

  1. 做系统ghost步骤图解_用好这工具,小孩都能会重装系统!
  2. Nginx的应用之动静分离
  3. SecureCRT 中文乱码问题
  4. BDD框架之Cucumber研究
  5. IT基础架构规划方案二(计算机系统与机房规划规划)
  6. c++成员变量与构造函数
  7. 算法补充 2011-9-12
  8. springcloud gateway 使用nacos 作为配置中心 和 注册中心
  9. mysql树节点【所有子节点列表 and 查询所有父节点列表】
  10. 华强北三代悦虎1562A怎么样?