SQL सर्वर में अग्रणी शून्य ट्रिमिंग के लिए बेहतर तकनीक?


161

मैं उपयोग कर रहे हैं यह कुछ समय के लिए:

SUBSTRING(str_col, PATINDEX('%[^0]%', str_col), LEN(str_col))

हालाँकि हाल ही में, मुझे '00000000' जैसे सभी "0" पात्रों के साथ कॉलम में एक समस्या मिली है क्योंकि यह कभी भी मैच के लिए गैर-"0" वर्ण नहीं पाता है।

एक वैकल्पिक तकनीक जो मैंने देखी है उसका उपयोग करना है TRIM:

REPLACE(LTRIM(REPLACE(str_col, '0', ' ')), ' ', '0')

यह एक समस्या है अगर वहाँ एम्बेडेड स्थान हैं, क्योंकि वे "0" s में बदल जाएंगे जब रिक्त स्थान "0" s में वापस बदल दिए जाएंगे।

मैं एक स्केलर UDF से बचने की कोशिश कर रहा हूं। मुझे SQL Server 2005 में UDFs के साथ प्रदर्शन समस्याओं का एक बहुत कुछ मिला है।


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

यह एक सामान्य तकनीक है। ये आम तौर पर खाता संख्याएं होती हैं जो एक अनकंफर्टेबल फील्ड में आ रही हैं और मुझे यह सुनिश्चित करने की आवश्यकता है कि वे अपने ईटीएल में डेटा वेयरहाउस का उपयोग करने वाले नियमों से मेल खाएं (जो कि निश्चित रूप से बहुत अधिक फुल-फीचर्ड एसएसआईएस वातावरण में हैं, मुझे लगता है कि वे उपयोग करते हैं। TrimStart)।
कैड रूक्स

जवाबों:


282
SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col))

2
चतुर, काश मैं उस के बारे में सोचा होता।
कैड रूक्स

4
कोई बात नहीं, मुझे एहसास हुआ कि '।' सबस्ट्रिंग में नहीं है क्योंकि यह केवल पैटर्न खोजने के लिए उपयोग किया जाता है - यह जितना मैंने सोचा था उससे कहीं अधिक चतुर है।
केड रूक्स

2
एक फ़ंक्शन में इसे एनकैप्सुलेट करने से मेरे प्रश्नों को धीमा कर दिया गया। मुझे यकीन नहीं है कि क्यों, लेकिन मुझे लगता है कि यह टाइप रूपांतरण के साथ करना है। SUBSTRING इनलाइन का उपयोग करना अधिक तेज था।
रॉनी ओवरबीएल

1
प्रश्न इस समस्या को बताता है जब आप एक शून्य ('0') को पार्स करते हैं, तो आप रिक्त हो जाते हैं। आपको '0' मान और रिक्त मान के बीच अंतर बताने में सक्षम होना चाहिए। कृपया एक पूर्ण समाधान के लिए मेरी पोस्ट देखें: stackoverflow.com/a/21805081/555798
MikeTeeVee

1
@Arvo वाह ... एक मिनट के लिए मैं उलझन में था और मुझे लगा कि मैंने इस सवाल का जवाब दिया जो मेरी मदद करने वाला था। पहली बार मैंने ArvoSO पर एक और देखा है !
अरवो बोवेन

41

आप अभी INTEGERऔर फिर वापस करने के लिए मान क्यों नहीं डालते हैं VARCHAR?

SELECT  CAST(CAST('000000000' AS INTEGER) AS VARCHAR)

--------
       0

11
यह एक स्ट्रिंग कॉलम है, इसलिए मुझे लगता है कि वे समय-समय पर गैर-संख्यात्मक डेटा की अपेक्षा कर रहे हैं। एमआरएन नंबर जैसा कुछ जहां डेटा केवल ज्यादातर संख्यात्मक होता है।
जोएल कोएहॉर्न

1
दुर्भाग्य से, केवल संख्यात्मक डेटा के लिए काम करता है, और कभी-कभी तार पूर्णांक के लिए सीमा से अधिक हो जाते हैं, इसलिए आपको बिगिन का उपयोग करना होगा।
कैड रूक्स

3
SELECT CASE ISNUMERIC(str_col) WHEN 1 THEN CAST(CAST(str_col AS BIGINT) AS VARCHAR(255)) ELSE str_col END
यूरी रोझोवेटस्की 14

