Il existe diverses situations où vous ne pouvez pas éviter CROSS APPLY
ou 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 JOIN
avec CROSS APPLY
.
1. Si nous voulons joindre 2 tables sur les TOP n
résultats avec des INNER JOIN
fonctionnalités
Considérez si nous devons sélectionner Id
et Name
de Master
et deux dernières dates pour chacune 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
Voir, il 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 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 APPLY
peut référencer la table externe, où INNER JOIN
cela 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 APPLY
c'est- à- dire WHERE M.ID=D.ID
.
2. Lorsque nous avons besoin de INNER JOIN
fonctionnalités utilisant des fonctions.
CROSS APPLY
peut être utilisé en remplacement INNER JOIN
lorsque nous devons obtenir le résultat de la Master
table 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 n
résultats avec des LEFT JOIN
fonctionnalités
Considérez si nous devons sélectionner l'ID et le nom à partir de Master
et les deux dernières dates pour chaque ID de la 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 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 Details
table, Id
mê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 JOIN
fonctionnalités en utilisant functions
.
OUTER APPLY
peut être utilisé en remplacement LEFT JOIN
lorsque nous devons obtenir le résultat de la Master
table 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 APPLY
etOUTER APPLY
CROSS APPLY
ou OUTER APPLY
peut être utilisé pour conserver les NULL
valeurs 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 UNPIVOT
pour amener FROMDATE
AND TODATE
à une colonne, il éliminera les NULL
valeurs 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 Id
nombre3
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 APPLY
ou OUTER APPLY
sera utile
SELECT DISTINCT ID,DATES
FROM MYTABLE
OUTER APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)
qui forme le résultat suivant et conserve Id
où 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