2010-09-21 10 views
6

मुझे एक प्रश्न है जो मैंने अभी डेटाबेस में पाया है जो एक रिपोर्ट को गिरने में असफल रहा है। क्वेरी के बुनियादी सार:मैं न्यूमेरिक फ़ील्ड पर संख्यात्मक डेटा के बीच 'क्वेरी' कैसे पूछ सकता हूं?

Select * 
From table 
Where IsNull(myField, '') <> '' 
And IsNumeric(myField) = 1 
And Convert(int, myField) Between @StartRange And @EndRange 

अब, myField सभी पंक्तियों [यह nvarchar प्रकार का है] में संख्यात्मक डेटा शामिल नहीं है ... लेकिन इस क्वेरी स्पष्ट रूप से डिजाइन किया गया था इस तरह है कि यह केवल पंक्तियों का ध्यान रखता है जहां इस क्षेत्र में डेटा संख्यात्मक है।

इस के साथ समस्या यह है कि T-SQL (जैसा कि मैं समझता हूँ के पास) जहां खंड इस प्रकार यह रिकॉर्ड जहां डाटा अपवाद के साथ संख्यात्मक नहीं है पर बाहर खाई करने के लिए पैदा कर रहा shortcircuit नहीं करता है:

Msg 245, Level 16, State 1, Line 1 Conversion failed when converting the nvarchar value '/A' to data type int.

उन सभी पंक्तियों को डंप करने का छोटा जहां MyField एक अस्थायी तालिका में संख्यात्मक है और फिर उन पंक्तियों के लिए पूछताछ करता है जहां फ़ील्ड निर्दिष्ट सीमा में है, मैं यह क्या कर सकता हूं यह इष्टतम है?

मेरी पहली पार्स विशुद्ध रूप से दिए गए डेटा का विश्लेषण करने और देखने के लिए प्रयास करने के लिए क्या हो रहा था जा रहा था:

Select * 
From (
    Select * 
    From table 
    Where IsNull(myField, '') <> '' 
    And IsNumeric(myField) = 1 
) t0 
Where Convert(int, myField) Between @StartRange And @EndRange 

लेकिन मैं एक ही त्रुटि मैं पहली बार क्वेरी जो मुझे यकीन है कि मुझे समझ में नहीं कर रहा हूँ के लिए किया था प्राप्त क्योंकि मैं किसी भी डेटा को परिवर्तित नहीं कर रहा हूं जो इस बिंदु पर संख्यात्मक नहीं होना चाहिए। सबक्वायरी केवल पंक्तियों को वापस करनी चाहिए जहां MyField में संख्यात्मक डेटा होता है।

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

अग्रिम धन्यवाद

+0

ली गई तालिका तो पहले materialized नहीं प्राप्त करता है 'WHERE' खंड लागू होता है। इसे एक ऐसे दृश्य के रूप में माना जाता है जहां ऑप्टिमाइज़र एक दूसरे को फिर से लिखने के लिए एक रिलेशनल बीजगणित पीओवी के समान होता है, वे वही होते हैं। –

+0

[इस पृष्ठ] के अनुसार (http://msdn.microsoft.com/en-us/library/aa226054 (SQL.80% 29.aspx), स्पष्ट रूप से 'nvchar' को' int' में परिवर्तित करने की आवश्यकता नहीं है। – NullUserException

उत्तर

5

IsNumeric केवल आपको बताता है कि स्ट्रिंग एसक्यूएल सर्वर में की एक सांख्यिक प्रकार के लिए परिवर्तित किया जा सकता है। यह इसे पैसे, या एक फ्लोट में परिवर्तित करने में सक्षम हो सकता है, लेकिन हो सकता है कि इसे एक int में परिवर्तित करने में सक्षम न हो।

बदलें अपनी

IsNumeric(myField) = 1 

होने के लिए:

not myField like '%[^0-9]%' and LEN(myField) < 9 

(जो है, आप myField केवल अंक होने, और एक पूर्णांक में फिट करना चाहते हैं)

संपादित उदाहरण:

select ISNUMERIC('.'),ISNUMERIC('£'),ISNUMERIC('1d9') 

परिणाम:

----------- ----------- ----------- 
1   1   1 

(1 row(s) affected) 
+0

केस स्टेटमेंट के संयोजन में यह एक आकर्षण की तरह काम करता है। आपने वास्तव में मुझे अंकगणित ओवरफ्लो को उस संख्या को परिवर्तित करने में मदद की जो कि बिगिन के लिए बहुत लंबा था। तो वह सहायक था। +1 – BenAlabaster

+0

@ बेनएलाबस्टर - उत्कृष्ट - इसलिए मैंने इसे पोस्ट करने का मौका मिलने से पहले आपके अनुवर्ती प्रश्न का उत्तर दिया? :-) –

