it-swarm.com.de

Wie kann ich Nullwerte in array_agg wie in string_agg mit postgres ausschließen?

Wenn ich zum Sammeln von Namen array_agg Verwende, werden meine Namen durch Kommas getrennt. Wenn jedoch ein null -Wert vorhanden ist, wird null auch als Name im Aggregat verwendet. Beispielsweise :

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;

es gibt ,Larry,Phil statt nur Larry,Phil zurück (in meinem 9.1.2 zeigt es NULL,Larry,Phil). wie in dies Geige

Wenn ich stattdessen string_agg() verwende, werden nur die Namen (ohne leere Kommas oder Nullen) wie hier angezeigt

Das Problem ist, dass ich Postgres 8.4 Auf dem Server installiert habe und string_agg() dort nicht funktioniert. Gibt es eine Möglichkeit, array_agg ähnlich wie string_agg () arbeiten zu lassen?

70
Daud

SQL Fiddle

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

Oder einfacher und billiger mit array_to_string, das Nullen beseitigt:

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

SQL Fiddle

21
Clodoaldo Neto

Mit postgresql-9.3 kann man dies tun;

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;

pdate: mit 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;
194
Dale O'Brien

Bei der Lösung der allgemeinen Frage nach dem Entfernen von Nullen aus Array-Aggregaten gibt es zwei Möglichkeiten, das Problem anzugreifen: entweder array_agg (unnest (array_agg (x))) oder ein benutzerdefiniertes Aggregat zu erstellen.

Der erste hat die gezeigte Form oben :

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

Der Zweite:

/*
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 = '{}'
);

Die zweite zu nennen ist (natürlich) ein bisschen schöner als die erste:

wähle array_agg_notnull (v) aus x;

11
rorycl

Ich füge dies hinzu, obwohl dieser Thread ziemlich alt ist, aber ich bin auf diesen netten Trick gestoßen, der auf kleinen Arrays ziemlich gut funktioniert. Es läuft auf Postgres 8.4+ ohne zusätzliche Bibliotheken oder Funktionen.

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

Die array_to_string() -Methode entfernt tatsächlich die Nullen.

7
ced-b

Wie in den Kommentaren vorgeschlagen wurde, können Sie eine Funktion schreiben, um Nullen in einem Array zu ersetzen. Dies wird jedoch auch in dem in den Kommentaren verknüpften Thread erwähnt, der die Effizienz der Aggregatfunktion beeinträchtigt, wenn Sie ein Aggregat erstellen müssen , teilen Sie es und aggregieren Sie es erneut.

Ich denke, dass Nullen im Array nur eine (möglicherweise unerwünschte) Funktion von Array_Agg ist. Sie können Unterabfragen verwenden, um dies zu vermeiden:

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

3
GarethD