MASTER TABLE
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DETAILS TABLE
x------x--------------------x-------x
| Id | PERIOD | QTY |
x------x--------------------x-------x
| 1 | 2014-01-13 | 10 |
| 1 | 2014-01-11 | 15 |
| 1 | 2014-01-12 | 20 |
| 2 | 2014-01-06 | 30 |
| 2 | 2014-01-08 | 40 |
x------x--------------------x-------x
使用LEFT JOIN
和OUTER APPLY
时,我得到的结果相同。
LEFT JOIN
SELECT T1.ID,T1.NAME,T2.PERIOD,T2.QTY
FROM MASTER T1
LEFT JOIN DETAILS T2 ON T1.ID=T2.ID
OUTER APPLY
SELECT T1.ID,T1.NAME,TAB.PERIOD,TAB.QTY
FROM MASTER T1
OUTER APPLY
(
SELECT ID,PERIOD,QTY
FROM DETAILS T2
WHERE T1.ID=T2.ID
)TAB
我应该在哪里使用LEFT JOIN
我应该在哪里使用OUTER APPLY
答案 0 :(得分:7)
在以下情况下,LEFT JOIN
应替换为OUTER APPLY
。
<强> 1。如果我们想根据TOP n
结果
考虑我们是否需要从Id
中选择Name
和Master
以及从Id
表中选择每个Details
的最后两个日期。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
LEFT JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
形成以下结果
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | NULL | NULL |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
这将带来错误的结果,即,即使我们加入Details
,它也只会带来来自Id
表的最新两个日期数据,而不管Id
。所以正确的解决方案是使用OUTER APPLY
。
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
OUTER APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
以下是工作:在LEFT JOIN
中,只有在派生表TOP 2
内执行查询后,MASTER
日期才会加入D
。在OUTER APPLY
中,它使用WHERE M.ID=D.ID
内的加入OUTER APPLY
,以便ID
中的每个Master
与TOP 2
日期一起加入以下结果。
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-08 | 40 |
| 2 | B | 2014-01-06 | 30 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
<强> 2。当我们需要使用LEFT JOIN
时的functions
功能时。
OUTER APPLY
表和LEFT JOIN
获取结果时, Master
可用作function
的替代。
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
功能就在这里。
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
生成以下结果
x------x---------x--------------x-------x
| Id | Name | PERIOD | QTY |
x------x---------x--------------x-------x
| 1 | A | 2014-01-13 | 10 |
| 1 | A | 2014-01-11 | 15 |
| 1 | A | 2014-01-12 | 20 |
| 2 | B | 2014-01-06 | 30 |
| 2 | B | 2014-01-08 | 40 |
| 3 | C | NULL | NULL |
x------x---------x--------------x-------x
第3。取消隐藏
时保留NULL
值
考虑您有下表
x------x-------------x--------------x
| Id | FROMDATE | TODATE |
x------x-------------x--------------x
| 1 | 2014-01-11 | 2014-01-13 |
| 1 | 2014-02-23 | 2014-02-27 |
| 2 | 2014-05-06 | 2014-05-30 |
| 3 | NULL | NULL |
x------x-------------x--------------x
当您使用UNPIVOT
将FROMDATE
和TODATE
带到一列时,默认情况下会消除NULL
个值。
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
生成以下结果。请注意,我们错过了Id
号3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
x------x-------------x
在这种情况下,可以使用APPLY
(CROSS APPLY
或OUTER APPLY
,这是可以互换的。)
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
形成以下结果,并保留Id
,其值为3
x------x-------------x
| Id | DATES |
x------x-------------x
| 1 | 2014-01-11 |
| 1 | 2014-01-13 |
| 1 | 2014-02-23 |
| 1 | 2014-02-27 |
| 2 | 2014-05-06 |
| 2 | 2014-05-30 |
| 3 | NULL |
x------x-------------x
答案 1 :(得分:0)
在您的示例查询中,结果确实相同。
但OUTER APPLY
可以做更多:对于每个外行,您可以生成任意内部结果集。例如,您可以加入TOP 1 ORDER BY ...
行。 LEFT JOIN
无法做到这一点。
内部结果集的计算可以引用外部列(就像你的例子那样)。
OUTER APPLY
严格来说比LEFT JOIN
更强大。这很容易看到,因为每个LEFT JOIN
都可以像您一样重写为OUTER APPLY
。不过,它的语法更加冗长。