在哪里使用外涂

Sar*_*avu 10 sql-server left-join sql-server-2008 outer-apply

主表

x------x--------------------x
| Id   |        Name        |
x------x--------------------x
|  1   |          A         |
|  2   |          B         |
|  3   |          C         |
x------x--------------------x
Run Code Online (Sandbox Code Playgroud)

详情表

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
Run Code Online (Sandbox Code Playgroud)

LEFT JOINOUTER APPLY使用时得到相同的结果.

LEFT JOIN

SELECT T1.ID,T1.NAME,T2.PERIOD,T2.QTY 
FROM MASTER T1
LEFT JOIN DETAILS T2 ON T1.ID=T2.ID
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

LEFT JOIN应该在哪里使用和我应该在哪里使用OUTER APPLY

Sar*_*avu 11

在下列情况下LEFT JOIN应更换A.OUTER APPLY

1.如果我们想根据TOP n结果加入两个表

考虑我们是否需要从表中选择每个日期IdName来自Master最后两个日期.IdDetails

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
Run Code Online (Sandbox Code Playgroud)

形成以下结果

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
Run Code Online (Sandbox Code Playgroud)

这将带来错误的结果,即,即使我们加入,它也只会从Details表中带来最新的两个日期数据.所以正确的解决方案是使用.IdIdOUTER 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
Run Code Online (Sandbox Code Playgroud)

这是工作:在LEFT JOIN,TOP 2日期将加入到MASTER仅在派生表内执行查询之后D.在OUTER APPLY,它使用WHERE M.ID=D.ID内部连接OUTER APPLY,以便每个IDin 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
Run Code Online (Sandbox Code Playgroud)

2.当我们需要LEFT JOIN使用功能时functions.

OUTER APPLYLEFT JOIN当我们需要从Master表和a 获得结果时,可以用作替代function.

SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Run Code Online (Sandbox Code Playgroud)

功能就在这里.

CREATE FUNCTION FnGetQty 
(   
    @Id INT 
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT ID,PERIOD,QTY 
    FROM DETAILS
    WHERE ID=@Id
)
Run Code Online (Sandbox Code Playgroud)

产生了以下结果

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

当您使用AND 将一个列UNPIVOT引入时,它将默认消除值.FROMDATETODATENULL

SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
Run Code Online (Sandbox Code Playgroud)

产生以下结果.请注意,我们已经错过了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
Run Code Online (Sandbox Code Playgroud)

在这种情况下的APPLY可用于(或者CROSS APPLYOUTER APPLY,这是可互换的).

SELECT DISTINCT ID,DATES
FROM MYTABLE 
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
Run Code Online (Sandbox Code Playgroud)

它形成以下结果并保留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
Run Code Online (Sandbox Code Playgroud)

  • "OUTER APPLY可用于在取消隐藏时保留NULL值" - 在[评论到您的其他答案]中(http://stackoverflow.com/questions/1139160/when-should-i-use-cross-apply-over-内部联接#comment45660786_28644152),我已经指出,如果你想用它进行翻新,使用哪个APPLY并不重要,但你从未在回复中解决过这个问题.这个答案意味着(以及另一个明确的状态)CROSS APPLY在这种情况下不会保留NULL,[这是错误的](http://sqlfiddle.com/#!3/2165d/1).您应该在分享知识之前检查您的事实. (3认同)