PostgreSQL 'समूह में एक स्ट्रिंग फ़ील्ड के स्ट्रिंग को' क्वेरी 'से कैसे मिलाएं?


351

मैं एक समूह के भीतर क्वेरी द्वारा समूह के क्षेत्र को समाप्‍त करने का मार्ग खोज रहा हूं। उदाहरण के लिए, मेरे पास एक तालिका है:

ID   COMPANY_ID   EMPLOYEE
1    1            Anna
2    1            Bill
3    2            Carol
4    2            Dave

और मैं कुछ पाने के लिए company_id द्वारा समूह बनाना चाहता था:

COMPANY_ID   EMPLOYEE
1            Anna, Bill
2            Carol, Dave

इस group_concat को करने के लिए mySQL में बिल्ट-इन फंक्शन है


1
मार्कस डोरिंग का जवाब तकनीकी रूप से बेहतर है।
पस्टनटॉन

@ पैंटनटॉन, डॉरिंग का जवाब केवल 8.4 और नीचे के लिए बेहतर है।
जारेड बेक

यह प्रश्न dba.stackexchange.com के लिए बेहतर अनुकूल प्रतीत होता है ।
डेव जार्विस

यह मान्य उत्तर होना चाहिए अब stackoverflow.com/a/47638417/243233
Jus12

जवाबों:


542

PostgreSQL 9.0 या बाद में:

Postgres के हाल के संस्करणों (2010 के अंत से) में वह string_agg(expression, delimiter)फ़ंक्शन होता है जो वही करेगा जो प्रश्न के लिए पूछा गया था, यहां तक ​​कि आपको नाजुक स्ट्रिंग निर्दिष्ट करने देता है:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;

9.0 पोस्टग्रेट्स ने किसी भी कुल अभिव्यक्ति में एक ORDER BYखंड निर्दिष्ट करने की क्षमता को जोड़ा ; अन्यथा, आदेश अपरिभाषित है। तो अब आप लिख सकते हैं:

SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;

या वास्तव में:

SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)

PostgreSQL 8.4 या बाद में:

PostgreSQL 8.4 (2009 में) ने एग्रीगेट फंक्शन कीarray_agg(expression) शुरुआत की जो एक एरे में मूल्यों को समेटता है। तब array_to_string()वांछित परिणाम देने के लिए इस्तेमाल किया जा सकता है:

SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;

string_agg पूर्व 8.4 संस्करणों के लिए:

यदि किसी को भी प्री-9.0 डेटाबेस के लिए कंपीटिबल शिम की तलाश में यह आता है, तो क्लॉज string_aggको छोड़कर सब कुछ लागू करना संभव है ORDER BY

तो नीचे दी गई परिभाषा के साथ यह 9.x Postgres DB के समान काम करना चाहिए:

SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;

लेकिन यह एक वाक्यविन्यास त्रुटि होगी:

SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"

PostgreSQL 8.3 पर परीक्षण किया गया।

CREATE FUNCTION string_agg_transfn(text, text, text)
    RETURNS text AS 
    $$
        BEGIN
            IF $1 IS NULL THEN
                RETURN $2;
            ELSE
                RETURN $1 || $3 || $2;
            END IF;
        END;
    $$
    LANGUAGE plpgsql IMMUTABLE
COST 1;

CREATE AGGREGATE string_agg(text, text) (
    SFUNC=string_agg_transfn,
    STYPE=text
);

कस्टम विविधताएं (सभी पोस्टग्रेज संस्करण)

9.0 से पहले, तारों को समेटने के लिए कोई अंतर्निहित एग्रीगेट फ़ंक्शन नहीं था। सबसे सरल कस्टम कार्यान्वयन ( इस मेलिंग सूची पोस्ट में वजदा गाबो द्वारा सुझाए गए , कई अन्य लोगों के बीच) अंतर्निहित textcatफ़ंक्शन (जो ||ऑपरेटर के पीछे स्थित है ) का उपयोग करना है:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

यहाँ CREATE AGGREGATEप्रलेखन है।

यह बस किसी भी विभाजक के साथ, सभी तारों को एक साथ जोड़ देता है। अंत में इसे बिना "बीच में" प्राप्त करने के लिए, आप अपना स्वयं का संयोजन कार्य करना चाहते हैं और इसे ऊपर दिए गए "टेक्स्टकैट" के लिए स्थानापन्न कर सकते हैं। यहाँ एक मैं एक साथ रखा और 8.3.12 पर परीक्षण किया है:

