【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】

原文链接:传送门

伴随着SQL SERVER 2005的发布,微软增加了一个新的操作符,它允许你将一个记录集与一个函数进行关联,然后对表(或者视图)的每一个指定列应用这个函数。这个新的操作符便是APPLY操作符。技术上来说,这个操作符实际上并不是一个JOIN,但是因为它用起来像是一个JOIN,它通常被成为关联操作。APPLY操作符具有两种形式,CROSS APPLY以及OUTER APPLY,在这篇文章中,我将向你解释这两种格式的差异,并以例子来演示每种格式是如何工作的。

介绍APPLY操作符

你曾经是否想要写过一个SELECT语句来对数据集中的每一行调用表值函数或计算表值表达式?如果是的话那么你将乐于了解APPLY操作符允许你进行这样的处理。APPLY操作符具有两种形式。

第一种形式是CROSS APPLY,其使用CROSS APPLY操作符一边的集合中每一行的列值并将它们作为CROSS APPLY操作符另一边的表值函数或表达式的输入项。每次对表值函数或者表达式调用返回的行会与触发表值函数调用的值所在的行进行关联,所有关联的行的集合最后再用UNION JOIN操作符关联起来。如果对于某一个特定的调用,表值函数并没有返回任何数据行,那么表或者记录行则不会被包含在最早的结果集中,因为它们不能与任何表值函数行进行关联。

APPLY操作符能够使用的第二种格式是OUTER APPLY。当表值函数或者表达式返回数据行时,这个操作符运行得如同CROSS APPLY。但是其有一个额外的特性。当表值函数被不会返回任何行的数据行所调用时,OUTER APPLY操作符同样会返回表或者记录集。

为了更好的理解这两种形式的APPLY操作符是如何工作的。让我们来查看下每个形式的操作符的一些示例。

示例的测试数据与函数

在我能够向你演示APPLY操作符的不同示例之前,我需要创建一些测试数据和一个表值函数。我的测试数据表和函数可以在列表1中被找到:

USE tempdb;
GO
IF object_id('dbo.Product') IS NOT NULL
DROP TABLE dbo.Product;
IF object_id('dbo.SearchString') IS NOT NULL
DROP TABLE dbo.SearchString;
IF object_id('dbo.FindProductLike') IS NOT NULL
DROP FUNCTION dbo.FindProductLike;
CREATE TABLE dbo.Product
(
ID INT IDENTITY ,
ProductName VARCHAR(100) ,
Price MONEY
);
INSERT INTO dbo.Product
VALUES ( 'Red Santa Suit', 199.99 ),
( 'Candy Canes', 1.99 ),
( 'Fake Snow', 2.99 ),
( 'Red Bells', 49.99 ),
( 'LED Lights', 6.99 );
CREATE TABLE dbo.SearchString
(
ID INT IDENTITY ,
String VARCHAR(100)
);
INSERT INTO dbo.SearchString
VALUES ( 'Red' ),
( 'Lights' ),
( 'Star' );
GO
CREATE FUNCTION dbo.FindProductLike
(
@FindString VARCHAR(100)
)
RETURNS TABLE
AS
RETURN
( SELECT ProductName ,
Price
FROM dbo.Product
WHERE ProductName LIKE '%' + @FindString + '%'
)

列表1:创建表和表值函数

列表1的代码创建了名为Product的表,其包含了5个不同的产品。同样我创建了一个名为SearchString的表,其包含了三个字符串。最后我创建了名为dbo.FindProductLike的表值函数。表值函数dbo.FindProductLike接受一个参数:@FindString。这个表值函数使用了提供的参数,并返回ProductName包含了传递进@FindString参数的字符串的那些数据行。

使用CROSS APPY操作符

CROSS APPLY操作符会对其所涉及的记录集中的每一行执行一个表值函数。为了演示这是如何工作的,让我来运行列表2的代码:

USE tempdb;
GO
SELECT *
FROM dbo.SearchString AS S
CROSS APPLY dbo.FindProductLike(S.String);

列表2:CROSS APPLY操作符的例子

当我运行列表2的代码,随着查询结果以文本形式来显示,我得到了如报告1的输出:

ID    String           ProductName                Price
----- ---------------- -------------------------- ---------
1 Red Red Santa Suit 199.99
1 Red Red Bells 49.99
2 Lights LED Lights 6.99

报告1:通过运行代码2产生的输出

如果你查看列表2的代码你会看到我使用CROSS APPLY操作符来将表dbo.SearchString的数据行与表值函数dbo.FindProductLike的结果进行关联。CROSS APPLY操作符使用来自于dbo.SearchString表的字符串值并且调用了表值函数dbo.FindProductLike。如果表值函数返回了任何数据行, 它们将会与dbo.SearchString的行进行关联。

结果表的前两行是由于使用了字符串值“Red”,并使用它调用表值函数dbo.FindProductLike而产生的。当“Red”被传递给表值函数时,对于那些ProductName 列包含字符“Red”的那些行,ProductName和Price列便被返回。由表值函数返回的这两行随后与包含“Red”的dbo.SearchString数据行进行关联,于是便产生了报告1所示的前两行数据。

