sql >> Databáze >  >> RDS >> Sqlserver

Vnější použít Vracející sloupce neočekávaně NOT NULL, pokud žádná shoda

To je určitě chyba v produktu.

Podobná chyba byla již nahlášena a uzavřena jako "Neopravím" .

Včetně této otázky, propojené položky připojení a další dva otázky na tomto webu Viděl jsem čtyři případy tohoto typu chování s inline TVF a OUTER APPLY - Všechny byly ve formátu

OUTER APPLY dbo.SomeFunction(...) F

A vrátil správné výsledky, když byl zapsán jako

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

Takže to vypadá jako možné řešení.

Pro dotaz

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;

Prováděcí plán vypadá takto

A seznam výstupních sloupců v konečné projekci je. Expr1000, Expr1001, Expr1003, Expr1004.

V tabulce konstant vpravo dole jsou však definovány pouze dva z těchto sloupců.

Doslovné $350000 je definována v tabulce konstant vpravo nahoře (Expr1001). To se pak vnější připojí k tabulce konstant vpravo dole. Protože podmínce spojení neodpovídají žádné řádky, dva sloupce zde definované (Expr1003, Expr1004) jsou správně vyhodnoceny jako NULL. pak nakonec výpočetní skalár přidá doslovný 12 do datového toku jako nový sloupec (Expr1000) bez ohledu na výsledek vnějšího spojení.

To není vůbec správná sémantika. Porovnejte se (správným) plánem, když je inline TVF vložen ručně.

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 

Zde jsou sloupce použité v konečné projekci Expr1003, Expr1004, Expr1005, Expr1006 . Všechny jsou definovány v konstantním skenování vpravo dole.

V případě TVF se zdá, že se vše pokazí velmi brzy.

Přidávání OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606); ukazuje, že vstupní strom procesu je již nesprávný. Vyjádřeno v SQL je to něco jako.

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 

Úplný výstup tohoto příznaku trasování je následující (A 8605 ukazuje v podstatě stejný strom.)

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

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


  1. Vytvoření seznamu hodnot oddělených čárkami v příkazu Oracle SQL

  2. Chyba přístupu odepřen při použití mysql_real_escape_string()

  3. Jaký typ sloupce používá SQLAlchemy pro text na MySQL?

  4. Použití názvu aliasu v jiném sloupci