มีสถานการณ์ต่าง ๆ ที่คุณไม่สามารถหลีกเลี่ยงหรือCROSS APPLY
OUTER APPLY
พิจารณาว่าคุณมีสองตาราง
ตาราง MASTER
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
ตารางรายละเอียด
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
ใช้ข้าม
มีหลายสถานการณ์ที่เราจำเป็นต้องเปลี่ยนเป็นด้วยINNER JOIN
CROSS APPLY
1. หากเราต้องการเข้าร่วม 2 ตารางกับTOP n
ผลลัพธ์ที่มีINNER JOIN
ฟังก์ชันการทำงาน
พิจารณาถ้าเราต้องเลือกId
และName
จากMaster
และวันที่สองวันที่ผ่านมาสำหรับแต่ละจากId
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
แบบสอบถามด้านบนสร้างผลลัพธ์ต่อไปนี้
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
ดูว่าสร้างผลลัพธ์สำหรับสองวันที่แล้วโดยมีวันที่สองวันที่Id
แล้วจากนั้นจึงรวมระเบียนเหล่านี้ในแบบสอบถามภายนอกId
เท่านั้นซึ่งไม่ถูกต้อง 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
และฟอร์มเขาตามผล
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
นี่คือการทำงาน แบบสอบถามภายในCROSS APPLY
สามารถอ้างอิงตารางด้านนอกซึ่งINNER JOIN
ไม่สามารถทำได้ (แสดงข้อผิดพลาดในการคอมไพล์) เมื่อหาวันที่สองวันที่ผ่านมาเข้าร่วมจะทำภายในคือCROSS APPLY
WHERE M.ID=D.ID
2. เมื่อเราต้องการINNER JOIN
ฟังก์ชันโดยใช้ฟังก์ชัน
CROSS APPLY
สามารถใช้แทนได้INNER JOIN
เมื่อเราต้องการผลลัพธ์จากMaster
ตารางและกfunction
.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
และนี่คือฟังก์ชัน
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@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-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
ใช้ภายนอก
1. หากเราต้องการเข้าร่วม 2 ตารางกับTOP n
ผลลัพธ์ที่มีLEFT JOIN
ฟังก์ชันการทำงาน
พิจารณาว่าเราจำเป็นต้องเลือก 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
ซึ่งสร้างผลลัพธ์ที่ต้องการดังต่อไปนี้
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 ID=@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-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
คุณสมบัติทั่วไปของCROSS APPLY
และOUTER APPLY
CROSS APPLY
หรือOUTER APPLY
สามารถใช้เพื่อรักษา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
AND 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
ในกรณีเช่นนี้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