यहां तक ​​कि BIGINT, कुछ प्रकार के स्ट्रिंग अभी भी इस रूपांतरण को विफल कर देंगे। 0001E123उदाहरण के लिए विचार करें ।
रोज़ा

1
मेरे परीक्षण (और अनुभव) से यह स्वीकृत उत्तर की तुलना में अपेक्षाकृत महंगा ऑपरेशन है। प्रदर्शन कारणों के लिए, डेटा प्रकार बदलने या विभिन्न प्रकार के डेटा की तुलना करने से बचना सबसे अच्छा है, यदि ऐसा करने की आपकी शक्ति के भीतर है।
रीडस्टोनफूड

14

यदि आपके पास ऑल-जीरो (या एक भी शून्य) है, तो अन्य उत्तरों पर ध्यान नहीं दिया जाना चाहिए।
कुछ हमेशा एक खाली स्ट्रिंग को शून्य में डिफ़ॉल्ट करते हैं, जो कि खाली रहना माना जाता है।
मूल प्रश्न को फिर से पढ़ें। यह प्रश्नकर्ता क्या चाहता है इसका उत्तर देता है।

समाधान # 1:

--This example uses both Leading and Trailing zero's.
--Avoid losing those Trailing zero's and converting embedded spaces into more zeros.
--I added a non-whitespace character ("_") to retain trailing zero's after calling Replace().
--Simply remove the RTrim() function call if you want to preserve trailing spaces.
--If you treat zero's and empty-strings as the same thing for your application,
--  then you may skip the Case-Statement entirely and just use CN.CleanNumber .
DECLARE @WackadooNumber VarChar(50) = ' 0 0123ABC D0 '--'000'--
SELECT WN.WackadooNumber, CN.CleanNumber,
       (CASE WHEN WN.WackadooNumber LIKE '%0%' AND CN.CleanNumber = '' THEN '0' ELSE CN.CleanNumber END)[AllowZero]
 FROM (SELECT @WackadooNumber[WackadooNumber]) AS WN
 OUTER APPLY (SELECT RTRIM(RIGHT(WN.WackadooNumber, LEN(LTRIM(REPLACE(WN.WackadooNumber + '_', '0', ' '))) - 1))[CleanNumber]) AS CN
--Result: "123ABC D0"

समाधान # 2 (नमूना डेटा के साथ):

SELECT O.Type, O.Value, Parsed.Value[WrongValue],
       (CASE WHEN CHARINDEX('0', T.Value)  > 0--If there's at least one zero.
              AND LEN(Parsed.Value) = 0--And the trimmed length is zero.
             THEN '0' ELSE Parsed.Value END)[FinalValue],
       (CASE WHEN CHARINDEX('0', T.Value)  > 0--If there's at least one zero.
              AND LEN(Parsed.TrimmedValue) = 0--And the trimmed length is zero.
             THEN '0' ELSE LTRIM(RTRIM(Parsed.TrimmedValue)) END)[FinalTrimmedValue]
  FROM 
  (
    VALUES ('Null', NULL), ('EmptyString', ''),
           ('Zero', '0'), ('Zero', '0000'), ('Zero', '000.000'),
           ('Spaces', '    0   A B C '), ('Number', '000123'),
           ('AlphaNum', '000ABC123'), ('NoZero', 'NoZerosHere')
  ) AS O(Type, Value)--O is for Original.
  CROSS APPLY
  ( --This Step is Optional.  Use if you also want to remove leading spaces.
    SELECT LTRIM(RTRIM(O.Value))[Value]
  ) AS T--T is for Trimmed.
  CROSS APPLY
  ( --From @CadeRoux's Post.
    SELECT SUBSTRING(O.Value, PATINDEX('%[^0]%', O.Value + '.'), LEN(O.Value))[Value],
           SUBSTRING(T.Value, PATINDEX('%[^0]%', T.Value + '.'), LEN(T.Value))[TrimmedValue]
  ) AS Parsed

परिणाम:

MikeTeeVee_SQL_Server_Remove_Leading_Zeros

सारांश:

आप अग्रणी-शून्य के एक-बंद हटाने के लिए मेरे पास जो कुछ भी है उसका उपयोग कर सकते हैं।
यदि आप इसे बहुत पुन: उपयोग करने की योजना बनाते हैं, तो इसे इनलाइन-टेबल-वैल्यूएड-फंक्शन (आईटीवीएफ) में रखें।
यूडीएफ के साथ प्रदर्शन समस्याओं के बारे में आपकी चिंता समझ में आती है।
हालाँकि, यह समस्या केवल ऑल-स्केलर-फ़ंक्शंस और मल्टी-स्टेटमेंट-टेबल-फ़ंक्शंस पर लागू होती है।
ITVF का उपयोग करना पूरी तरह से ठीक है।

