मैं एक स्ट्रिंग को पूर्णांक कैसे डाल सकता हूं और पोस्टग्रेएसक्यूएल के साथ कलाकारों में त्रुटि के मामले में 0 है?


128

PostgreSQL में मेरे पास एक वर्चर कॉलम के साथ एक टेबल है। डेटा को पूर्णांक माना जाता है और मुझे क्वेरी में पूर्णांक प्रकार में इसकी आवश्यकता होती है। कुछ मान खाली स्ट्रिंग हैं। निम्नलिखित:

SELECT myfield::integer FROM mytable

पैदावार ERROR: invalid input syntax for integer: ""

पोस्टग्रेज में कलाकारों के दौरान त्रुटि के मामले में मैं किसी कलाकार को कैसे क्वेरी कर सकता हूं और 0 है?

जवाबों:


161

मैं खुद भी इसी तरह की समस्या से जूझ रहा था, लेकिन एक समारोह के ओवरहेड नहीं चाहता था। मैं निम्नलिखित प्रश्न के साथ आया था:

SELECT myfield::integer FROM mytable WHERE myfield ~ E'^\\d+$';

इसकी शर्तों को शॉर्टकट पोस्ट करता है, इसलिए आपको अपने :: पूर्णांक कलाकारों को मारते हुए कोई भी गैर-पूर्णांक नहीं मिलना चाहिए। यह NULL मान भी संभालता है (वे regexp से मेल नहीं खाएगा)।

यदि आप चयन न करने के बजाय शून्य चाहते हैं, तो एक CASE कथन को काम करना चाहिए:

SELECT CASE WHEN myfield~E'^\\d+$' THEN myfield::integer ELSE 0 END FROM mytable;

14
मैं मैथ्यू के सुझाव के साथ जाने की जोरदार सलाह दूंगा। इस समाधान में स्ट्रिंग के साथ समस्याएं हैं जो संख्याओं की तरह दिखती हैं लेकिन पूर्णांक में आपके द्वारा रखे जा सकने वाले अधिकतम मान से बड़ी हैं।
दोपहर

4
मैं दूसरे पायलट की टिप्पणी। वह अधिकतम मूल्य एक बग होने की प्रतीक्षा कर रहा है। डेटा अमान्य होने पर त्रुटि न फेंकने का बिंदु एक त्रुटि नहीं है। यह स्वीकार किया गया उत्तर इसका समाधान नहीं करता है। धन्यवाद मैथ्यू! अच्छा कार्य!
शॉन कोवाक

3
जैसा कि मैथ्यू का जवाब है, मुझे कुछ डेटा की जाँच के लिए बस एक त्वरित और गंदे तरीके की जरूरत थी। मैं यह भी स्वीकार करता हूं कि एसक्यूएल में कार्यों को परिभाषित करने में मेरे अपने ज्ञान की कमी है। मुझे केवल 1 और 5 अंकों के बीच की संख्या में दिलचस्पी थी, इसलिए मैंने regex को बदल दिया E'\\d{1,5}$'
बॉबर्ट

3
हां, हां यह समाधान अपेक्षाकृत जल्दी और गंदा है, लेकिन मेरे मामले में मुझे पता था कि मेरे पास क्या डेटा था और वह तालिका अपेक्षाकृत कम थी। यह संपूर्ण फ़ंक्शन लिखने (और डीबग करने) की तुलना में बहुत आसान है। @ अंकों के {1,5}ऊपर बॉबर्ट की सीमा संभवत: एक अच्छा विचार है यदि आप अतिप्रवाह के बारे में चिंतित हैं, लेकिन यह बड़ी संख्या में मुखौटा लगाएगा , जिससे यदि आप एक तालिका परिवर्तित कर रहे हैं तो परेशानी हो सकती है। व्यक्तिगत रूप से मेरे पास क्वेरी त्रुटि सामने होगी और जानिए कि मेरे कुछ "पूर्णांक" खराब हैं (आप E'\\d{6,}$'यह सुनिश्चित करने के लिए पहले के साथ भी चयन कर सकते हैं )।
एंथनी ब्रिग्स

1
@ एंथनी ब्रिग्स: यह काम नहीं करेगा अगर मायफील्ड में "'" या "," या "।", या' - '
स्टीफन स्टीगर

100

आप अपना स्वयं का रूपांतरण फ़ंक्शन भी बना सकते हैं, जिसके अंदर आप अपवाद ब्लॉक का उपयोग कर सकते हैं:

