Il y a plusieurs situations où vous ne pouvez pas éviter CROSS APPLY
o OUTER APPLY
.
Considérons que vous avez deux tables.
TABLE 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
CROSS APPLY
Il y a de nombreuses situations où nous devons remplacer INNER JOIN
con CROSS APPLY
.
1. Si nous voulons joindre 2 tables sur TOP n
les résultats avec INNER JOIN
fonctionnalité
Considérons si nous devons sélectionner Id
y Name
de Master
et les deux dernières dates pour chaque Id
de 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
Tu vois, ça a généré des résultats pour les deux dernières dates avec les deux dernières dates. Id
puis a joint ces enregistrements uniquement dans la requête externe sur 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 fonctionnement. La requête à l'intérieur CROSS APPLY
peut faire référence à la table externe, où INNER JOIN
ne peut pas le faire (erreur de compilation). Lors de la recherche des deux dernières dates, la jonction est faite à l'intérieur de CROSS APPLY
ie, WHERE M.ID=D.ID
.
2. Lorsque nous avons besoin INNER JOIN
la fonctionnalité à l'aide de fonctions.
CROSS APPLY
peut être utilisé en remplacement de INNER JOIN
quand nous avons besoin d'obtenir le résultat de Master
et une 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 TOP n
les résultats avec LEFT JOIN
fonctionnalité
Considérons que nous avons besoin de sélectionner Id et Name à partir de Master
et les deux dernières dates pour chaque Id de Details
table.
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 donne 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 donnera des résultats erronés, c'est-à-dire que seules les données des deux dernières dates seront affichées. Details
indépendamment de Id
même si nous nous joignons à Id
. La bonne solution est donc d'utiliser 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
ce qui donne 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 LEFT JOIN
fonctionnalité utilisant functions
.
OUTER APPLY
peut être utilisé en remplacement de LEFT JOIN
quand nous avons besoin d'obtenir le résultat de Master
et une 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 APPLY
y OUTER APPLY
CROSS APPLY
o OUTER APPLY
peut être utilisé pour conserver NULL
lors du dépivotage, qui sont interchangeables.
Considérons 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 UNPIVOT
d'apporter FROMDATE
ET TODATE
à une colonne, cela éliminera NULL
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 manqué l'enregistrement de Id
numéro 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
Dans ce cas, un CROSS APPLY
o OUTER APPLY
sera utile
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
qui forme le résultat suivant et retient Id
où sa valeur est 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