2015-09-04 3 views
14

मैं बाहरी आवेदन के साथ उपयोग किए जाने पर एक तालिका मूल्यवान फ़ंक्शन पर कुछ अजीब व्यवहार मार रहा हूं। मेरे पास एक साधारण इनलाइन फ़ंक्शन है जो किसी अन्य तालिका में पंक्ति के आधार पर कुछ सरल गणना देता है। जब टीवीएफ के लिए इनपुट मान हार्ड-कोड वाले स्केलर होते हैं, तो कोई पंक्ति वापस नहीं होती है। जब मैं एक ही स्केलर लेता हूं और सीटीई में उनमें से एक पंक्ति बना देता हूं, तो उन्हें क्रॉस एपली का उपयोग करके कॉलम के रूप में खिलाएं, कोई परिणाम सेट नहीं। जब मैं बाहरी आवेदन के साथ ऐसा करता हूं, तो मुझे 1 पंक्ति (अपेक्षित के रूप में) मिलती है, लेकिन आउटपुट कॉलम में से दो NULL और अन्य दो NOT NULL हैं। बीओएल के आधार पर, यह OUTER APPLY के साथ नहीं होना चाहिए। क्या यह एक उपयोगकर्ता त्रुटि है? मैंने इस मुद्दे को प्रदर्शित करने के लिए एक सरल संस्करण लिखा था।बाहरी रिटर्निंग कॉलम अप्रत्याशित रूप से न्यूल करें जब कोई मिलान

--Test set-up 
CREATE FUNCTION dbo.TVFTest 
(
     @keyID INT, 
     @matchValue1 MONEY, 
     @matchValue2 MONEY 
) 
RETURNS TABLE AS RETURN 
(
WITH TestRow 
    AS (SELECT @keyID  AS KeyID, 
       @matchValue1 AS MatchValue1, 
       @matchValue2 AS MatchValue2) 
SELECT KeyID, 
     MatchValue1, 
     MatchValue2, 
     CASE 
     WHEN MatchValue1 <> MatchValue2 
      THEN 'Not equal' 
     ELSE 'Something else' 
     END AS MatchTest 
FROM TestRow 
WHERE MatchValue1 <> MatchValue2 
) 
GO 

क्वेरी

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; 

परिणाम

+-------+-------------+-------------+-----------+ 
| KeyID | MatchValue1 | MatchValue2 | MatchTest | 
+-------+-------------+-------------+-----------+ 
| 12 | 350000.00 | NULL  | NULL  | 
+-------+-------------+-------------+-----------+ 

अपेक्षा के अनुरूप Cross Apply रिटर्न नहीं पंक्तियों का उपयोग करना। सीटीई को हटाने और इनलाइन स्थिरांक का उपयोग करने से कोई पंक्ति नहीं आती है।

--Scalars, no row here... 
SELECT LP.* 
FROM dbo.TVFTest 
(
     12, 
     $350000, 
     350000 
) LP; 
+0

मेरा मानना ​​है कि यह है क्योंकि आप अपने TVF में एक फिल्टर है '' कहां MatchValue1 इस प्रकार है (और 8605 मूल रूप से एक ही पेड़ को दर्शाता है।) है! = MatchValue2'' और आपके प्रत्येक परीक्षण मिलान मानों की आपूर्ति करता है। तो यह कोई मैच नहीं देता है। उस स्थिति को हटाएं और मुझे लगता है कि आपको अपेक्षित परिणाम मिलेंगे। ... एनवीआर दिमाग, आपके प्रश्न का गलत व्याख्या कर सकता है ... – cocogorilla

+0

आउटपुट आवेदन को समारोह के खिलाफ बाहरी जुड़ाव के समान व्यवहार करना चाहिए। मैंने 0 परिणाम लौटने के लिए यह उदाहरण चुना है। लेकिन, टीवीएफ द्वारा लौटाए गए सभी कॉलम पूर्ण होना चाहिए। पहला नहीं है। मेरा सवाल है - क्यों? क्या मेरे कोड में कोई बग है या यह कुछ और है? – CDC