CREATE OR REPLACE FUNCTION convert_to_integer(v_input text)
RETURNS INTEGER AS $$
DECLARE v_int_value INTEGER DEFAULT NULL;
BEGIN
    BEGIN
        v_int_value := v_input::INTEGER;
    EXCEPTION WHEN OTHERS THEN
        RAISE NOTICE 'Invalid integer value: "%".  Returning NULL.', v_input;
        RETURN NULL;
    END;
RETURN v_int_value;
END;
$$ LANGUAGE plpgsql;

परिक्षण:

=# select convert_to_integer('1234');
 convert_to_integer 
--------------------
               1234
(1 row)

=# select convert_to_integer('');
NOTICE:  Invalid integer value: "".  Returning NULL.
 convert_to_integer 
--------------------

(1 row)

=# select convert_to_integer('chicken');
NOTICE:  Invalid integer value: "chicken".  Returning NULL.
 convert_to_integer 
--------------------

(1 row)

8
स्वीकार किए गए उत्तर के विपरीत, यहां यह समाधान अधिक सही है क्योंकि यह संख्याओं के साथ समान रूप से बहुत बड़ा सौदा कर सकता है जो एक पूर्णांक में फिट होने के लिए है और यह तेजी से होने की संभावना है क्योंकि यह सामान्य मामले में कोई सत्यापन कार्य नहीं करता है (= वैध तार )
पिलिफ

आप अपने समारोह का उपयोग कर विशिष्ट क्षेत्रों पर पूर्णांक में स्ट्रिंग डाली हैं , जबकि में में INSERTबयान?
sk

27

मुझे उसी तरह की आवश्यकता थी और यह मेरे लिए अच्छी तरह से काम करने के लिए मिला (पोस्टग्रेज 8.4):

CAST((COALESCE(myfield,'0')) AS INTEGER)

प्रदर्शित करने के लिए कुछ परीक्षण मामले:

db=> select CAST((COALESCE(NULL,'0')) AS INTEGER);
 int4
------
    0
(1 row)

db=> select CAST((COALESCE('','0')) AS INTEGER);
 int4
------
    0
(1 row)

db=> select CAST((COALESCE('4','0')) AS INTEGER);
 int4
------
    4
(1 row)

db=> select CAST((COALESCE('bad','0')) AS INTEGER);
ERROR:  invalid input syntax for integer: "bad"

यदि आपको गैर-संख्यात्मक पाठ वाले क्षेत्र की संभावना को संभालने की आवश्यकता है (जैसे कि "100bad") तो आप कलाकारों से पहले गैर-संख्यात्मक वर्णों को हटाने के लिए regexp_replace का उपयोग कर सकते हैं।

CAST(REGEXP_REPLACE(COALESCE(myfield,'0'), '[^0-9]+', '', 'g') AS INTEGER)

फिर "b3ad5" जैसे टेक्स्ट / वर्चर मान भी नंबर देंगे

db=> select CAST(REGEXP_REPLACE(COALESCE('b3ad5','0'), '[^0-9]+', '', 'g') AS INTEGER);
 regexp_replace
----------------
             35
(1 row)

सभी मामलों के लिए 0 नहीं देने के समाधान के साथ क्रिस कॉगडॉन की चिंता को दूर करने के लिए, जैसे "खराब" (बिल्कुल कोई वर्ण वर्ण नहीं) जैसे मामले में, मैंने यह समायोजित बयान दिया:

