2012-05-22 19 views
9

क्षमा करें अगर यह उपयुक्त नहीं है, लेकिन वास्तव में यह 'कैसे' की बजाय 'क्यों' है। यह सुनिश्चित नहीं है कि यह उपयुक्त है, लेकिन पूछने के लिए एक बेहतर जगह नहीं पता है और मैं नहीं सोच सकता कि Google को वाक्यांश कैसे प्राप्त किया जाए, जो मैं ढूंढ रहा हूं।आईएफ क्लॉज के एसक्यूएल मूल्यांकन

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT log(0) 
    END 

उस कथन को देखें। ऐसी कोई दुनिया नहीं है जिसमें आईएफ खंड सत्य होगा। अगर मैं इसे चलाने का प्रयास करता हूं तो मुझे उम्मीद है कि एसक्यूएल आईएफ क्लॉज से आगे बढ़कर अंत तक चलेगा। इसके बजाय मुझे मिलता है:

An invalid floating point operation occurred. 

यह विचित्र है। तो मुझे लगता है कि यह वही तरीका है जो एसक्यूएल यह काम करता है। इसके अलावा ...

IF 'hell' = 'freezing over' 
    BEGIN 
    SELECT 1/0 
    END 

यहां कोई त्रुटि नहीं है। आईएफ खंड में बयान अभी भी एक त्रुटि उत्पन्न करना चाहिए। क्या कोई यह समझा सकता है कि यह क्यों नहीं हो रहा है?

यह एसक्यूएल कैल्क्स के बड़े पैमाने पर सेट डीबगिंग करते समय आया, जहां EXP (SUM (LOG())) का उपयोग किसी खंड में डेटा जमा करने के लिए किया जाता है। मैं कोड को फिर से होने से रोकने के लिए बदल सकता हूं, लेकिन यह एक आईएफ खंड में कुछ क्यों मूल्यांकन कर रहा है जो पूरा नहीं हुआ है।

चीयर्स।

संपादित करें: अतिरिक्त मनोरंजन। पकड़ने की कोशिश? Pffft

IF 1=2 
    BEGIN 
     BEGIN TRY 
      SELECT SQRT(-1) 
     END TRY 
     BEGIN CATCH 
     END CATCH 
    END 

गैर गणितीय:

IF 1=2 
    BEGIN 
    SELECT SUBSTRING('hello',-1,-1) 
    END 

उत्तर

7

मेरा अनुमान होगा कि log(0) प्रभावी रूप से समय से पहले ही मूल्यांकन किया जाता है की वजह से constant-folding जबकि 1/0 है नहीं, या तो उसकी गणनसंख्या आकलन या अधिक होने की संभावना तथ्य यह है कि ANSI_WARNINGS सेटिंग शून्य (अतिप्रवाह बनाम द्वारा विभाजन के वांछित परिणाम को प्रभावित करेगा के कारण शून्य)।

+0

एएनएसआई चेतावनियों ने कोई फर्क नहीं पड़ता, लेकिन यह वह लिंक है जो मुझे लगता है कि मुझे बहुत धन्यवाद है :) –

+0

आपका स्वागत है। ANSI_WARNINGS द्वारा मेरा मतलब था कि यदि किसी भी समय "सेट ansi_warnings off" जारी किया गया था तो आपको शून्य त्रुटि से विभाजित नहीं दिखाई देगा। चूंकि कंपाइलर पहले से कभी एएनएसआई_वार्निंग्स ध्वज की स्थिति को पहले से नहीं जानता है, जब संकलित क्वेरी चलती है, तो उसे किसी भी फोल्ड अभिव्यक्ति को अनदेखा करना चाहिए जो संकलन समय पर शून्य अपवाद द्वारा विभाजित करता है क्योंकि यह वांछित व्यवहार की भविष्यवाणी नहीं कर सकता है। (यदि ansi_warnings हमेशा 1/0 बंद होने की गारंटी दी जाती है तो NULL में गुना होगा) –

2

पार्सर बस स्मार्ट के अपने यदि तर्क का पालन करने की जरूरत नहीं है। निम्न उदाहरण पर विचार करें:

IF (1 = 0) 
BEGIN 
    CREATE TABLE #t(x INT): 
END 
ELSE 
BEGIN 
    CREATE TABLE #t(x INT): 
END 

आप इसे निष्पादित या यहाँ तक कि बस इसे पार्स हैं, पार्सर बैच में CREATE TABLE बयानों के सभी को देखता है और निर्धारित करता है कि आप तालिका में दो बार बनाने की कोशिश की (पहली प्रति स्पष्ट रूप से नहीं करता है ऐसा होने के लिए अस्तित्व में नहीं होना चाहिए)। परिणाम:

संदेश 2714, स्तर 16, राज्य 1, लाइन 7
वहां पहले से ही है एक वस्तु नामित डेटाबेस में '#t'।

मुझे वास्तव में पता नहीं है कि मेरे पास पार्सर जितना स्मार्ट नहीं है, उसके लिए मेरे पास बेहतर जवाब है या नहीं।

गतिशील एसक्यूएल का उपयोग करके रनटाइम तक समस्या का निवारण करके आप पार्सर को पराजित कर सकते हैं, उदा।

