कैसे post_es का उपयोग करके string_agg में array_agg में शून्य मानों को बाहर करना है?


96

यदि मैं array_aggनामों को इकट्ठा करने के लिए उपयोग करता हूं, तो मुझे मेरे नाम अल्पविराम से अलग कर दिए जाते हैं, लेकिन अगर कोई nullमूल्य है, तो यह भी कुल में एक नाम के रूप में लिया जाता है। उदाहरण के लिए :

SELECT g.id,
       array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
       array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
FROM groups g
GROUP BY g.id;

यह ,Larry,Philसिर्फ के बजाय Larry,Phil(मेरे 9.1.2 में, यह दिखाता है NULL,Larry,Phil) लौटता है । के रूप में इस बेला में

इसके बजाय, यदि मैं उपयोग करता हूं, तो string_agg()यह मुझे यहाँ की तरह केवल नाम (खाली कॉमा या नल के बिना) दिखाता है

समस्या यह है कि मैंने Postgres 8.4सर्वर पर स्थापित किया है, और string_agg()वहां काम नहीं करता है। क्या array_agg को string_agg () के समान काम करने का कोई तरीका है?


इस विषय पर पोस्टग्रेक्सेल मेलिंग लिस्ट थ्रेड देखें: postgresql.1045698.n5.nabble.com/…
क्रेग रिंगर

मुझे खेद है, मुझे नहीं लगता कि उस सूत्र में कोई समाधान है ..
Daud

उस सूत्र में दो उपाय हैं। एक फ़ंक्शन बनाने के लिए है और दूसरा (केवल सुझाव नहीं दिखाया गया है) वह है जिसका मैंने उत्तर दिया है।
क्लोडोल्डो नेटो

@ क्लोडाल्डो - सभी पंक्तियों में विहित होगा ('y', 'n') ... इसलिए जहां खंड निरर्थक लगता है। समस्या यह है कि एक समूह के अंदर, यदि विहित क्षेत्र का मान 'Y' है, और हम 'N's' एकत्र कर रहे हैं, तो एक नल भी एकत्र किया जाएगा ..
Daud

ठीक। अब मैं समझ गया। अद्यतन उत्तर की जाँच करें।
क्लोडोल्डो नेटो

जवाबों:


28

एसक्यूएल फिडल

select
    id,
    (select array_agg(a) from unnest(canonical_users) a where a is not null) canonical_users,
    (select array_agg(a) from unnest(non_canonical_users) a where a is not null) non_canonical_users
from (
    SELECT g.id,
           array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
           array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
    FROM groups g
    GROUP BY g.id
) s

या, सरल और सस्ता हो सकता है, array_to_stringजिसके उपयोग से नल समाप्त हो जाते हैं:

SELECT
    g.id,
    array_to_string(
        array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END)
        , ','
    ) canonical_users,
    array_to_string(
        array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END)
        , ','
    ) non_canonical_users
FROM groups g
GROUP BY g.id

एसक्यूएल फिडल


धन्यवाद। लेकिन यदि मुख्य क्वेरी (s) 1000 पंक्तियों को लौटाती है, तो 2 उपश्रेणी (अनावश्यक का उपयोग करके) प्रत्येक पंक्ति के लिए एक बार चलेगी .. क्या 2000 अतिरिक्त चुनिंदा प्रश्नों को निष्पादित करने की तुलना में NULL को सहन करना बेहतर होगा?
दाउद

@Daud नया संस्करण जो सस्ता हो सकता है। सुनिश्चित करने के लिए दोनों का व्याख्या आउटपुट लें।
क्लोडोल्डो नेटो

3
@Clodoaldo यदि आप उपयोग कर रहे हैं तो आप भी उपयोग array_to_string(array_agg(...))कर सकते हैं string_agg
क्रेग रिंगर

1
@ क्रेग प्रश्न में समस्या 8.4 है
क्लोडोल्डो नेटो

@ क्लोडोल्डो गह, पुराने संस्करण। धन्यवाद।
क्रेग रिंगर

247

