LEFT JOIN
by měla být nahrazena OUTER APPLY
v následujících situacích.
1. Pokud chceme spojit dvě tabulky na základě TOP n
výsledky
Zvažte, zda musíme vybrat Id
a Name
z Master
a poslední dvě data pro každé Id
z Details
tabulka.
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
který tvoří následující výsledek
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
To přinese špatné výsledky, tj. přinese pouze poslední dvě data z Details
tabulky bez ohledu na Id
i když se připojíme pomocí Id
. Správným řešením je tedy použití 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
Zde je funkční:V LEFT JOIN
, TOP 2
data budou spojena s MASTER
až po provedení dotazu v odvozené tabulce D
. V OUTER APPLY
, používá spojení WHERE M.ID=D.ID
uvnitř OUTER APPLY
, takže každé Id
v Master
bude spojen s TOP 2
data, která přinesou následující výsledek.
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. Když potřebujeme LEFT JOIN
funkčnost pomocí functions
.
OUTER APPLY
lze použít jako náhradu za LEFT JOIN
když potřebujeme získat výsledek z Master
tabulka a function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
A funkce je tady.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE [email protected]
)
který vygeneroval následující výsledek
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. Zachovat NULL
hodnoty při odklopení
Zvažte, že máte níže uvedenou tabulku
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
Když použijete UNPIVOT
aby přinesl FROMDATE
AND TODATE
do jednoho sloupce, odstraní NULL
hodnoty ve výchozím nastavení.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
který generuje níže uvedený výsledek. Všimněte si, že jsme vynechali záznam Id
číslo 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
V takových případech APPLY
lze použít (buď CROSS APPLY
nebo OUTER APPLY
, který je zaměnitelný).
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
který tvoří následující výsledek a zachovává Id
kde jeho hodnota je 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