+0

आप बिल्कुल सही हैं ... वह WEIRD है ... आप वास्तव में इसे पांच कॉलम डंप करने के लिए प्राप्त कर सकते हैं ...किसी कारण से, matchid टीवीपी उपनाम के माध्यम से आ रहा है ... और मैं नहीं देख सकता कि यह क्यों चाहिए। – cocogorilla

उत्तर

14

यह निश्चित रूप से उत्पाद में एक बग है।

एक समान बग was already reported and closed as "Won't Fix"

इस सवाल है, लेकिन संबद्ध कनेक्ट आइटम और इस साइट मैं इनलाइन TVFs और OUTER APPLY साथ व्यवहार के इस प्रकार के चार मामलों को देखा है पर anothertwo सवाल भी शामिल है - वे सब के सब प्रारूप के थे

OUTER APPLY dbo.SomeFunction(...) F 

और

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

के रूप में लिखा गया सही परिणाम लौटाए तो यह एक संभावित कामकाज की तरह दिखता है।

क्वेरी

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; 

कार्य योजना लागू करके दिखता है

enter image description here

और अंतिम प्रक्षेपण में उत्पादन स्तंभों की सूची है

तरह लिए

। Expr1000, Expr1001, Expr1003, Expr1004।

हालांकि उन दो स्तंभों को नीचे दाईं ओर स्थिरांक की तालिका में परिभाषित किया गया है।

शाब्दिक $350000 शीर्ष दाएं (Expr1001) में स्थिरांक की तालिका में परिभाषित किया गया है। यह तब नीचे दाईं ओर स्थिरांक की मेज पर बाहरी हो जाता है। चूंकि कोई भी पंक्तियां जुड़ने की स्थिति से मेल नहीं खाती हैं, वहां परिभाषित दो कॉलम (Expr1003, Expr1004) को सही रूप से पूर्ण के रूप में मूल्यांकन किया जाता है। फिर आखिर में गणना स्केलर बाहरी जुड़ने के परिणाम के बावजूद एक नए कॉलम (Expr1000) के रूप में डेटा प्रवाह में शाब्दिक 12 जोड़ता है।

ये सभी सही अर्थशास्त्र नहीं हैं। इनलाइन टीवीएफ मैन्युअल रूप से रेखांकित होने पर (सही) योजना के साथ तुलना करें।

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 

enter image description here

यहाँ अंतिम प्रक्षेपण में इस्तेमाल कॉलम Expr1003, Expr1004, Expr1005, Expr1006 हैं। इन सभी को निचले दाएं निरंतर स्कैन में परिभाषित किया गया है।

टीवीएफ के मामले में यह सब बहुत जल्दी गलत लगता है।

OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606); जोड़ना प्रक्रिया में इनपुट पेड़ पहले से ही गलत है। एसक्यूएल में व्यक्त किया गया यह कुछ ऐसा है।

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 

कि झंडा निशान से भरा उत्पादन

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

******************* 
+0

धन्यवाद मार्टिन। मैं इस पर बहुत गहन शोध की सराहना करता हूं। मुझे लगता है कि मुझे एक काम मिल जाएगा, मुझे लगता है, क्योंकि इस पर एक कनेक्ट आइटम है जिसे "ठीक नहीं किया जाएगा" के रूप में चिह्नित किया गया है। इस बीच, मैं इस पर एक कनेक्ट आइटम खोलूंगा। धन्यवाद! – CDC

+0

@CDC - अगर आपको कोई दिलचस्प प्रतिक्रिया मिलती है तो कृपया अपडेट करें, –

2

मैंने कुछ और शोध (एसक्यूएल सर्वर 2012) किया - और यह वास्तव में अजीब है!

आप इसे सरल बना सकते हैं। ऐसा लगता है कि इसमें अंतर्निहित प्रकार के रूपांतरण के साथ कुछ करना है। यही वजह है कि मैं डेटा प्रकार के साथ चारों ओर करने की कोशिश की है ...