CREATE FUNCTION commacat(acc text, instr text) RETURNS text AS $$
  BEGIN
    IF acc IS NULL OR acc = '' THEN
      RETURN instr;
    ELSE
      RETURN acc || ', ' || instr;
    END IF;
  END;
$$ LANGUAGE plpgsql;

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

a, b, c, , e, , g

यदि आप इसे आउटपुट करने के लिए अतिरिक्त कॉमा निकालना चाहते हैं:

a, b, c, e, g

फिर ELSIFइस तरह फ़ंक्शन में एक चेक जोड़ें :

CREATE FUNCTION commacat_ignore_nulls(acc text, instr text) RETURNS text AS $$
  BEGIN
    IF acc IS NULL OR acc = '' THEN
      RETURN instr;
    ELSIF instr IS NULL OR instr = '' THEN
      RETURN acc;
    ELSE
      RETURN acc || ', ' || instr;
    END IF;
  END;
$$ LANGUAGE plpgsql;

1
मुझे S & R varchar को पाठ (नवीनतम pgsql स्थिर) करना था, लेकिन यह बहुत अच्छा है!
केव

1
आप फ़ंक्शन को SQL में ही लिख सकते हैं, जो इंस्टॉलेशन के लिए आसान है (plpgsql को सुपरयूज़र द्वारा इंस्टॉल किया जाना है)। एक उदाहरण के लिए मेरी पोस्ट देखें।
bortzmeyer

11
"स्ट्रिंग्स को समेटने के लिए कोई बिल्ट-इन एग्रीगेट फंक्शन नहीं है" - आप इसका उपयोग क्यों नहीं करेंगे array_to_string(array_agg(employee), ',')?
पस्टनटॉन

2
PostgreSQL 9.0 फ़ंक्शन के लिए +1। यदि आपको प्री-9.0 के बारे में चिंतित होने की आवश्यकता है, तो मार्कस का उत्तर बेहतर है।
ब्रैड कोच

7
ध्यान दें कि Postgres के हाल के संस्करण भी Order Byकुल फ़ंक्शन के अंदर एक क्लॉज की अनुमति देते हैं , जैसेstring_agg(employee, ',' Order By employee)
IMSoP

99

बिल्ट-इन सरणी फ़ंक्शन का उपयोग करने के बारे में कैसे? कम से कम 8.4 पर यह बॉक्स से बाहर काम करता है:

SELECT company_id, array_to_string(array_agg(employee), ',')
FROM mytable
GROUP BY company_id;

दुख की बात है कि यह हमारे लिए ग्रीनप्लम (v8.2) पर काम नहीं करता है। +1 सभी समान
इक्कीस

ग्रीनप्लम 4.3.4.1 (पोस्टग्रेक्यूएल 8.2.15 पर निर्मित) पर मेरे लिए ठीक काम करता है।
फिलिब्स

19

PostgreSQL 9.0 के रूप में, आप string_agg नामक कुल फ़ंक्शन का उपयोग कर सकते हैं । आपकी नई SQL कुछ इस तरह दिखनी चाहिए:

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;


13

मैं उत्तर के लिए कोई श्रेय का दावा नहीं करता क्योंकि मुझे यह कुछ खोज के बाद मिला:

मुझे नहीं पता था कि PostgreSQL आपको क्रिएट एज के साथ अपने स्वयं के कुल कार्यों को परिभाषित करने की अनुमति देता है

PostgreSQL सूची की यह पोस्ट बताती है कि जो आवश्यक है उसे करने के लिए एक फ़ंक्शन बनाने के लिए कितना तुच्छ है:

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

SELECT company_id, textcat_all(employee || ', ')
FROM mytable
GROUP BY company_id;

7

जैसा कि पहले ही उल्लेख किया गया है, अपना स्वयं का कुल कार्य बनाना सही काम है। यहाँ मेरा संयोजन कार्य है (आप फ्रेंच में विवरण पा सकते हैं ):

CREATE OR REPLACE FUNCTION concat2(text, text) RETURNS text AS '
    SELECT CASE WHEN $1 IS NULL OR $1 = \'\' THEN $2
            WHEN $2 IS NULL OR $2 = \'\' THEN $1
            ELSE $1 || \' / \' || $2
            END; 
'
 LANGUAGE SQL;

CREATE AGGREGATE concatenate (
  sfunc = concat2,
  basetype = text,
  stype = text,
  initcond = ''

);

और फिर इसका उपयोग करें:

SELECT company_id, concatenate(employee) AS employees FROM ...

5

