cross apply 和 outer apply的区别

来源:互联网 发布:微额速达旗下软件 编辑:程序博客网 时间:2024/05/29 13:33

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

apply有两种形式: cross apply 和 outer apply

先看看语法:

  <left_table_expression>  {cross|outer} apply <right_table_expression>

再让我们了解一下apply运算涉及的两个步骤:

  1. A1:把右表表达式(<right_table_expression>)应用到左表(<left_table_expression>)输入的行;
  2. A2:添加外部行;

  使用apply就像是先计算左输入,然后为左输入中的每一行计算一次右输入。(这一句很重要,可能会不理解,但要先记住,后面会有详细的说明

最后结合以上两个步骤说明cross apply和outer apply的区别:

  cross apply和outer apply 总是包含步骤A1,只有outer apply包含步骤A2,如果cross apply左行应用右表表达式时返回空集,则不返回该行。而outer apply返回改行,并且改行的右表表达式的属性为null。

看到上面的解释或步骤大家可能还是一头的雾水,不知所云。下面用例子来说明:

先建表一([dbo].[Customers]  字段说明:customerid -- 消费者id , city -- 所在城市):

 

复制代码
复制代码
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

结果如图:

再建表二([dbo].[Orders]  字段说明:orderid -- 订单id  , customerid -- 消费者id):

复制代码
复制代码
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

sql:

复制代码
复制代码
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 试试看看的到的结果:

sql语句:

复制代码
复制代码
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)就会知道了。



含表值函数cross apply例子:

比如:LargeTable表中的某一列存储的数据是以“:”号分隔的数据,我们处理的时候,可能要先把这个值,先分隔,然后把分隔后的每个值单独一行放在一张表中,然后对这个表做处理。

原始数据(LargeTable表):
SQL Server中CROSS APPLY和OUTER APPLY的应用详解

为了简单,我们先拿其中id=2的一行处理,这些以:号分隔的数据,可能是我们某张表的主键(t1),我们可能需要把这些数值提出来,放在一张临时表中,和t1表关联,做一些处理。

处理这个分隔的数据结果如下图:

SQL Server中CROSS APPLY和OUTER APPLY的应用详解

如果用之前的版本处理这个操作的话,应该很发杂,暂时没想到怎么处理,如果有人实现过,可以提示一下。

这只是用其中一行做的处理,如果我们用上图的3行都做这样处理,把三行以:号分隔的数值都放在一个表中,该怎么处理呢?

今天的主角APPLY该闪亮登场了。用APPLY表运算符一行语句就能处理以上操作。

  1. SELECT a FROM dbo.LargeTable AS LT--实际表  
  2. CROSS APPLY dbo.split(LT.Name,':')--自定义表值函数,处理以某个字符分隔的数据,把这些数据,返回一张表  
  3. WHERE a <> '' --去掉结果表中a字段为空的数据 

处理的结果如下图:

SQL Server中CROSS APPLY和OUTER APPLY的应用详解

是不是很简单。

需要额外定义的就是那个自定义表值函数(split),这是我在网上找的,类似.Net中Split操作,代码如下:

使用方法:

  1. SELECT * FROM dbo.split('581::579::519::279::406::361::560',':')  
  2. ALTER Function [dbo].[Split](@Sql varchar(8000),@Splits varchar(10))  
  3. returns @temp Table (a varchar(100))  
  4. As  
  5. Begin  
  6. Declare @i Int  
  7. Set @Sql = RTrim(LTrim(@Sql))  
  8. Set @i = CharIndex(@Splits,@Sql)  
  9. While @i >= 1  
  10. Begin  
  11. Insert @temp Values(Left(@Sql,@i-1))  
  12. Set @Sql = SubString(@Sql,@i+1,Len(@Sql)-@i)  
  13. Set @i = CharIndex(@Splits,@Sql)  
  14. End 
  1. If @Sql <> ''  
  2. Insert @temp Values (@Sql)  
  3. Return  
  4. End 





原创粉丝点击