Có nhiều tình huống mà bạn không thể tránh CROSS APPLYhoặc OUTER APPLY.
Hãy xem xét bạn có hai bảng.
BẢNG MASTER
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
BẢNG CHI TIẾT
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
ÁP DỤNG CROSS
Có nhiều tình huống chúng ta cần thay thế INNER JOINbằng CROSS APPLY.
1. Nếu chúng tôi muốn tham gia 2 bảng về TOP nkết quả với INNER JOINchức năng
Xem xét nếu chúng ta cần chọn Idvà Nametừ Mastervà hai ngày cuối cùng cho mỗi Idtừ 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
Các truy vấn trên tạo ra kết quả sau.
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
Xem, nó đã tạo kết quả cho hai ngày cuối cùng với hai ngày cuối cùng Idvà sau đó chỉ tham gia các bản ghi này trong truy vấn bên ngoài Id, điều này là sai. Để thực hiện điều này, chúng ta cần sử dụng 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
và hình thức anh ta theo kết quả.
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
Đây là công việc. Truy vấn bên trong CROSS APPLYcó thể tham chiếu bảng bên ngoài, nơi INNER JOINkhông thể thực hiện điều này (ném lỗi biên dịch). Khi tìm thấy hai ngày cuối cùng, việc tham gia được thực hiện bên trong CROSS APPLYtức là WHERE M.ID=D.ID.
2. Khi chúng ta cần INNER JOINchức năng sử dụng các chức năng.
CROSS APPLYcó thể được sử dụng thay thế INNER JOINkhi chúng ta cần lấy kết quả từ Masterbảng và a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Và đây là chức năng
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
tạo ra kết quả sau
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
ỨNG DỤNG NGOÀI
1. Nếu chúng tôi muốn tham gia 2 bảng về TOP nkết quả với LEFT JOINchức năng
Xem xét nếu chúng ta cần chọn Id và Tên từ Mastervà hai ngày cuối cùng cho mỗi Id từ Detailsbảng.
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
tạo thành kết quả sau
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
Điều này sẽ mang lại kết quả sai, tức là nó sẽ chỉ mang lại dữ liệu hai ngày mới nhất từ Detailsbảng bất kể Idchúng ta tham gia cùng Id. Vì vậy, giải pháp thích hợp là sử dụng 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
tạo thành kết quả mong muốn sau đây
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. Khi chúng ta cần LEFT JOINchức năng sử dụng functions.
OUTER APPLYcó thể được sử dụng thay thế LEFT JOINkhi chúng ta cần lấy kết quả từ Masterbảng và a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Và chức năng ở đây.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
tạo ra kết quả sau
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
Đặc điểm chung của CROSS APPLYvàOUTER APPLY
CROSS APPLYhoặc OUTER APPLYcó thể được sử dụng để giữ lại NULLcác giá trị khi không xoay vòng, có thể hoán đổi cho nhau.
Xem xét bạn có bảng dưới đây
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
Khi bạn sử dụng UNPIVOTđể đưa FROMDATEAND TODATEđến một cột, nó sẽ loại bỏ NULLcác giá trị theo mặc định.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
tạo ra kết quả dưới đây. Lưu ý rằng chúng tôi đã bỏ lỡ hồ sơ Idsố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
Trong những trường hợp như vậy, một CROSS APPLYhoặc OUTER APPLYsẽ hữu ích
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
tạo thành kết quả sau và giữ nguyên Idgiá trị của nó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