sql >> Databasteknik >  >> RDS >> Sqlserver

Var ska man använda Outer Apply

En LEFT JOIN bör ersättas med OUTER APPLY i följande situationer.

1. Om vi ​​vill sammanfoga två tabeller baserade på TOP n resultat

Fundera på om vi behöver välja Id och Name från Master och de två senaste datumen för varje Id från Details bord.

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

vilket ger följande resultat

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

Detta kommer att ge felaktiga resultat, dvs. det kommer endast att ta med de senaste två datumdata från Details tabell oavsett Id även om vi går med med Id . Så den rätta lösningen är att använda 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

Så här fungerar :I LEFT JOIN , TOP 2 datum kommer att kopplas till MASTER endast efter att ha kört frågan i den härledda tabellen D . I OUTER APPLY , använder den anslutande WHERE M.ID=D.ID inuti OUTER APPLY , så att varje ID i Master kommer att förenas med TOP 2 datum som ger följande resultat.

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. När vi behöver LEFT JOIN funktionalitet med functions .

OUTER APPLY kan användas som ersättning med LEFT JOIN när vi behöver få resultat från Master tabell och en function .

SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C

Och funktionen går här.

CREATE FUNCTION FnGetQty 
(   
    @Id INT 
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT ID,PERIOD,QTY 
    FROM DETAILS
    WHERE [email protected]
)

vilket genererade följande resultat

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. Behåll NULL värden vid unpivotering

Tänk på att du har tabellen nedan

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

När du använder UNPIVOT för att hämta FROMDATE OCH TODATE till en kolumn kommer den att eliminera NULL värden som standard.

SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P

vilket genererar resultatet nedan. Observera att vi har missat posten för Id nummer 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

I sådana fall en APPLY kan användas (antingen CROSS APPLY eller OUTER APPLY , som är utbytbar).

SELECT DISTINCT ID,DATES
FROM MYTABLE 
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)

som bildar följande resultat och behåller Id där dess värde är 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. MySQL &PHP :Sök med flera nyckelord

  2. Undersökningar med EXISTS vs IN - MySQL

  3. Konvertera från DateTime till INT

  4. MySQL Data - Bästa sättet att implementera personsökning?