Ada berbagai situasi di mana Anda tidak dapat menghindari CROSS APPLYatau 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 JOINdengan CROSS APPLY.
1. Jika kita ingin menggabungkan 2 tabel pada TOP nhasil dengan INNER JOINfungsionalitas
Pertimbangkan apakah kita perlu memilih Iddan Namedari Masterdan dua tanggal terakhir untuk masing-masing Iddari 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 Iddan 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 APPLYbisa mereferensikan tabel luar, di mana INNER JOINtidak bisa melakukan ini (melempar kesalahan kompilasi). Saat menemukan dua tanggal terakhir, penggabungan dilakukan di dalam CROSS APPLYyaitu WHERE M.ID=D.ID.
2. Saat kita membutuhkan INNER JOINfungsionalitas menggunakan fungsi.
CROSS APPLYdapat digunakan sebagai pengganti INNER JOINketika kita membutuhkan hasil dari Mastertabel 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 nhasil dengan LEFT JOINfungsionalitas
Pertimbangkan jika kita perlu memilih Id dan Nama dari Masterdan dua tanggal terakhir untuk setiap Id dari Detailstabel.
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 Detailstabel terlepas dari Idmeskipun 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 JOINfungsionalitas menggunakan functions.
OUTER APPLYdapat digunakan sebagai pengganti LEFT JOINketika kita membutuhkan hasil dari Mastertabel 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 APPLYdanOUTER APPLY
CROSS APPLYatau OUTER APPLYdapat digunakan untuk mempertahankan NULLnilai 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 UNPIVOTuntuk membawa FROMDATEDAN TODATEke satu kolom, ini akan menghilangkan NULLnilai 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 Idnomor3
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 APPLYatau OUTER APPLYakan berguna
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
yang membentuk hasil berikut dan mempertahankan di Idmana 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