sql >> Base de Datos >  >> RDS >> Sqlserver

Aplicación externa Columnas que regresan inesperadamente NO NULAS cuando no hay coincidencia

Este es ciertamente un error en el producto.

Un error similar ya se informó y cerró como "No arreglará" .

Incluyendo esta pregunta, el elemento de conexión vinculado y otro dos preguntas en este sitio he visto cuatro casos de este tipo de comportamiento con TVF en línea y OUTER APPLY - Todos ellos eran del formato

OUTER APPLY dbo.SomeFunction(...) F

Y devolvió resultados correctos cuando se escribió como

OUTER APPLY (SELECT * FROM dbo.SomeFunction(...)) F

Así que esto parece una posible solución.

Para la consulta

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;

El plan de ejecución parece

Y la lista de columnas de salida en la proyección final es. Expr1000, Expr1001, Expr1003, Expr1004.

Sin embargo, solo dos de esas columnas están definidas en la tabla de constantes en la parte inferior derecha.

El literal $350000 se define en la tabla de constantes en la parte superior derecha (Expr1001). Esto luego se une a la tabla de constantes en la parte inferior derecha. Como ninguna fila coincide con la condición de combinación, las dos columnas definidas allí (Expr1003, Expr1004) se evalúan correctamente como NULL. luego, finalmente, el escalar de cómputo agrega el literal 12 en el flujo de datos como una nueva columna (Expr1000) independientemente del resultado de la combinación externa.

Estas no son en absoluto la semántica correcta. Compare con el plan (correcto) cuando el TVF en línea se inserta manualmente.

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 

Aquí las columnas utilizadas en la proyección final son Expr1003, Expr1004, Expr1005, Expr1006 . Todos estos se definen en el escaneo constante inferior derecho.

En el caso de la TVF, todo parece ir mal desde el principio.

Agregando OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606); muestra que el árbol de entrada al proceso ya es incorrecto. Expresado en SQL es algo así como.

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 

El resultado completo de ese indicador de seguimiento es el siguiente (y 8605 muestra básicamente el mismo árbol).

*** 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 

*******************