Postgresql-9.3 के साथ कोई भी ऐसा कर सकता है;

SELECT g.id,
   array_remove(array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END), NULL) canonical_users,
   array_remove(array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END), NULL) non_canonical_users
FROM groups g 
GROUP BY g.id;

अद्यतन : Postgresql-9.4 के साथ;

SELECT g.id,
   array_agg(g.users) FILTER (WHERE g.canonical = 'Y') canonical_users,
   array_agg(g.users) FILTER (WHERE g.canonical = 'N') non_canonical_users
FROM groups g 
GROUP BY g.id;

5
यह काम करता है और तेज और सुरुचिपूर्ण है, इसने मुझे ओपी के समान एक समस्या हल कर दी। उन लोगों के लिए 9.3 में अपग्रेड करने का एक कारण जिन्होंने इसे अभी तक नहीं किया था। +1
पावेल वी।

12
9.4 और भी सुंदर है। एक आकर्षण की तरह काम करता है
jmgarnier

2
9.4 संस्करण और भी बेहतर है, क्योंकि मुझे अपने मामले में दूर करने की आवश्यकता है नल है।
कोलाडिक्ट

मैंने पहले अपडेट किए गए संस्करण का उपयोग किया, लेकिन फिर मुझे लगा कि मुझे नल और डुप्लिकेट को हटाने की आवश्यकता है, इसलिए पहले सुझाव पर वापस चला गया। यह एक बड़ी क्वेरी है, लेकिन यह भौतिकवादी दृश्य बनाना है, इसलिए यह बहुत बड़ा मुद्दा नहीं है।
रीलेक्वेस्टल

12

सरणी समुच्चय से नल हटाने के सामान्य प्रश्न को हल करने में समस्या पर हमला करने के दो मुख्य तरीके हैं: या तो array_agg (अनावश्यक (array_agg (x))) करना या कस्टम कुल बनाना।

पहला ऊपर दिखाए गए फॉर्म का है :

SELECT 
    array_agg(u) 
FROM (
    SELECT 
        unnest(
            array_agg(v)
        ) as u 
    FROM 
        x
    ) un
WHERE 
    u IS NOT NULL;

द्वितीय:

/*
With reference to
http://ejrh.wordpress.com/2011/09/27/denormalisation-aggregate-function-for-postgresql/
*/
CREATE OR REPLACE FUNCTION fn_array_agg_notnull (
    a anyarray
    , b anyelement
) RETURNS ANYARRAY
AS $$
BEGIN

    IF b IS NOT NULL THEN
        a := array_append(a, b);
    END IF;

    RETURN a;

END;
$$ IMMUTABLE LANGUAGE 'plpgsql';

CREATE AGGREGATE array_agg_notnull(ANYELEMENT) (
    SFUNC = fn_array_agg_notnull,
    STYPE = ANYARRAY,
    INITCOND = '{}'
);

दूसरे को कॉल करना (स्वाभाविक रूप से) पहले की तुलना में थोड़ा अच्छा है:

x से array_agg_notnull (v) चुनें;


9

मैं इसे जोड़ रहा हूं भले ही यह धागा काफी पुराना है, लेकिन मैं इस स्वच्छ चाल में चला गया जो छोटे सरणियों पर काफी अच्छी तरह से काम करता है। यह अतिरिक्त पुस्तकालयों या कार्यों के बिना Postgres 8.4+ पर चलता है।

string_to_array(array_to_string(array_agg(my_column)))::int[]

array_to_string()विधि वास्तव में nulls से छुटकारा मिलता है।


8

यदि आप किसी सरणी से NULL को निकालने के सामान्य प्रश्न के आधुनिक उत्तर की तलाश कर रहे हैं , तो यह है:

array_remove(your_array, NULL)

मैं प्रदर्शन के बारे में विशेष रूप से उत्सुक था और सबसे अच्छा संभव विकल्प के लिए इसकी तुलना करना चाहता था:

CREATE OR REPLACE FUNCTION strip_nulls(
    IN array_in ANYARRAY
)
RETURNS anyarray AS
'
SELECT
    array_agg(a)
