Kaçınamayacağınız CROSS APPLYveya kaçınamayacağınız çeşitli durumlar vardır OUTER APPLY.
İki masanız olduğunu düşünün.
MASTER TABLO
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
DETAY TABLOSU
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
ÇAPRAZ UYGULAMA
Değiştirmemiz gereken birçok durum INNER JOINvar CROSS APPLY.
1. TOP nSonuçlarda INNER JOINişlevselliğe sahip 2 tabloyu birleştirmek istiyorsak
Biz belirlemeniz gerekirse düşünün Idve Namegelen Masterbiri için ve son iki tarihleri Idarasından 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
Yukarıdaki sorgu aşağıdaki sonucu verir.
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
Bakın, son iki tarih için son iki tarih için sonuçlar üretti Idve sonra bu kayıtları sadece dış sorguda birleştirdi Id, ki bu yanlış. Bunu başarmak için kullanmamız gerekiyor 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
ve takip eden sonucu oluşturur.
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
İşte çalışma. İçerideki sorgu CROSS APPLY, INNER JOINbunu yapamayan dış tabloya başvurabilir (derleme hatası verir). Son iki tarihi bulurken, birleştirme CROSS APPLYyani içinde yapılır WHERE M.ID=D.ID.
2. INNER JOINİşlevleri kullanarak işlevselliğe ihtiyaç duyduğumuzda .
CROSS APPLYtablo ve INNER JOINa'dan sonuç almamız gerektiğinde yerine kullanılabilir .Masterfunction
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Ve işte fonksiyon
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
aşağıdaki sonucu oluşturan
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
DIŞ UYGULAMA
1. TOP nSonuçlarda LEFT JOINişlevselliğe sahip 2 tabloyu birleştirmek istiyorsak
Tablodaki Masterher bir Id için başlangıç ve son iki tarihi seçmemiz gerekip gerekmediğini düşünün 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
aşağıdaki sonucu oluşturan
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
Bu yanlış sonuçlar getirecektir, yani biz katılmış olsak da Detailstablodan en son iki tarih verisini getirecektir . Yani doğru çözüm kullanmaktır .IdIdOUTER 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
aşağıdaki istenen sonucu oluşturan
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 JOINKullanarak işlevselliğe ihtiyacımız olduğunda functions.
OUTER APPLYtablo ve LEFT JOINa'dan sonuç almamız gerektiğinde yerine kullanılabilir .Masterfunction
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Ve fonksiyon buraya gelir.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
aşağıdaki sonucu oluşturan
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
Ortak özelliği CROSS APPLYveOUTER APPLY
CROSS APPLYveya birbirinin yerine geçebilen değerleri döndürürken OUTER APPLYkorumak için kullanılabilir NULL.
Aşağıdaki tabloya sahip olduğunuzu düşünün
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
Kullandığınızda UNPIVOTgetirmek FROMDATEVE TODATEtek sütuna, bu ortadan kaldıracak NULLvarsayılan olarak değerleri.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
aşağıdaki sonucu oluşturur. Rekor Idsayıları kaçırdığımızı unutmayın3
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
Bu gibi durumlarda a CROSS APPLYveya OUTER APPLYyararlı olacaktır
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
aşağıdaki sonucu oluşturan Idve değerini olduğu yerde tutan3
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