Có nhiều tình huống mà bạn không thể tránh CROSS APPLY
hoặ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 JOIN
bằng CROSS APPLY
.
1. Nếu chúng tôi muốn tham gia 2 bảng về TOP n
kết quả với INNER JOIN
chức năng
Xem xét nếu chúng ta cần chọn Id
và Name
từ Master
và hai ngày cuối cùng cho mỗi Id
từ 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 Id
và 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 APPLY
có thể tham chiếu bảng bên ngoài, nơi INNER JOIN
khô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 APPLY
tức là WHERE M.ID=D.ID
.
2. Khi chúng ta cần INNER JOIN
chức năng sử dụng các chức năng.
CROSS APPLY
có thể được sử dụng thay thế INNER JOIN
khi chúng ta cần lấy kết quả từ Master
bả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 n
kết quả với LEFT JOIN
chức năng
Xem xét nếu chúng ta cần chọn Id và Tên từ Master
và hai ngày cuối cùng cho mỗi Id từ Details
bả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ừ Details
bảng bất kể Id
chú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 JOIN
chức năng sử dụng functions
.
OUTER APPLY
có thể được sử dụng thay thế LEFT JOIN
khi chúng ta cần lấy kết quả từ Master
bả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 APPLY
vàOUTER APPLY
CROSS APPLY
hoặc OUTER APPLY
có thể được sử dụng để giữ lại NULL
cá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 FROMDATE
AND TODATE
đến một cột, nó sẽ loại bỏ NULL
cá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ơ Id
số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 APPLY
hoặc OUTER APPLY
sẽ 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 Id
giá 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