FROM unnest(array_in) a
WHERE
    a IS NOT NULL
;
'
LANGUAGE sql
;

एक pgbench परीक्षण करना (उच्च आत्मविश्वास के साथ) कि array_remove () दो बार की तुलना में थोड़ा अधिक तेज है । मैंने विभिन्न प्रकार के सरणी आकारों (10, 100 और 1000 तत्वों) और बीच में यादृच्छिक NULLs के साथ दोहरे सटीक संख्याओं पर अपना परीक्षण किया।


@VivekSinha आप किस संस्करण का उपयोग कर रहे हैं? मैंने अभी आपकी क्वेरी का परीक्षण किया और मेरे लिए "{1,2,3}" का परिणाम आया। मैं 12.1 का उपयोग कर रहा हूं।
अलेक्सि थियोडोर

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

3

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

मुझे लगता है कि सरणी में नल रखना Array_Agg की सिर्फ एक (शायद अवांछित) विशेषता है। इससे बचने के लिए आप उपश्रेणियों का उपयोग कर सकते हैं:

SELECT  COALESCE(y.ID, n.ID) ID,
        y.Users,
        n.Users
FROM    (   SELECT  g.ID, ARRAY_AGG(g.Users) AS Users
            FROM    Groups g
            WHERE   g.Canonical = 'Y'
            GROUP BY g.ID
        ) y
        FULL JOIN 
        (   SELECT  g.ID, ARRAY_AGG(g.Users) AS Users
            FROM    Groups g
            WHERE   g.Canonical = 'N'
            GROUP BY g.ID
        ) n
            ON n.ID = y.ID

SQL FIDDLE


धन्यवाद। लेकिन मुझे एक दिए गए समूहीकरण के भीतर पंक्तियों को संभालने के लिए 'केस' की आवश्यकता थी, और उपश्रेणियाँ वहाँ अक्षम होंगी
Daud

0

यह बहुत सरल है, बस सबसे पहले एक नया - (ऋण) ऑपरेटर पाठ के लिए बनाएं [] :

CREATE OR REPLACE FUNCTION diff_elements_text
    (
        text[], text[] 
    )
RETURNS text[] as 
$$
    SELECT array_agg(DISTINCT new_arr.elem)
    FROM
        unnest($1) as new_arr(elem)
        LEFT OUTER JOIN
        unnest($2) as old_arr(elem)
        ON new_arr.elem = old_arr.elem
    WHERE old_arr.elem IS NULL
$$ LANGUAGE SQL IMMUTABLE;

CREATE OPERATOR - (
    PROCEDURE = diff_elements_text,
    leftarg = text[],
    rightarg = text[]
);

और बस सरणी [null] घटाएँ:

select 
    array_agg(x)-array['']
from
    (   select 'Y' x union all
        select null union all
        select 'N' union all
        select '' 
    ) x;

बस इतना ही:

{Y N}


array_agg(x) FILTER (WHERE x is not null)बहुत आसान लगता है: dbfiddle.uk/… और आपको वास्तव में अपने स्वयं के फ़ंक्शन की आवश्यकता नहीं है, आप बस array_remove() dbfiddle.uk/… का
a_horse_with_no_name

-6

एक बड़ा सवाल यह है कि सभी उपयोगकर्ता / समूह कॉम्बोस को एक ही बार में क्यों खींचें। अपने UI कैंट को सभी डेटा को संभालने की गारंटी दें। ओवरसाइज़्ड डेटा में पेजिंग जोड़ना भी एक बुरा विचार है। डेटा देखने से पहले अपने उपयोगकर्ताओं को सेट को फ़िल्टर करने के लिए प्राप्त करें। सुनिश्चित करें कि आपका JOIN विकल्प सेट सूची में है, इसलिए यदि वे चाहें तो प्रदर्शन के लिए फ़िल्टर कर सकते हैं। कभी-कभी 2 प्रश्न उपयोगकर्ताओं को खुश कर देते हैं यदि वे दोनों तेज हैं।

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