यदि आप 8.4 में अपग्रेड होंगे, तो यह नवीनतम घोषणा सूची स्निपेट ब्याज की हो सकती है:

जब तक 8.4 एक सुपर-होशियार मूल निवासी के साथ नहीं निकलता, तब तक आप PostgreSQL प्रलेखन में array_accum () फ़ंक्शन को किसी भी कॉलम को एक सरणी में रोल करने के लिए जोड़ सकते हैं, जिसे तब एप्लिकेशन कोड द्वारा उपयोग किया जा सकता है, या array_to-string () से प्रारूपित किया जा सकता है। यह एक सूची के रूप में:

http://www.postgresql.org/docs/current/static/xaggr.html

मैं 8.4 विकास डॉक्स से लिंक करूंगा लेकिन वे अभी तक इस सुविधा को सूचीबद्ध नहीं करते हैं।


5

Kev के उत्तर के बाद, पोस्टग्रोज़ डॉक्स का उपयोग कर:

सबसे पहले, तत्वों की एक सरणी बनाएं, फिर अंतर्निहित array_to_stringफ़ंक्शन का उपयोग करें ।

CREATE AGGREGATE array_accum (anyelement)
(
 sfunc = array_append,
 stype = anyarray,
 initcond = '{}'
);

select array_to_string(array_accum(name),'|') from table group by id;

5

स्ट्रिंग संयोजन के एक कस्टम एकीकृत फ़ंक्शन के उपयोग पर एक बार फिर बाद: यदि आप याद रखना होगा कि चयन बयान किसी भी क्रम में पंक्तियों जगह होगा, ताकि आप एक उप करने की आवश्यकता होगी की आवश्यकता का चयन में से एक के साथ बयान से आदेश खंड, और फिर एक समूह के साथ एक बाहरी चयन करें , जिससे स्ट्रिंग्स को एकत्रित किया जा सके

SELECT custom_aggregate(MY.special_strings)
FROM (SELECT special_strings, grouping_column 
        FROM a_table 
        ORDER BY ordering_column) MY
GROUP BY MY.grouping_column

3

मुझे यह PostgreSQL दस्तावेज़ीकरण मददगार लगा: http://www.postgresql.org/docs/8.0/interactive/functions-conditional.html

मेरे मामले में, मैंने मैदान के चारों ओर कोष्ठक के साथ मैदान को खाली करने के लिए सादे एसक्यूएल की मांग की, यदि फ़ील्ड खाली नहीं है।

select itemid, 
  CASE 
    itemdescription WHEN '' THEN itemname 
    ELSE itemname || ' (' || itemdescription || ')' 
  END 
from items;


0

संस्करण PostgreSQL 9.0 और ऊपर के अनुसार आप string_agg नामक कुल फ़ंक्शन का उपयोग कर सकते हैं। आपकी नई SQL कुछ इस तरह दिखनी चाहिए:

SELECT company_id, string_agg(employee, ', ')
    FROM mytable GROUP BY company_id;

0

आप प्रारूप फ़ंक्शन का उपयोग भी कर सकते हैं। जो अपने आप में पाठ के प्रकार रूपांतरण, इंट, आदि का भी ध्यान रख सकता है।

create or replace function concat_return_row_count(tbl_name text, column_name text, value int)
returns integer as $row_count$
declare
total integer;
begin
    EXECUTE format('select count(*) from %s WHERE %s = %s', tbl_name, column_name, value) INTO total;
    return total;
end;
$row_count$ language plpgsql;


postgres=# select concat_return_row_count('tbl_name','column_name',2); --2 is the value

1
यह कैसे कड़े मूल्यों को समेटने के लिए एक समुच्चय का उपयोग करने से संबंधित है?
a_horse_with_no_name

0

मैं Jetbrains राइडर का उपयोग कर रहा हूं और यह उपरोक्त उदाहरणों से परिणामों को कॉपी करने में परेशानी थी, क्योंकि यह JSON में यह सब लपेटने के लिए लग रहा था। यह उन्हें एक ही बयान में शामिल करता है जिसे चलाना आसान था

select string_agg('drop table if exists "' || tablename || '" cascade', ';') 
from pg_tables where schemaname != $$pg_catalog$$ and tableName like $$rm_%$$

0

यदि आप Amazon Redshift पर हैं, जहाँ string_agg समर्थित नहीं है, तो listagg का उपयोग करके देखें।

SELECT company_id, listagg(EMPLOYEE, ', ') as employees
FROM EMPLOYEE_table
GROUP BY company_id;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.