SQL 关于apply的两种形式cross apply 和 outer apply

例子:

CREATE TABLE [dbo].[Customers](
    [customerid] [char](5) COLLATE Chinese_PRC_CI_AS NOT NULL,
    [city] [varchar](10) COLLATE Chinese_PRC_CI_AS NOT NULL,
PRIMARY KEY CLUSTERED
(
    [customerid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

insert into dbo.Customers values(‘FISSA‘,‘Madrid‘);
insert into dbo.Customers values(‘FRNDO‘,‘Madrid‘);
insert into dbo.Customers values(‘KRLOS‘,‘Madrid‘);
insert into dbo.Customers values(‘MRPHS‘,‘Zion‘);

select * from dbo.Customers

CREATE TABLE [dbo].[Orders](
    [orderid] [int] NOT NULL,
    [customerid] [char](5) COLLATE Chinese_PRC_CI_AS NULL,
PRIMARY KEY CLUSTERED
(
    [orderid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

insert into dbo.Orders values(1,‘FRNDO‘);
insert into dbo.Orders values(2,‘FRNDO‘);
insert into dbo.Orders values(3,‘KRLOS‘);
insert into dbo.Orders values(4,‘KRLOS‘);
insert into dbo.Orders values(5,‘KRLOS‘);
insert into dbo.Orders values(6,‘MRPHS‘);
insert into dbo.Orders values(7,null);

select * from dbo.orders

--得到每个消费者最新的两个订单:
--用cross apply

select *
from dbo.Customers as C
 cross apply
    (select top 2 *
     from dbo.Orders as O
     where C.customerid=O.customerid
     order by orderid desc) as CA

--过程分析:
--它是先得出左表【dbo.Customers】里的数据,然后把此数据一条一条的放入右表表式中,分别得出结果集,最后把结果集整合到一起就是最终的返回结果集了
--(T1的数据 像for循环一样 一条一条的进入到T2中 然后返回一个集合  最后把所有的集合整合到一块  就是最终的结果),
--最后我们再理解一下上面让记着的话(使用apply就像是先计算左输入,让后为左输入中的每一行计算一次右输入)是不是有所明白了。
--实验:用outer apply 试试看看的到的结果:

select *
from dbo.Customers as C
 outer apply
    (select top 2 *
     from dbo.Orders as O
     where C.customerid=O.customerid
     order by orderid desc) as CA

--结果分析:
--发现outer apply得到的结果比cross多了一行,我们结合上面所写的区别(cross apply和outer apply 总是包含步骤A1,只有outer apply包含步骤A2,
--如果cross apply左行应用右表表达式时返回空积,则不返回该行。而outer apply返回改行,并且改行的右表表达式的属性为null)就会知道了。

例子:

--下面是完整的测试代码,你可以在 SQL Server 2005 联机帮助上找到: 

-- create Employees table and insert values
IF OBJECT_ID(‘Employees‘) IS NOT NULL
 DROP TABLE Employees
GO
CREATE TABLE Employees
(
 empid INT NOT NULL,
 mgrid INT NULL,
 empname VARCHAR(25) NOT NULL,
 salary MONEY NOT NULL
)
GO
IF OBJECT_ID(‘Departments‘) IS NOT NULL
 DROP TABLE Departments
GO
-- create Departments table and insert values
CREATE TABLE Departments
(
 deptid INT NOT NULL PRIMARY KEY,
 deptname VARCHAR(25) NOT NULL,
 deptmgrid INT
)
GO

-- fill datas
INSERT  INTO employees VALUES  (1,NULL,‘Nancy‘,00.00)
INSERT  INTO employees VALUES  (2,1,‘Andrew‘,00.00)
INSERT  INTO employees VALUES  (3,1,‘Janet‘,00.00)
INSERT  INTO employees VALUES  (4,1,‘Margaret‘,00.00)
INSERT  INTO employees VALUES  (5,2,‘Steven‘,00.00)
INSERT  INTO employees VALUES  (6,2,‘Michael‘,00.00)
INSERT  INTO employees VALUES  (7,3,‘Robert‘,00.00)
INSERT  INTO employees VALUES  (8,3,‘Laura‘,00.00)
INSERT  INTO employees VALUES  (9,3,‘Ann‘,00.00)
INSERT  INTO employees VALUES  (10,4,‘Ina‘,00.00)
INSERT  INTO employees VALUES  (11,7,‘David‘,00.00)
INSERT  INTO employees VALUES  (12,7,‘Ron‘,00.00)
INSERT  INTO employees VALUES  (13,7,‘Dan‘,00.00)
INSERT  INTO employees VALUES  (14,11,‘James‘,00.00)

INSERT  INTO departments VALUES  (1,‘HR‘,2)
INSERT  INTO departments VALUES  (2,‘Marketing‘,7)
INSERT  INTO departments VALUES  (3,‘Finance‘,8)
INSERT  INTO departments VALUES  (4,‘R&D‘,9)
INSERT  INTO departments VALUES  (5,‘Training‘,4)
INSERT  INTO departments VALUES  (6,‘Gardening‘,NULL)
GO
--SELECT * FROM departments

-- table-value function
IF OBJECT_ID(‘fn_getsubtree‘) IS NOT NULL
 DROP FUNCTION  fn_getsubtree
GO
CREATE  FUNCTION dbo.fn_getsubtree(@empid AS INT)
RETURNS TABLE
AS
RETURN(
  WITH Employees_Subtree(empid, empname, mgrid, lvl)
  AS
  (
    -- Anchor Member (AM)
    SELECT empid, empname, mgrid, 0
    FROM employees
    WHERE empid = @empid
    UNION ALL
    -- Recursive Member (RM)
    SELECT e.empid, e.empname, e.mgrid, es.lvl+1
    FROM employees AS e
       join employees_subtree AS es
          ON e.mgrid = es.empid
  )
    SELECT * FROM Employees_Subtree
)
GO

-- cross apply query
SELECT  *
FROM Departments AS D
    CROSS APPLY fn_getsubtree(D.deptmgrid) AS ST

-- outer apply query
SELECT  *
FROM Departments AS D
    OUTER APPLY fn_getsubtree(D.deptmgrid) AS ST

select * from employees
select * from Departments

select * from fn_getsubtree(2)
select * from fn_getsubtree(3)
select * from fn_getsubtree(4)
select * from fn_getsubtree(5)
select * from fn_getsubtree(6)

例子:

create table #T(姓名 varchar(10))
insert into #T values(‘张三‘)
insert into #T values(‘李四‘)
insert into #T values(NULL )

create table #T2(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
insert into #T2 values(‘张三‘ , ‘语文‘ , 74)
insert into #T2 values(‘张三‘ , ‘数学‘ , 83)
insert into #T2 values(‘张三‘ , ‘物理‘ , 93)
insert into #T2 values(NULL , ‘数学‘ , 50)

--drop table #t,#T2
go

select
    *
from
    #T a
cross apply
    (select 课程,分数 from #t2 where 姓名=a.姓名) b

/*
姓名         课程         分数
---------- ---------- -----------
张三         语文         74
张三         数学         83
张三         物理         93

(3 行受影响)

*/

select
    *
from
    #T a
outer apply
    (select 课程,分数 from #t2 where 姓名=a.姓名) b
/*
姓名         课程         分数
---------- ---------- -----------
张三         语文         74
张三         数学         83
张三         物理         93
李四         NULL       NULL
NULL       NULL       NULL

(5 行受影响)

*/
时间: 2024-10-22 19:33:12

SQL 关于apply的两种形式cross apply 和 outer apply的相关文章

SQL关于apply的两种形式cross apply和outer apply(转载)

SQL 关于apply的两种形式cross apply 和 outer apply apply有两种形式: cross apply 和 outer apply 先看看语法: <left_table_expression>  {cross|outer} apply <right_table_expression> 再让我们了解一下apply运算涉及的两个步骤: A1:把右表表达式(<right_table_expression>)应用到左表(<left_table_

在sql中case子句的两种形式

case子句,在select后面可以进行逻辑判断. 两种形式:判断相等.判断不等 一.判断相等的语法: case 列名 when ...  then ... when ...  then ... else ... end as 列别名 ONE:新建一个表,插入初始数据. --查整个表 select * from SDetail --插入初始数据 insert into SDetail (SName,SScore,SGender) values('刘德华',99,0) insert into SD

MyBatis collection的两种形式——MyBatis学习笔记之九

与association一样,collection元素也有两种形式,现介绍如下: 一.嵌套的resultMap 实际上以前的示例使用的就是这种方法,今天介绍它的另一种写法.还是以教师映射为例,修改映射文件TeacherMapper.xml如下(点击此处进入嵌套resultMap形式的示例源码下载页面.注:本示例代码是在修改本系列的上篇博文示例代码的基础上完成的,用到了MapperScannerConfigurer和注解等知识.对这些知识不熟悉的读者,可参考上篇博文:http://legend20

include的两种形式与介绍

include的另种形式和区别先简单的说下include的两种形式:<% include file="" %>:为静态包含(加载)<jsp:include page="" flush="true" />:为动态包含(加载) 简单来解释一下静态包含和和动态包含:静态包含:JSP编译器编译的时候已经包含好相应的文件,生成一个java_servlet,对应的Servlet文件中已经包含了被包含的页面,然后javac编译成一个cl

C# 支持两种形式的字符串:规则字符串和逐字字符串(@字符串)

规则字符串由包含在双引号中的零个或多个字符组成(如 "hello"),并且可以包含简单转义序列(如表示制表符的 \t).十六进制转义序列和 Unicode 转义序列. 逐字字符串由 @ 字符后跟开始的双引号字符.零个或多个字符以及结束的双引号字符组成.一个简单的示例就是 @"hello".在逐字字符串中,分隔符之间的字符逐字解释,唯一的例外是"引号转义序列".具体说来,在逐字字符串中不处理简单转义序列以及十六进制 和 Unicode 转义序列.逐

爪哇国新游记之十二----线程创建的两种形式

public class Thread1 extends Thread{ public void run(){ int i=0; while(i<10){ i++; System.out.println(i); } } public static void main(String[] args){ Thread1 t=new Thread1(); t.start(); } } public class Thread2 implements Runnable{ @Override public v

C++:一般情况下,设计函数的形参只需要两种形式

C++:一般情况下,设计函数的形参只需要两种形式.一,是引用形参,例如 void function (int &p_para):二,是常量引用形参,例如 void function(const int &p_para). 它们的特点如下: # 引用形参适用于需要改变变量数据的情况,常量引用形参适用于不需要改变对象.变量数据的情况. # 引用形参需要对象.变量来传递值,常量引用形参则不需要,可以直接传递表达式或者函数返回值. 通过这两种方式可以涵盖所有可能需要的设计情况,而通过这种方式实现的

重连通量的邻接矩阵和邻接表两种形式的求法

邻接矩阵: #include <cstdio> #include <cstring> #include <stack> using namespace std; #define min(a,b) a<b?a:b #define N 105 int dfn[N],low[N],mat[N][N],visit[N],tmpdfn,n; struct Edge{ int x,y; void print(){ printf("%d-%d\n",x,y)

MyBatis association的两种形式——MyBatis学习笔记之四

一.嵌套的resultMap 这 种方法本质上就是上篇博文介绍的方法,只是把教师实体映射从association元素中提取出来,用一个resultMap元素表示.然后 association元素再引用这个resultMap元素.修改上篇博文示例的StudentMapper.xml如下: <?xml version="1.0" encoding="utf8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org