Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Terapkan Luar Mengembalikan kolom secara tidak terduga NOT NULL saat tidak ada kecocokan

Ini tentu saja merupakan bug dalam produk.

Bug serupa telah dilaporkan dan ditutup sebagai "Tidak Akan Memperbaiki" .

Termasuk pertanyaan ini, item koneksi tertaut dan lainnya dua pertanyaan di situs ini Saya telah melihat empat kasus perilaku seperti ini dengan TVF sebaris dan OUTER APPLY - Semuanya berformat

OUTER APPLY dbo.SomeFunction(...) F

Dan mengembalikan hasil yang benar ketika ditulis sebagai

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

Jadi ini sepertinya solusi yang mungkin.

Untuk kueri

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;

Rencana eksekusi terlihat seperti

Dan daftar kolom keluaran dalam proyeksi akhir adalah. Ekspr1000, Ekspr1001, Ekspr1003, Ekspr1004.

Namun hanya dua dari kolom tersebut yang didefinisikan dalam tabel konstanta di kanan bawah.

$350000 harfiah didefinisikan dalam tabel konstanta di kanan atas (Expr1001). Ini kemudian akan digabungkan ke luar ke tabel konstanta di kanan bawah. Karena tidak ada baris yang cocok dengan kondisi gabungan, dua kolom yang ditentukan di sana (Expr1003, Expr1004) dievaluasi dengan benar sebagai NULL. lalu akhirnya skalar komputasi menambahkan 12 literal ke dalam aliran data sebagai kolom baru (Expr1000) terlepas dari hasil gabungan luar.

Ini sama sekali bukan semantik yang benar. Bandingkan dengan paket (yang benar) saat TVF sebaris disejajarkan secara manual.

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 

Di sini kolom yang digunakan dalam proyeksi akhir adalah Expr1003, Expr1004, Expr1005, Expr1006 . Semua ini didefinisikan di pemindaian konstan kanan bawah.

Dalam kasus TVF, semuanya tampak salah sejak awal.

Menambahkan OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606); menunjukkan pohon input ke proses sudah salah. Dinyatakan dalam SQL seperti ini.

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 

Output lengkap dari flag trace tersebut adalah sebagai berikut (Dan 8605 pada dasarnya menunjukkan pohon yang sama.)

*** 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apa itu Pemblokiran SQL Server?

  2. Bagaimana cara mengubah String ke Hex dan sebaliknya?

  3. Bagaimana menemukan gaji maksimum ketiga atau n dari tabel gaji?

  4. Bisakah saya menggunakan variabel saat menggunakan ISABOUT?

  5. Memaksa code-first untuk selalu menginisialisasi database yang tidak ada?