2016-04-02 11 views
18

में एक स्ट्रिंग के भीतर एक सबस्ट्रिंग की घटनाओं की संख्या की गणना करना मैं PostgreSQL में किसी स्ट्रिंग के भीतर किसी सबस्ट्रिंग की घटनाओं की संख्या को कैसे गिन सकता हूं?PostgreSQL


उदाहरण:

मैं एक मेज है

CREATE TABLE test."user" 
(
    uid integer NOT NULL, 
    name text, 
    result integer, 
    CONSTRAINT pkey PRIMARY KEY (uid) 
) 

मैं एक प्रश्न लिखना चाहते हैं ताकि result कॉलम होता है कैसे-स्ट्रिंग o स्तंभ name शामिल पाया जाना। उदाहरण के लिए, यदि एक पंक्ति में, namehello world है, तो कॉलम result में 2 होना चाहिए, क्योंकि स्ट्रिंग hello world में दो o हैं।

enter image description here

और result स्तंभ अद्यतन:

enter image description here


मैं

दूसरे शब्दों में, मैं एक प्रश्न है कि इनपुट के रूप में ले जाएगा लिखने के लिए कोशिश कर रहा हूँ regexp_matches और इसके g विकल्प के बारे में पता है, जो इंगित करता है कि पूर्ण (g = वैश्विक) स्ट्रिंग को सबस्ट्रिंग की सभी घटनाओं की उपस्थिति के लिए स्कैन करने की आवश्यकता है)।

उदाहरण:

SELECT * FROM regexp_matches('hello world', 'o', 'g'); 

रिटर्न

{o} 
{o} 

और

SELECT COUNT(*) FROM regexp_matches('hello world', 'o', 'g'); 

रिटर्न

2 

लेकिन मुझे नहीं लगता कि UPDATE क्वेरी को कैसे लिखना है जो result कॉलम को इस तरह से अपडेट करेगा कि इसमें name कॉलम के सबस्ट्रिंग की कितनी घटनाएं शामिल होंगी।

+0

संभावित डुप्लिकेट (http://stackoverflow.com/questions/25757194/postgresql -काउंट-संख्या-समय-सबस्ट्रिंग-इन-टेक्स्ट में) –

उत्तर

21

एक आम समाधान इस तर्क पर आधारित है: कोई रिक्त स्ट्रिंग के साथ खोज स्ट्रिंग की जगह और खोज स्ट्रिंग की लंबाई

(CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'substring', ''))) 
/CHAR_LENGTH('substring') 

इसलिए द्वारा पुराने और नए लंबाई के बीच अंतर को विभाजित:

UPDATE test."user" 
SET result = 
    (CHAR_LENGTH(name) - CHAR_LENGTH(REPLACE(name, 'o', ''))) 
    /CHAR_LENGTH('o'); 
+0

यह एक ठोस उत्तर है, और यह सही है। आपको मेरे लिखने पर रुचि हो सकती है [ऐसा करने के सभी तरीके] (http://dba.stackexchange.com/a/166763/2639) –

+0

धन्यवाद! क्या कोई जानता है, कोई आसान तरीका क्यों नहीं है? मेरा मतलब है, सभी घटनाओं के लिए पूरी स्ट्रिंग स्कैनिंग की समस्या से पहले ही स्थानांतरित हो जाता है, क्यों कुछ ऐसा नहीं है जो प्रतिस्थापन के आधे काम करता है - बस –

+0

@AleksandrLevchuk की गणना करें: ठीक है, आप अपना खुद का उपयोगकर्ता परिभाषित फ़ंक्शन लिख सकते हैं इस गणना कर रहे हैं, उदाहरण के लिए https://www.enterprisedb.com/docs/en/9.5/eeguide/EDB_Postgres_Enterprise_Guide.1.041.html में ओरेकल का 'REGEXP_COUNT' है। – dnoeth

13
ऐसा करने का

एक Postgres'y तरह से एक सरणी के लिए स्ट्रिंग में कनवर्ट करता है और सरणी की लंबाई में गिना जाता है (और फिर घटा देती है 1):

select array_length(string_to_array(name, 'o'), 1) - 1 

ध्यान दें कि यह लंबे सबस्ट्रिंग के साथ भी काम करता है।

इसलिए:

update test."user" 
    set result = array_length(string_to_array(name, 'o'), 1) - 1; 
+2

अगर किसी को regexp की आवश्यकता है, तो "string_to_array" के बजाय "regexp_split_to_array" के साथ यह समाधान भी काम करता है। –

+0

यह समाधान @ dnoeth के सुझाव से काफी धीमा है। मुझे नहीं लगता कि यह और अधिक पोस्टग्रेस-वाई है। जब चीजें तेजी से और एक अलग विधि में अधिक पोर्टेबल होती हैं, तो मुझे लगता है कि हम इसे * बेहतर * कहते हैं। =) –

+1

@EvanCarroll दुर्भाग्य से, dnoeth का जवाब regex मैचों के लिए काम नहीं करेगा, क्योंकि आप मैच की लंबाई नहीं जानते हैं। यह उत्तर रेगेक्स मैचों और कच्चे स्ट्रिंग मैचों दोनों के लिए काम करेगा। मुझे लगता है कि हम _better_ को क्या कहते हैं वह समाधान है जो आप जो भी करने की कोशिश कर रहे हैं उसके लिए काम करता है :) – WebWanderer

0

अन्य तरीका:

UPDATE test."user" SET result = length(regexp_replace(name, '[^o]', '', 'g')); 
की [PostgreSQL बार-स्ट्रिंग की गिनती संख्या पाठ में होता है]