मुझे हमारे तृतीय-पक्ष डेटाबेस के साथ समान समस्या है।
अल्फा-न्यूमेरिक क्षेत्रों के साथ कई अग्रणी स्थानों, खतरे वाले मनुष्यों के बिना प्रवेश किया जाता है!
यह लापता अग्रणी शून्य को साफ किए बिना असंभव में शामिल हो जाता है।

निष्कर्ष:

अग्रणी-शून्य को हटाने के बजाय, आप अपने जुड़ने पर अग्रणी-शून्य के साथ अपने छंटनी-मूल्यों को पैडिंग करने पर विचार कर सकते हैं।
बेहतर अभी तक, अग्रणी शून्य जोड़कर तालिका में अपना डेटा साफ़ करें, फिर अपने अनुक्रमितों का पुनर्निर्माण करें।
मुझे लगता है कि यह तेज़ और कम जटिल होगा।

SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF(' 0A10  ', ''))), 10)--0000000A10
SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF('', ''))), 10)--NULL --When Blank.

4
@DiegoQueiroz यदि उत्तर गलत है, तो कृपया नीचे बताएं और बताएं कि यह काम क्यों नहीं करता है। यदि जवाब काम करता है, लेकिन आपके लिए बहुत व्यापक है, तो कृपया मुझे या इस साइट पर अन्य सदस्यों को नीचा न करें। टिप्पणी के लिये आपका धन्यवाद। यह सुनने के लिए अच्छी प्रतिक्रिया है - मैं इसे ईमानदारी से कहता हूं।
माइकेटीवीई

5

एक जगह के बजाय 0 के 'दुर्लभ' व्हाट्सएप चरित्र के साथ बदलें जो आमतौर पर कॉलम के पाठ में नहीं होना चाहिए। इस तरह से एक कॉलम के लिए एक पंक्ति फ़ीड संभवतः पर्याप्त है। फिर आप सामान्य रूप से LTrim कर सकते हैं और 0 के फिर से विशेष चरित्र को बदल सकते हैं।


3

यदि स्ट्रिंग पूरी तरह से शून्य में है, तो निम्नलिखित '0' लौटाएगा:

CASE WHEN SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) = '' THEN '0' ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) END AS str_col

यह शून्य भी लौटाएगा जब मूल्य में शून्य नहीं है (रिक्त है)।
माइक टिवेवी

क्यों str_col + 'है।' और न केवल str_col? डॉट क्या करता है?
मुफ्लिक्स

2

यह एक अच्छा कार्य करता है ....

DROP FUNCTION [dbo].[FN_StripLeading]
GO
CREATE FUNCTION [dbo].[FN_StripLeading] (@string VarChar(128), @stripChar VarChar(1))
RETURNS VarChar(128)
AS
BEGIN
-- http://stackoverflow.com/questions/662383/better-techniques-for-trimming-leading-zeros-in-sql-server
    DECLARE @retVal VarChar(128),
            @pattern varChar(10)
    SELECT @pattern = '%[^'+@stripChar+']%'
    SELECT @retVal = CASE WHEN SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) = '' THEN @stripChar ELSE SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) END
    RETURN (@retVal)
END
GO
GRANT EXECUTE ON [dbo].[FN_StripLeading] TO PUBLIC

यह शून्य भी लौटाएगा जब मूल्य में शून्य नहीं है (रिक्त है)। यह उत्तर एक मल्टी-स्टेटमेंट-स्केलर-फंक्शन का भी उपयोग करता है, जब UDF के उपयोग से बचने के लिए विशेष रूप से ऊपर दिया गया प्रश्न।
मिकीटेवी

2

यदि स्ट्रिंग एक संख्या है, तो कास्ट (int के रूप में मान) हमेशा काम करेगा


यह प्रश्न का उत्तर प्रदान नहीं करता है। किसी लेखक से स्पष्टीकरण मांगने या उसका अनुरोध करने के लिए, उनके पोस्ट के नीचे एक टिप्पणी छोड़ दें। - समीक्षा से
जोसिप आइकिक

1
यह एक जवाब है क्योंकि यह काम करता है? जवाब लंबा होने की जरूरत नहीं है
tichra

