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 [email protected]
)
което генерира следния резултат
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