3

में आप एक निश्चित क्रम में भाव का मूल्यांकन करने के लिए SQL मजबूर करने के लिए होगा। यह एक काम की मेज पर एक तरह से मजबूर करता: यहाँ एक समाधान

Select * 
From (TOP 2000000000 
    Select * 
    From table 
    Where IsNumeric(myField) = 1 
    And IsNull(myField, '') <> '' 
    ORDER BY Key 
) t0 
Where Convert(int, myField) Between @StartRange And @EndRange 

और एक अन्य

Select * 
From table 
Where 

CASE 
    WHEN IsNumeric(myField) = 1 And IsNull(myField, '') <> '' 
    THEN Convert(int, myField) ELSE @StartRange-1 
END Between @StartRange And @EndRange 
  • पहली तकनीक "मध्यवर्ती materialisation" है।
  • 2 मामले आदेश मूल्यांकन पर निर्भर करता है की गारंटी है
  • न तो सुंदर या whizzy

एसक्यूएल कथात्मक है: आप अनुकूलक बताएं कि आप क्या चाहते हैं, यह करने के लिए कैसे नहीं। बल के ऊपर की चाल एक निश्चित क्रम में किया जाना चाहिए।

+0

असल में, प्रश्न यह साबित करता है कि यह एसक्यूएल कार्यान्वयन घोषणात्मक नहीं है। आप ऑप्टिमाइज़र को जो भी चाहते हैं उसे बताएं, और यह आपकी घोषणा को एक व्यवहार्य निष्पादन योजना में बदलने में विफल रहता है। एक वास्तविक घोषणात्मक भाषा में, यहां तक ​​कि स्थिति 'कन्वर्ट (int, myField) @StartRange और @EndRange और IsNumeric (MyField) = 1' के बीच सही है। (टर्नरी लॉजिक के साथ आसान, जहां 'नल और गलत' 'गलत है ') – MSalters

+0

@MSalters: मैं कहूंगा कि बीच या ISNUMERIC विरोधाभासी हैं वह स्तर। एसक्यूएल इसकी घोषणात्मक चीज कर रहा है और यह तय कर रहा है कि डेटा को कैसे प्राप्त किया जाए, बॉट्स को शर्तों का मूल्यांकन करने के लिए ऑर्डर करें। बीटवेन इंडेक्स का उपयोग करने की अधिक संभावना है, ISNUMERIC नहीं है। बकवास डेटा की वजह से एक बकवास क्वेरी को पुनर्लेखित करना हिस्सा नहीं है "घोषणात्मक" परिभाषा – gbn

+0

सॉर का वाई, सोचा था कि "टर्नरी लॉजिक" बिट ने इसे स्पष्ट कर दिया। जब भी 'IsNumeric' पक्ष FALSE का मूल्यांकन करता है तो अभिव्यक्ति का' कनवर्ट 'पक्ष न्यूल (त्रुटि) का मूल्यांकन करेगा। एक वास्तविक घोषणात्मक भाषा इस "कचरा प्रश्न" का न्याय नहीं करेगी क्योंकि नतीजा बहुत अच्छी तरह परिभाषित है। – MSalters

1

यह सुनिश्चित नहीं है कि यह आपकी मदद करता है, लेकिन मैंने कहीं पढ़ा है कि CONVERT का उपयोग करके गलत रूपांतरण हमेशा SQL में त्रुटि उत्पन्न करेगा। तो मुझे लगता है कि सीएएसई का उपयोग करना बेहतर होगा जहां सभी पंक्तियों पर कनवर्ट करने से रोकने के लिए क्लॉज

+0

यह काम करता है, मुझे यकीन नहीं है कि यह इष्टतम है, लेकिन यह पहले से कम से कम एक कदम आगे है। धन्यवाद। – BenAlabaster

1

CASE कथन का उपयोग करें।

declare @StartRange int 
declare @EndRange int 

set @StartRange = 1 
set @EndRange = 3 

select * 
from TestData 
WHERE Case WHEN ISNUMERIC(Value) = 0 THEN 0 
      WHEN Value IS NULL THEN 0 
      WHEN Value = '' THEN 0 
      WHEN CONVERT(int, Value) BETWEEN @StartRange AND @EndRange THEN 1 
      END = 1 
संबंधित मुद्दे

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