Ada berbagai situasi di mana Anda tidak dapat menghindari CROSS APPLY
atau OUTER APPLY
.
Anggaplah Anda memiliki dua tabel.
TABEL MASTER
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
TABEL DETAIL
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
LINTAS BERLAKU
Ada banyak situasi di mana kita perlu mengganti INNER JOIN
dengan CROSS APPLY
.
1. Jika kita ingin menggabungkan 2 tabel pada TOP n
hasil dengan INNER JOIN
fungsionalitas
Pertimbangkan apakah kita perlu memilih Id
dan Name
dari Master
dan dua tanggal terakhir untuk masing-masing Id
dari Details table
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID
Kueri di atas menghasilkan hasil sebagai berikut.
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 |
x------x---------x--------------x-------x
Lihat, itu menghasilkan hasil untuk dua tanggal terakhir dengan dua tanggal terakhir Id
dan kemudian menggabungkan catatan ini hanya di kueri luar pada Id
, yang salah. Untuk mencapai ini, kita perlu menggunakan CROSS APPLY
.
SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
SELECT TOP 2 ID, PERIOD,QTY
FROM DETAILS D
WHERE M.ID=D.ID
ORDER BY CAST(PERIOD AS DATE)DESC
)D
dan bentuk dia mengikuti hasil.
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 |
x------x---------x--------------x-------x
Inilah pekerjaannya. Kueri di dalam CROSS APPLY
bisa mereferensikan tabel luar, di mana INNER JOIN
tidak bisa melakukan ini (melempar kesalahan kompilasi). Saat menemukan dua tanggal terakhir, penggabungan dilakukan di dalam CROSS APPLY
yaitu WHERE M.ID=D.ID
.
2. Saat kita membutuhkan INNER JOIN
fungsionalitas menggunakan fungsi.
CROSS APPLY
dapat digunakan sebagai pengganti INNER JOIN
ketika kita membutuhkan hasil dari Master
tabel dan a function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Dan inilah fungsinya
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
yang menghasilkan hasil sebagai berikut
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 |
x------x---------x--------------x-------x
TERAPKAN LUAR
1. Jika kita ingin menggabungkan 2 tabel pada TOP n
hasil dengan LEFT JOIN
fungsionalitas
Pertimbangkan jika kita perlu memilih Id dan Nama dari Master
dan dua tanggal terakhir untuk setiap Id dari Details
tabel.
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
yang membentuk hasil sebagai berikut
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
Ini akan membawa hasil yang salah, yaitu hanya akan membawa dua data tanggal terakhir dari Details
tabel terlepas dari Id
meskipun kita bergabung Id
. Jadi solusi yang tepat adalah menggunakan 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
yang membentuk hasil yang diinginkan berikut
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. Saat kita membutuhkan LEFT JOIN
fungsionalitas menggunakan functions
.
OUTER APPLY
dapat digunakan sebagai pengganti LEFT JOIN
ketika kita membutuhkan hasil dari Master
tabel dan a function
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Dan fungsinya di sini.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
yang menghasilkan hasil sebagai berikut
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
Fitur umum CROSS APPLY
danOUTER APPLY
CROSS APPLY
atau OUTER APPLY
dapat digunakan untuk mempertahankan NULL
nilai saat tidak berputar, yang dapat dipertukarkan.
Pertimbangkan Anda memiliki tabel di bawah ini
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
Saat Anda menggunakan UNPIVOT
untuk membawa FROMDATE
DAN TODATE
ke satu kolom, ini akan menghilangkan NULL
nilai secara default.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
yang menghasilkan hasil di bawah ini. Perhatikan bahwa kami melewatkan rekor Id
nomor3
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
Dalam kasus seperti itu, a CROSS APPLY
atau OUTER APPLY
akan berguna
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
yang membentuk hasil berikut dan mempertahankan di Id
mana nilainya3
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