Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Áp dụng bên ngoài Trả về các cột bất ngờ KHÔNG ĐỦ khi không có kết quả phù hợp

Đây chắc chắn là một lỗi trong sản phẩm.

Một lỗi tương tự đã được báo cáo và đóng lại là "Sẽ không sửa chữa" .

Bao gồm câu hỏi này, mục kết nối được liên kết và khác hai câu hỏi trên trang web này Tôi đã thấy bốn trường hợp của loại hành vi này với TVF nội tuyến và OUTER APPLY - Tất cả chúng đều có định dạng

OUTER APPLY dbo.SomeFunction(...) F

Và trả về kết quả chính xác khi được viết là

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

Vì vậy, đây có vẻ như là một giải pháp khả thi.

Đối với truy vấn

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;

Kế hoạch thực hiện giống như

Và danh sách các cột đầu ra trong hình chiếu cuối cùng là. Expr1000, Expr1001, Expr1003, Expr1004.

Tuy nhiên, chỉ có hai trong số các cột đó được xác định trong bảng hằng số ở phía dưới bên phải.

Chữ $350000 được định nghĩa trong bảng hằng số ở trên cùng bên phải (Expr1001). Điều này sau đó được nối bên ngoài vào bảng hằng số ở phía dưới bên phải. Vì không có hàng nào phù hợp với điều kiện nối nên hai cột được xác định ở đó (Expr1003, Expr1004) được đánh giá chính xác là NULL. sau đó cuối cùng vô hướng tính toán thêm vào 12 theo nghĩa đen vào luồng dữ liệu dưới dạng cột mới (Expr1000) bất kể kết quả của phép nối ngoài.

Đây hoàn toàn không phải là ngữ nghĩa chính xác. So sánh với kế hoạch (đúng) khi TVF nội tuyến được nội tuyến theo cách thủ công.

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 

Ở đây, các cột được sử dụng trong phép chiếu cuối cùng là Expr1003, Expr1004, Expr1005, Expr1006 . Tất cả những điều này được xác định trong quá trình quét liên tục dưới cùng bên phải.

Trong trường hợp của TVF, tất cả dường như đã sai ngay từ rất sớm.

Thêm OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606); hiển thị cây đầu vào cho quá trình đã không chính xác. Được thể hiện trong SQL, nó giống như thế này.

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 

Đầu ra đầy đủ của cờ theo dõi đó như sau (Và 8605 về cơ bản hiển thị cùng một cây.)

*** 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. Thêm một cột vào bảng, nếu nó chưa tồn tại

  2. Làm cách nào để băm mật khẩu quản trị viên trong bảng Người dùng của tôi?

  3. Truy vấn SQL với KHÔNG THÍCH TRONG

  4. Cài đặt SQL Server 2019 trên máy Mac

  5. Tại sao lại sử dụng mệnh đề INCLUDE khi tạo chỉ mục?