Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Onde usar a aplicação externa


Um LEFT JOIN deve ser substituído por OUTER APPLY nas seguintes situações.

1. Se quisermos juntar duas tabelas com base em TOP n resultados

Considere se precisamos selecionar Id e Name de Master e duas últimas datas para cada Id de Details tabela.
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

que forma o seguinte resultado
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

Isso trará resultados errados, ou seja, trará apenas as últimas duas datas de Details tabela independente de Id mesmo que nos juntemos com Id . Portanto, a solução adequada é usar 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

Aqui está o trabalho:Em LEFT JOIN , TOP 2 as datas serão unidas ao MASTER somente após executar a consulta dentro da tabela derivada D . Em OUTER APPLY , ele usa a junção WHERE M.ID=D.ID dentro do OUTER APPLY , para que cada ID em Master será juntado com TOP 2 datas que trarão o seguinte resultado.
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. Quando precisamos de LEFT JOIN funcionalidade usando functions .

OUTER APPLY pode ser usado como um substituto com LEFT JOIN quando precisamos obter o resultado do Master tabela e uma function .
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C

E a função vai aqui.
CREATE FUNCTION FnGetQty 
(   
    @Id INT 
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT ID,PERIOD,QTY 
    FROM DETAILS
    WHERE [email protected]
)

que gerou o seguinte resultado
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. Reter NULL valores ao não dinamizar

Considere que você tem a tabela abaixo
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

Quando você usa UNPIVOT para trazer FROMDATE E TODATE para uma coluna, ele eliminará NULL valores por padrão.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P

que gera o resultado abaixo. Observe que perdemos o registro de Id número 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

Nesses casos, um APPLY pode ser usado(tanto CROSS APPLY ou OUTER APPLY , que é intercambiável).
SELECT DISTINCT ID,DATES
FROM MYTABLE 
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)

que forma o seguinte resultado e retém Id onde seu valor é 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