Il s'agit certainement d'un bug du produit.
Un bogue similaire a déjà été signalé et fermé comme "Ne répare pas" .
Y compris cette question, l'élément de connexion lié et un autre
deux
questions sur ce site, j'ai vu quatre cas de ce type de comportement avec des TVF en ligne et OUTER APPLY
- Tous étaient au format
OUTER APPLY dbo.SomeFunction(...) F
Et a renvoyé des résultats corrects lorsqu'il est écrit comme
OUTER APPLY (SELECT * FROM dbo.SomeFunction(...)) F
Cela ressemble donc à une solution de contournement possible.
Pour la requête
WITH Test AS
(
SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2
)
SELECT LP.*
FROM Test T
OUTER APPLY dbo.TVFTest
(
T.PropertyID,
T.Ap1,
T.Ap2
) LP;
Le plan d'exécution ressemble à
Et la liste des colonnes de sortie dans la projection finale est. Expr1000, Expr1001, Expr1003, Expr1004.
Cependant, seules deux de ces colonnes sont définies dans le tableau des constantes en bas à droite.
Le littéral $350000
est défini dans le tableau des constantes en haut à droite (Expr1001). Celui-ci est ensuite joint à l'extérieur sur le tableau des constantes en bas à droite. Comme aucune ligne ne correspond à la condition de jointure, les deux colonnes qui y sont définies (Expr1003, Expr1004) sont correctement évaluées comme NULL. puis enfin le scalaire de calcul ajoute le littéral 12
dans le flux de données en tant que nouvelle colonne (Expr1000) quel que soit le résultat de la jointure externe.
Ce n'est pas du tout la bonne sémantique. Comparez avec le plan (correct) lorsque le TVF en ligne est intégré manuellement.
WITH Test
AS (SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2)
SELECT LP.*
FROM Test T
OUTER APPLY (SELECT KeyID,
MatchValue1,
MatchValue2,
CASE
WHEN MatchValue1 <> MatchValue2
THEN 'Not equal'
ELSE 'Something else'
END AS MatchTest
FROM (SELECT T.PropertyID AS KeyID,
T.Ap1 AS MatchValue1,
T.Ap2 AS MatchValue2) TestRow
WHERE MatchValue1 <> MatchValue2) LP
Ici les colonnes utilisées dans la projection finale sont Expr1003, Expr1004, Expr1005, Expr1006
. Tous ces éléments sont définis dans le balayage constant en bas à droite.
Dans le cas de la TVF, tout semble mal tourner très tôt.
Ajout de OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606);
montre que l'arborescence d'entrée du processus est déjà incorrecte. Exprimé en SQL, c'est quelque chose comme.
SELECT Expr1000,
Expr1001,
Expr1003,
Expr1004
FROM (VALUES (12,
$350000,
350000)) V1(Expr1000, Expr1001, Expr1002)
OUTER APPLY (SELECT Expr1003,
IIF(Expr1001 <> Expr1003,
'Not equal',
'Something else') AS Expr1004
FROM (SELECT CAST(Expr1002 AS MONEY) AS Expr1003) D
WHERE Expr1001 <> Expr1003) OA
La sortie complète de cet indicateur de trace est la suivante (et 8605 affiche essentiellement le même arbre.)
*** Input Tree: ***
LogOp_Project COL: Expr1000 COL: Expr1001 COL: Expr1003 COL: Expr1004
LogOp_Apply (x_jtLeftOuter)
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1000
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=12)
AncOp_PrjEl COL: Expr1001
ScaOp_Const TI(money,ML=8) XVAR(money,Not Owned,Value=(10000units)=(-794967296))
AncOp_PrjEl COL: Expr1002
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=350000)
LogOp_Project
LogOp_Select
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1003
ScaOp_Convert money,Null,ML=8
ScaOp_Identifier COL: Expr1002
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
AncOp_PrjList
AncOp_PrjEl COL: Expr1004
ScaOp_IIF varchar collate 53256,Var,Trim,ML=14
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=9) XVAR(varchar,Owned,Value=Len,Data = (9,Not equal))
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=14) XVAR(varchar,Owned,Value=Len,Data = (14,Something else))
AncOp_PrjList
*******************