Cross Apply 与 Outer Apply 的区别

Cross Apply 与 Outer Apply 的区别,就像是 Inner join 与 Outer Join 的区别。

Inner Join 如果两边的表,无论是 Left Table, 或者是 Right Table, 做了限制,都会被应用到两边去,即一方的结果影响了另一方的结果。而 Out Join 则不会,即处于 Right Table 位置的表,对它做的条件限制,并不会影响 Left Table 位置上表的最后结果。

初学者肯定会被 Left Table, Right Table 给搞晕。简单理解,Inner Join, Outer Join 就是一个运算符,处于左边的就是 Left Table, 右边的就是 Right Table. 但是有例外,就是 Right Join. 它要反过来, 右边的表为 Left Table, 左边的表为 Right Table.

本质上, Left Join ,正规写法是 Left Outer Join, 左边的表(Left Table, 如果没有指定条件限制,并且不在 where 里限制右边的表 - Right Table)数据都会被作为结果返回。而 Left Outer Join 右边的表,则根据 Join 条件,只选出符合条件的记录, 不满足条件的记录,都显示 Null.

Left Table, Right Table , 还可以被称作, Preserved Table, Null-Supplying Table. Preserved Table 不受另外一个表的 Join 条件限制, 在最终结果里面,将记录全部保留作为结果,所以是 Left Table。

Cross Apply 与 Outer Apply 则有另外的术语:

Apply 运算符有内外表(表的表达式)之分。

这里写图片描述

处于图中 driver_table 位置的表,称为 Inner Table, 也称为 Driver Table. 表连接都是这张表驱动的。Correlated_table 位置的表,称为 Outer Table, 也称为 Correlated Table, 根据链接条件,选出本位置表中的数据。

当 Cross 用来形容 Apply 的时候,Correlated Table 位置上的表,会限制 Driver Table 的输出,即 Correlated Table 表中满足条件的关键字(key)必须同时在 Driver Table中也存在。而Outer Apply 则要宽容一些,在 Correlated Table 中不满足关键字(key)的记录用 Null 来替代。

SELECT BusinessEntityID

    ,FirstName

    ,LastName

    ,phx.PhoneNumber

FROM Person.Person per

OUTER APPLY (

    SELECT PhoneNumber

    FROM person.personphone ph

    WHERE ph.BusinessEntityID = per.BusinessEntityID

    ) phx

-------------------------------------------------------------------------------

SELECT BusinessEntityID

    ,FirstName

    ,LastName

    ,phx.PhoneNumber

FROM Person.Person per

CROSS APPLY (

    SELECT PhoneNumber

    FROM person.personphone ph

    WHERE ph.BusinessEntityID = per.BusinessEntityID

    ) phx

(经过notepad++的poorman’s T-sql formatter 插件进行了格式化)

这里写图片描述

cross apply 的结果将 293,38 这 2 条数据给滤掉了。

上次我们在文章

Cross Apply 与 Inner Join 的对抗

自动化赋值的 SQL 语句

中列出了 cross apply 的适用场景,并附上了 SQL 语句,这次我们继续基于那一次的 SQL 表结构,举个 Inner Join 的适用场景,Cross Apply 则完全失效:

SELECT count(*) AS rowseffect

FROM DimUser usr

CROSS APPLY (

    SELECT TOP 3 ord.OrderID

        ,ord.OrderDate

        ,ord.OrderAmount

    FROM FctOrderHeader ord

    INNER JOIN FctOrderUser usra ON ord.OrderID = usra.OrderID

        AND usra.UserID = usr.UserID

    WHERE OrderDate BETWEEN '2015-01-01'

            AND '2015-02-1'

    ORDER BY OrderDate DESC

        ,OrderAmount DESC

    ) ord;



WITH BASE_QUERY

AS (

    SELECT ord.OrderID

        ,ord.OrderDate

        ,ord.OrderAmount

        ,usr.UserID

        ,Row_Number() OVER (

            PARTITION BY usr.UserID ORDER BY ord.OrderDate DESC

                ,ord.OrderAmount DESC

            ) AS RNK

    FROM FctOrderHeader ord

    INNER JOIN FctOrderUser usr ON ord.OrderID = usr.OrderID

    WHERE ord.OrderDate BETWEEN '2015-01-01'

            AND '2015-02-1'

    )

SELECT count(*) AS rowseffect

FROM DimUser usr

INNER JOIN BASE_QUERY ord ON usr.UserID = ord.UserID

WHERE ord.RNK <= 3

SQL 写法的灵活多变,优化器给出的执行方案也就此一时,彼一时了。

需要在平时的场景中多加运用和体会!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dbLenis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值