इस प्रयास करें:

--Test set-up 
CREATE FUNCTION dbo.TVFTest 
(
     @ValueInt INT, 
     @ValueMoney MONEY, 
     @ValueVarchar VARCHAR(10), 
     @ValueDate DATE, 
     @DateAsVarchar DATE 

) 
RETURNS TABLE AS RETURN 
(
     SELECT @ValueInt AS ValueInt 
      ,@ValueMoney AS ValueMoney 
      ,@ValueVarchar AS ValueVarchar 
      ,@ValueDate AS ValueDate 
      ,@DateAsVarchar AS DateAsVarchar 
     WHERE 1 != 1 
) 
GO 

इस समारोह कहां की वजह से एक लाइन वापस कभी नहीं होगा ...

DECLARE @d AS DATE='20150101'; 

इस टाइप बाद की तारीख चर की जरूरत है, GETDATE() के आधार पर कॉल में इसे बदलना

--direct call: comes back with no row 
SELECT * FROM dbo.TVFTest(1,2,'test',@d,'20150101'); 

--parameters via CTE: 
WITH Test AS 
(
     SELECT 1 AS valint, 
       2 AS valmoney, 
       'test' AS valchar, 
       @d AS valdate, --try GETDATE() here! 
       '20150101' AS valdateasvarchar 
) 
SELECT * 
FROM Test AS T 
OUTER APPLY dbo.TVFTest(T.valint,T.valmoney,T.valchar,T.valdate,T.valdateasvarchar) AS LP; 

दोनों परोक्ष सी कोशिश ... उल्टा पैरामीटर (मनी और डेटएस्वार्कर) दिखाई नहीं देते हैं, लेकिन आईएनटी, वचरर और "असली" DATE !!!
निष्पादन योजना को देखें: enter image description here यह कॉल GETDATE() के साथ किया गया था। अन्यथा केवल 2 अदिश ऑपरेटरों ...

संपादित होगा: पहली "कंप्यूट अदिश" निष्पादन योजना में सभी स्तंभों पता चलता है, लगातार स्कैन (स्थिरांक के साथ एक आंतरिक तालिका स्कैनिंग) तीन यदि केवल दो कॉलम (आप GETDATE() का उपयोग करते हैं)। "बुरा" कॉलम भी इस स्तर पर CTE का हिस्सा होने लगते हैं नहीं ...

--parameters via CTE with single calls 
WITH Test AS 
(
     SELECT 1 AS valint, 
       2 AS valmoney, 
       'test' AS valchar, 
       @d AS valdate, 
       '20150101' AS valdateasvarchar 
) 
SELECT * FROM dbo.TVFTest((SELECT valint FROM Test) 
         ,(SELECT valmoney FROM Test) 
         ,(SELECT valchar FROM Test) 
         ,(SELECT valdate FROM Test) 
         ,(SELECT valdateasvarchar FROM Test)); 
GO 
DROP FUNCTION dbo.TVFTest; 

बस का एक और अवसर, इस अपेक्षित परिणाम (खाली)

मेरे conclusio साथ देता है: केवल स्केलर वैल्यू जिन्हें कुछ अतिरिक्त हैंडलिंग की आवश्यकता होती है उन्हें संभाला जाता है और इसलिए "पता" है कि उन्हें दिखाना नहीं चाहिए। सभी स्केलर मान जिन्हें बिना किसी अतिरिक्त काम के पारित किया जा सकता है, को फ़ंक्शन के भीतर प्रबंधित नहीं किया जाता है और दिखाया जाता है - जो एक बग है।

आपकी राय क्या है?

+0

इस पर ध्यान देने के लिए धन्यवाद। मैं सभी खुदाई की सराहना करता हूं। मार्टिन ने सिर पर नाखून मारा, हालांकि, और कनेक्ट बग को इंगित किया जो पहले से ही इसके लिए दायर किया गया था। – CDC

संबंधित मुद्दे