CAST((COALESCE(NULLIF(REGEXP_REPLACE(myfield, '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);

यह सरल समाधानों के समान काम करता है, सिवाय 0 तब देगा जब परिवर्तित करने के लिए मूल्य केवल गैर-अंक वर्ण होते हैं, जैसे कि "खराब":

db=> select CAST((COALESCE(NULLIF(REGEXP_REPLACE('no longer bad!', '[^0-9]+', '', 'g'), ''), '0')) AS INTEGER);
     coalesce
----------
        0
(1 row)

आपको '0' की आवश्यकता क्यों है || ? डॉक्स से: "COALESCE फ़ंक्शन अपने उन तर्कों को पहले देता है जो अशक्त नहीं हैं।" इसलिए यदि आपके पास अपने मूल्य के रूप में अशक्त है, तो कॉलेसस को इससे छुटकारा मिल जाएगा।
अमाला

@ अमाला सच। अच्छा पकड़ा। संपादित।
घबराहट

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

@ChrisCogdon मैंने आपकी चिंता को दूर करने के लिए समाधान को हमेशा शून्य नहीं देने के लिए जोड़ा है यदि रूपांतरण करने का मूल्य परिवर्तनीय नहीं है। " समाधान का यह संशोधित संस्करण 0 लौटाएगा जब कोई अंक वर्णों वाली स्ट्रिंग को रूपांतरित करने के लिए मान दिया जाएगा।
घबराहट

22

यह कुछ हद तक हैक हो सकता है, लेकिन इसे हमारे मामले में काम मिल गया:

(0 || myfield)::integer

स्पष्टीकरण (पोस्टग्रैस पर परीक्षण 8.4):

उपर्युक्त अभिव्यक्ति में NULLरिक्त मान के लिए myfieldऔर 0खाली स्ट्रिंग्स के लिए पैदावार मिलती है (यह सटीक व्यवहार आपके उपयोग के मामले में फिट हो भी सकता है और नहीं भी)।

SELECT id, (0 || values)::integer from test_table ORDER BY id

परीक्षण डेटा:

CREATE TABLE test_table
(
  id integer NOT NULL,
  description character varying,
  "values" character varying,
  CONSTRAINT id PRIMARY KEY (id)
)

-- Insert Test Data
INSERT INTO test_table VALUES (1, 'null', NULL);
INSERT INTO test_table VALUES (2, 'empty string', '');
INSERT INTO test_table VALUES (3, 'one', '1');

क्वेरी निम्न परिणाम देगी:

 ---------------------
 |1|null        |NULL|
 |2|empty string|0   |
 |3|one         |1   |
 ---------------------

जबकि केवल चयन करें values::integer एक त्रुटि संदेश में परिणाम देगा।

उम्मीद है की यह मदद करेगा।


3

SELECT CASE WHEN myfield="" THEN 0 ELSE myfield::integer END FROM mytable

मैंने कभी PostgreSQL के साथ काम नहीं किया है, लेकिन मैंने SELECT क्वेरीज़ में IF स्टेटमेंट्स के सही सिंटैक्स के लिए मैनुअल चेक किया ।


यह अब के रूप में तालिका के लिए काम करता है। मैं थोड़ा डर गया कि भविष्य में इसमें गैर-संख्यात्मक मूल्य शामिल हो सकते हैं। मैंने एक कोशिश / कैच जैसा समाधान पसंद किया है, लेकिन यह चाल है। धन्यवाद।
११

हो सकता है कि आप रेगुलर एक्सप्रेशन postgresql.org/docs/8.4/interactive/functions-matching.html का उपयोग कर सकें, लेकिन यह महंगा हो सकता है। इसका उत्तर भी स्वीकार करें यदि इसका हल है :)
Jan Hančič

3

@ मैथ्यू का जवाब अच्छा है। लेकिन यह सरल और तेज हो सकता है। और सवाल खाली स्ट्रिंग्स ( '') को बदलने के लिए कहता है 0, लेकिन अन्य "अमान्य इनपुट सिंटैक्स" या "आउट ऑफ रेंज" इनपुट:

CREATE OR REPLACE FUNCTION convert_to_int(text)
  RETURNS int AS
$func$
BEGIN
   IF $1 = '' THEN  -- special case for empty string like requested
      RETURN 0;
   ELSE
      RETURN $1::int;
   END IF;

EXCEPTION WHEN OTHERS THEN
   RETURN NULL;  -- NULL for other invalid input

END
$func$  LANGUAGE plpgsql IMMUTABLE;

यह 0खाली स्ट्रिंग और NULLकिसी अन्य अमान्य इनपुट के लिए देता है।
यह आसानी से किसी भी डेटा प्रकार रूपांतरण के लिए अनुकूलित किया जा सकता है

एक अपवाद ब्लॉक में प्रवेश करना काफी अधिक महंगा है। यदि खाली तार सामान्य हैं तो अपवाद को बढ़ाने से पहले उस मामले को पकड़ना समझ में आता है।
यदि खाली तार बहुत दुर्लभ हैं, तो यह परीक्षण को अपवाद खंड में स्थानांतरित करने के लिए भुगतान करता है।


1
CREATE OR REPLACE FUNCTION parse_int(s TEXT) RETURNS INT AS $$
BEGIN
  RETURN regexp_replace(('0' || s), '[^\d]', '', 'g')::INT;
END;
$$ LANGUAGE plpgsql;

0इनपुट स्ट्रिंग में कोई अंक नहीं होने पर यह फ़ंक्शन हमेशा वापस आ जाएगा ।

SELECT parse_int('test12_3test');

वापस होगा 123


क्या आपने regex vs string फ़ंक्शन के लिए कोई प्रदर्शन परीक्षण किया है? इसके अलावा, यह कैसे संभालती है नल? क्या यह उम्मीद के मुताबिक 0 या NULL लौटा देगा? धन्यवाद!
Vol7ron

1

मुझे निम्नलिखित कोड आसान और काम करने वाला लगा। मूल उत्तर यहाँ है https://www.postgresql.org/message-id/371F1510.F86C876B@sferacarta.com

prova=> create table test(t text, i integer);
CREATE

prova=> insert into test values('123',123);
INSERT 64579 1

prova=> select cast(i as text),cast(t as int)from test;
text|int4
----+----
123| 123
(1 row)

आशा करता हूँ की ये काम करेगा


1

SUBSTRING कुछ मामलों के लिए मदद कर सकता है, आप इंट के आकार को सीमित कर सकते हैं।

SELECT CAST(SUBSTRING('X12312333333333', '([\d]{1,9})') AS integer);

0

यदि डेटा को पूर्णांक माना जाता है, और आपको केवल पूर्णांक के रूप में उन मानों की आवश्यकता है, तो आप पूरे मील क्यों नहीं जाते हैं और कॉलम को पूर्णांक कॉलम में परिवर्तित करते हैं?

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

उपरोक्त रूपांतरण के साथ, आप उन मानों को बार-बार प्रत्येक तालिका में उस तालिका के लिए प्रत्येक पंक्ति में परिवर्तित करने के लिए Postgres मजबूर कर रहे हैं - यदि आप इस तालिका में इस स्तंभ के विरुद्ध बहुत सारे प्रश्न करते हैं तो यह प्रदर्शन को गंभीरता से कम कर सकता है।


सिद्धांत रूप में आप सही हैं, लेकिन इस विशेष परिदृश्य में मुझे एक अनुप्रयोग में एक एकल धीमी क्वेरी को अनुकूलित करना होगा। मुझे नहीं पता कि कोड जो डेटा इनपुट कार्य को संभालता है। मैं इसे छूना नहीं चाहता। अब तक मेरी पुनः लिखित क्वेरी काम करती है, लेकिन मैं चाहूंगा कि यह अप्रत्याशित मामलों में न टूटे। एप्लिकेशन को फिर से आर्किटेक्चर करना एक विकल्प नहीं है, भले ही यह सबसे समझदार चीज लगती हो।
१०:२५ पर सिल्वोट

0

निम्नलिखित कार्य करता है

  • एक डिफ़ॉल्ट मान का उपयोग करें (error_resultकास्टेबल परिणाम जैसे ( abcया नहीं) के लिए ) का999999999999999999999999999999999999999999
  • रखता है null रूप में हैnull
  • ट्रिम और अन्य व्हाट्सएप को इनपुट में दूर करता है
  • मान्य के रूप में डाले गए मूल्यों bigintsकी तुलना lower_boundकेवल सकारात्मक मूल्यों को लागू करने के खिलाफ की जाती है
CREATE OR REPLACE FUNCTION cast_to_bigint(text) 
RETURNS BIGINT AS $$
DECLARE big_int_value BIGINT DEFAULT NULL;
DECLARE error_result  BIGINT DEFAULT -1;
DECLARE lower_bound   BIGINT DEFAULT 0;
BEGIN
    BEGIN
        big_int_value := CASE WHEN $1 IS NOT NULL THEN GREATEST(TRIM($1)::BIGINT, lower_bound) END;
    EXCEPTION WHEN OTHERS THEN
        big_int_value := error_result;
    END;
RETURN big_int_value;
END;

-1

मुझे भी वही ज़रूरत है लेकिन यह JPA 2.0 और हाइबरनेट 5.0.2 के साथ काम करता है:

SELECT p FROM MatchProfile p WHERE CONCAT(p.id, '') = :keyword

अद्भुत काम करता है। मुझे लगता है कि यह LIKE के साथ भी काम करता है।


-3

यह भी काम करना चाहिए, लेकिन यह SQL के पार है और विशिष्ट पोस्टग्रे नहीं है।

select avg(cast(mynumber as numeric)) from my table
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.