报告的第三行的结果和前两行产生的方式是一样的,除过这次函数是用“Lights”值来调用的,其仅仅匹配了一个单独的ProductName值。因此仅仅产生了一个单独的数据行。dbo.SearchString表的最后一行,其查询列值为“Star”,其在Product表不会匹配到任何ProductName的值。所以对于包含“Star”值的dbo.SearchString数据行,在报告1中不会产生任何数据行。

----To be continued.

高级T-SQL进阶系列 (二)【上篇】:使用 APPLY操作符的更多相关文章

  1. Wireshark入门与进阶系列(二)

    摘自http://blog.csdn.net/howeverpf/article/details/40743705 Wireshark入门与进阶系列(二) “君子生非异也,善假于物也”---荀子 本文 ...

  2. Bing Maps进阶系列二:使用GeocodeService进行地理位置检索

    Bing Maps进阶系列二:使用GeocodeService进行地理位置检索 在<Bing Maps进阶系列一:初识Bing Maps地图服务>里已经对GeocodeService的功能 ...

  3. Spring Boot进阶系列二

    上一篇文章,主要分析了怎么建立一个Restful web service,系列二主要创建一个H5静态页面使用ajax请求数据,功能主要有添加一本书,请求所有书并且按照Id降序排列,以及查看,删除一本书 ...

  4. SQL 工具系列二

    1.RedGate 工具 SQL Prompt 脚步智能提示工具 脚步提示工具,轻松写入,编辑和探索SQL: SQL Prompt能根据数据库的对象名称,语法和用户编写的代码片段自动进行检索,智能的为 ...

  5. 高级java必会系列二:多线程经常使用的3个关键字:synchronized、ReentrantLock、volatile

    系列一讲解了多线程,本章讲解多线程开发中经常使用到的3个关键字synchronized.ReentrantLock.volatile. 一.synchronized 互斥锁,即操作互斥,并发线程过来, ...

  6. SQL进阶系列之11让SQL飞起来

    写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...

  7. SQL进阶系列之7用SQL进行集合运算

    写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...

  8. SQL进阶系列之5外连接的用法

    写在前面 SQL本身是作为一种数据提取工具而出现,使用SQL生成各种定制化报表和非定制化报表并非SQL原本用途的功能,但这并不意味着SQL无法实现这些功能. 用外连接进行行列转换(1)(行 → 列): ...

  9. 进阶系列二【绝对干货】---Quartz.Net的入门

    一.Quartz.Net是什么? Quartz.Net是一个开源的作业调度框架,OpenSymphony的开源项目,是Quartz的C#移植项目.非常适合在平时的工作中,定时轮询数据库同步,定时邮件通 ...

  10. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

随机推荐

  1. Bootstrap入门(2)表格

    Bootstrap入门(四)表格 <table>标签 首先,引入bootstrap的css文件,然后表格内容放在一个class为table的<table>标签中(class=& ...

  2. Redis05——Redis五大数据类型 String

    String String是Redis最基本的数据类型(较常用),一个key对应一个value string类型是二进制安全的,Redis的string可以包含任何数据 一个Redis中字符串valu ...

  3. HDU 1326 Box of Bricks(思维)

    Little Bob likes playing with his box of bricks. He puts the bricks one upon another and builds stac ...

  4. drf-jwt手动签发与校验,drf小组件:过滤、筛选、排序、分页

    复习 """ 频率组件:限制接口的访问频率 源码分析:初始化方法.判断是否有权限方法.计数等待时间方法 自定义频率组件: class MyThrottle(SimpleR ...

  5. 有源汇有上下界最小流 (ZQU 1592)

    这道题跟求最大流的时候差不多. 都是先构造可行流,然后判断是否可行, 可行的话,就利用残余流量,构造从汇点t跑到源点s的最大流, 如何求出答案呢. 在第一次求可行流的dinic后,跟求最大流的时候一样 ...

  6. 并发编程之CyclicBarrier

    栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生.栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行.闭锁用于等待事件,而栅栏用于等待其他线程. CyclicBarrier可以使 ...

  7. Python 多任务(进程) day1(2)

    进程和线程的简单区别: 功能:进程:能够完成多任务,比如 在一台电脑上能够运行多个QQ一份资源有一个执行的剪头,有多份资源就可以执行多个语句线程:能够完成多任务,比如 在一个QQ中的多个聊天窗口一份资 ...

  8. Docker - Docker Engine 结构结构概述

    概述 Docker Engine 结构的简单描述 ref docker 实战 第一本 docker 书 1. docker 版本 1. 版本 Docker Engine - Community 概述 ...

  9. Spring - Spring Boot - Actuator Web 访问开启

    1. 概述 打开 Spring Boot Actuator 的 Web 访问 2. 场景 之前看 Spring 的时候, 曾经想了解当时的配置 后来发现, 确实有这么个工具 刚开始发现, 除了 act ...

  10. CSS学习(1)简介

    什么是 CSS? CSS 指层叠样式表 (Cascading Style Sheets) 样式定义如何显示 HTML 元素 样式通常存储在样式表中 把样式添加到 HTML 4.0 中,是为了解决内容与 ...