Il existe diverses situations où vous ne pouvez pas éviter CROSS APPLYou OUTER APPLY.
Considérez que vous avez deux tables.
TABLE DE MAÎTRE
x------x--------------------x
| Id | Name |
x------x--------------------x
| 1 | A |
| 2 | B |
| 3 | C |
x------x--------------------x
TABLEAU DE DÉTAILS
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
APPLIQUER CROISÉ
Il y a beaucoup de situations où nous devons remplacer INNER JOINavec CROSS APPLY.
1. Si nous voulons joindre 2 tables sur les TOP nrésultats avec des INNER JOINfonctionnalités
Considérez si nous devons sélectionner Idet Namede Masteret deux dernières dates pour chacune Idde 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
La requête ci-dessus génère le résultat suivant.
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
Voir, il a généré des résultats pour les deux dernières dates avec les deux dernières dates, Idpuis a joint ces enregistrements uniquement dans une requête externe Id, ce qui est faux. Pour ce faire, nous devons utiliser 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
et forme le résultat suivant.
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
Voici le travail. La requête à l'intérieur CROSS APPLYpeut référencer la table externe, où INNER JOINcela ne peut pas faire (génère une erreur de compilation). Lors de la recherche des deux dernières dates, la jonction se fait à l'intérieur, CROSS APPLYc'est- à- dire WHERE M.ID=D.ID.
2. Lorsque nous avons besoin de INNER JOINfonctionnalités utilisant des fonctions.
CROSS APPLYpeut être utilisé en remplacement INNER JOINlorsque nous devons obtenir le résultat de la Mastertable et a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C
Et voici la fonction
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
qui a généré le résultat suivant
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
APPLIQUER À L'EXTÉRIEUR
1. Si nous voulons joindre 2 tables sur les TOP nrésultats avec des LEFT JOINfonctionnalités
Considérez si nous devons sélectionner l'ID et le nom à partir de Masteret les deux dernières dates pour chaque ID de la Detailstable.
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
ce qui forme le résultat suivant
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
Cela entraînera des résultats erronés, c'est-à-dire qu'il n'apportera que les données des deux dernières dates de la Detailstable, Idmême si nous nous joignons Id. Donc, la bonne solution utilise 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
qui forme le résultat souhaité suivant
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. Lorsque nous avons besoin de LEFT JOINfonctionnalités en utilisant functions.
OUTER APPLYpeut être utilisé en remplacement LEFT JOINlorsque nous devons obtenir le résultat de la Mastertable et a function.
SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
OUTER APPLY dbo.FnGetQty(M.ID) C
Et la fonction va ici.
CREATE FUNCTION FnGetQty
(
@Id INT
)
RETURNS TABLE
AS
RETURN
(
SELECT ID,PERIOD,QTY
FROM DETAILS
WHERE ID=@Id
)
qui a généré le résultat suivant
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
Caractéristique commune de CROSS APPLYetOUTER APPLY
CROSS APPLYou OUTER APPLYpeut être utilisé pour conserver les NULLvaleurs lors du non-pivotement, qui sont interchangeables.
Considérez que vous avez le tableau ci-dessous
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
Lorsque vous utilisez UNPIVOTpour amener FROMDATEAND TODATEà une colonne, il éliminera les NULLvaleurs par défaut.
SELECT ID,DATES
FROM MYTABLE
UNPIVOT (DATES FOR COLS IN (FROMDATE,TODATE)) P
qui génère le résultat ci-dessous. Notez que nous avons raté le record du Idnombre3
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
Dans de tels cas, un CROSS APPLYou OUTER APPLYsera utile
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
qui forme le résultat suivant et conserve Idoù sa valeur est3
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