आप सही हैं कि उत्तरों को लंबा होने की आवश्यकता नहीं है, हालाँकि वे यदि संभव हो तो पूर्ण होने चाहिए, और आपका उत्तर नहीं है; यह परिणाम का डेटा प्रकार बदलता है। मेरा मानना ​​है कि यह एक बेहतर प्रतिक्रिया होगी: सेलेक्ट कास्ट (CAST (मान के अनुसार) AS VARCHAR)। आपको यह भी उल्लेख करना चाहिए कि यदि आप मान को 2.1x10 ^ 9 (आठ अंकों की सीमा) से अधिक है तो आपको Int के साथ एक त्रुटि मिलेगी। यदि मूल्य 19 अंकों (9.2x10 ^ 18) से अधिक है तो बिगइंट का उपयोग करके आपको त्रुटि मिलती है।
जे। क्रिस कॉम्पटन

2

मेरा यह संस्करण Arvo के काम का एक अनुकूलन है, दो अन्य मामलों को सुनिश्चित करने के लिए थोड़ा और जोड़ा गया है।

1) यदि हमारे पास सभी 0 हैं, तो हमें अंक 0 वापस करना चाहिए।

2) यदि हमारे पास एक खाली है, तो हमें अभी भी एक खाली चरित्र लौटाना चाहिए।

CASE 
    WHEN PATINDEX('%[^0]%', str_col + '.') > LEN(str_col) THEN RIGHT(str_col, 1) 
    ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col + '.'), LEN(str_col))
 END

1
replace(ltrim(replace(Fieldname.TableName, '0', '')), '', '0')

थॉमस जी के सुझाव ने हमारी जरूरतों के लिए काम किया।

हमारे मामले में क्षेत्र पहले से ही कठोर था और केवल प्रमुख शून्य को छंटनी की आवश्यकता थी। अधिकतर यह सभी संख्यात्मक है, लेकिन कभी-कभी पत्र भी होते हैं ताकि पिछले INT रूपांतरण दुर्घटनाग्रस्त हो जाए।


नहीं, यह ट्रिम भी शून्य से पीछे चल रहा है
एडम ओस्ट्रूज़िल

1
SELECT CAST(CAST('000000000' AS INTEGER) AS VARCHAR)

यह स्ट्रिंग की लंबाई पर सीमा है जिसे एक INT में परिवर्तित किया जा सकता है


क्या आप अपने उत्तर में थोड़ा और समझा सकते हैं कि आपको क्यों लगता है कि यह काम करेगा? यदि यह शून्य शून्य होता है जिसमें अग्रणी शून्य का एक समूह होता है?
तायगेओस्ट

यदि आपकी संख्या 18 अंक या उससे कम है (और सबसे अधिक 19 अंकों की संख्या काम करती है, क्योंकि सीमा वास्तव में 9.2x10 ^ 18 है) तो आप अग्रणी शून्य से छुटकारा पाने के लिए SELECT CAST (CAST (@Field_Name AS BigInt) AS VARCHAR) का उपयोग कर सकते हैं। नोट: यदि आप गैर-संख्यात्मक वर्ण (डैश, अक्षर, अवधि, आदि) त्रुटि मैसेंजर 8114 के साथ "विफल हो जाएगा" डेटा प्रकार varchar को bigint में परिवर्तित करने में त्रुटि। "
जे। क्रिस कोम्पटन

1

यदि आप स्नोफ्लेक एसक्यूएल का उपयोग कर रहे हैं, तो इसका उपयोग कर सकते हैं:

ltrim(str_col,'0')

लेट्रिम फ़ंक्शन बाईं ओर से वर्णों के निर्दिष्ट सेट के सभी उदाहरणों को निकालता है।

इसलिए '00000008A' पर ltrim (str_col, '0') '8A' लौटाएगा

और '$ 125.00' पर rtrim (str_col, '0') '$ 125' लौटाएगा


1
  SUBSTRING(str_col, IIF(LEN(str_col) > 0, PATINDEX('%[^0]%', LEFT(str_col, LEN(str_col) - 1) + '.'), 0), LEN(str_col))

'0', '00' आदि के साथ भी ठीक काम करता है।



0

यदि आप इंट में बदलना नहीं चाहते हैं, तो मैं इसे नीचे तर्क पसंद करता हूं क्योंकि यह IFNULL (फ़ील्ड, LTRIM (फ़ील्ड, '0') को संभाल सकता है)


0

MySQL में आप ऐसा कर सकते हैं ...

Trim(Leading '0' from your_column)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.