IF 'hell' = 'freezing over' 
BEGIN 
    EXEC sp_executesql N'SELECT log(0);'; 
END 

लेकिन तब मुझे आश्चर्य है कि करने के लिए एक शर्त है कि सच कभी नहीं होगा के लिए मचान की स्थापना, और एक बयान आप जानते हैं कि त्रुटि के लिए जा रहा है जारी करने की बात क्या है होगा?

+0

लगभग 5 आईएफ स्थितियां हैं। उनमें से एक में डेटा पर एक गणना की जाती है जो अन्य स्थितियों में त्रुटियों का कारण बनती है। ये उदाहरण व्यवहार दिखाने के लिए तुच्छ हैं। यह की तरह था [डेटा त्रुटि नहीं देगा] "कैलक करें" END –

+0

इसके अलावा, दिलचस्प रूप से यह ठीक से पार्स करता है, लेकिन सफलतापूर्वक निष्पादित नहीं करता है –

+0

हां पार्सर हमेशा सभी प्रकार की त्रुटियों को पहले से नहीं पकड़ता है, और कुछ पहले से पकड़ता है कि रनटाइम पर कभी भी त्रुटियां नहीं होतीं। जैसा कि मैंने कहा, यह सबसे बुद्धिमान नहीं है। लेकिन इसमें जटिल नियमों और एल्गोरिदम का एक * बहुत * है जो यह निर्धारित करने के लिए है कि यह सफलतापूर्वक विश्लेषण करने की अनुमति देगा और यह क्या नहीं करेगा।इन नियमों को दस्तावेज नहीं किया गया है, इसलिए @ गॉर्डन लिनॉफ ने आपको समझाया कि आपको पता होना चाहिए कि किस प्रकार की चीजें पार्सर की यात्रा करेंगी और यह किस तरह की चीजें स्लाइड करेगी। –

0

स्पष्ट रूप से, कुछ अभिव्यक्तियां हैं कि SQL कंपाइलर रन टाइम पर बनाम संकलन समय पर मूल्यांकन करने का प्रयास कर रहा है। मेरा अनुमान है कि एक विभाजन को बहुत महंगा नहीं माना जाता है, इसलिए यह इसे रन टाइम पर स्थगित कर देता है। दूसरी तरफ, लॉग() की तरह वास्तव में जटिल कुछ महंगा है और वे इसे संकलित समय पर करना चाहते हैं।

यह अनुमान है। इसका मतलब यह भी है कि इस तरह के मतभेद गैर-निर्धारक हैं।आपको यह पता लगाना होगा कि कौन सा काम किसी विशेष स्क्रिप्ट में काम करता है या काम नहीं करता है - और व्यवहार डेटाबेस के रिलीज के बीच बदल सकता है।

2

अगर मैं करने के लिए रन यह मैं एसक्यूएल अतीत यदि खंड कूद और अंत करने के लिए स्थानांतरित करने के लिए उम्मीद कर रहा हूँ का प्रयास।

जब आप अपने बैच चलाने तीन चीज़ें हो

  1. आपका एसक्यूएल पार्स किया गया है

  2. आपका एसक्यूएल संकलित किया गया है

  3. आपका एसक्यूएल निष्पादित किया जाता है

क्या है rtunate यह है कि SQL सर्वर में बैच में संकलन और निष्पादन त्रुटियों दोनों के परिणामस्वरूप "त्रुटियों के साथ पूर्ण क्वेरी" संदेश होता है। तो एक प्रक्रिया जहां इसकी आसान अंतर

देखने के लिए उपयोग करने पर विचार करें निम्नलिखित

Create proc compiletime 
as 
SELECT log(0) 
SELECT SQRT(-1) 
SELECT SUBSTRING('hello',-1,-1) 
SELECT 1/0 

यही प्रक्रिया ठीक से पार्स करने देता है। हालांकि इसे संकलित नहीं किया जा सकता है जब तक कि हम पहले थेरे SELECT को हटा दें क्योंकि हमारे पास कुछ स्थिरांक हैं जो पैरामीटर के रूप में अमान्य हैं। यह अच्छा होगा अगर SELECT 1/0 ने रन टाइम त्रुटि के बजाय संकलन समय त्रुटि भी उत्पन्न की लेकिन जैसा कि @Alex K व्यवहार को इंगित करता है, ANSI_WARNINGS पर आधारित है, इसलिए यह संकलन समय त्रुटि नहीं है।

इसलिए हम पहले दो के बीच अंतर देखते हैं। यह भी बताता है कि क्यों संकलन समय त्रुटि के बाद TRY कैच काम नहीं करता था।

अब SQL सर्वर पहुंचने योग्य कोड क्यों संकलित करता है। क्योंकि सामान्य में यह जानने के लिए कि यह पहुंच योग्य नहीं है, को रोकने की समस्या का हल करने की आवश्यकता है। आप कुछ मामलों लेकिन फिर इस के लिए इसे हल कर सकते हैं ...


DECLARE @x as integer 
SET @x = SomeFunction() 
If (1 = @x) 
    SomeCompiletime error 

अलग व्यवहार जो और भी अधिक भ्रामक है होगा।

if (1=0) 
    SomeCompiletime error 
संबंधित मुद्दे