PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Können wir eine GROUP_CONCAT-Funktion in PostgreSQL definieren?

Es gibt ein eingebautes string_agg(), das tut, was Sie wollen, aber Sie bitten ausdrücklich darum, dass es aus Gründen der MySQL-Kompatibilität group_concat heißt. Leider verwendet string_agg() einen internen Datentyp für die Akkumulation (vermutlich um zu vermeiden, dass der gesamte Puffer bei jedem Anhängen kopiert wird, ich habe mir die Quelle jedoch nicht angesehen) und ich habe keinen Weg gefunden, eine SQL-Aggregation identisch mit string_agg( ).

Das Definieren der Funktion group_concat() würde auch nicht funktionieren, da pg bewusst gemacht werden muss, dass es sich um ein Aggregat handelt, nicht um eine Funktion mit einem darin versteckten Aggregat, was nicht funktionieren würde. Eine solche Funktion würde jeweils nur eine Zeile bearbeiten:Jedes Aggregat darin würde nur eine einzelne Zeile aggregieren und sie unverändert zurückgeben ...

Daher akkumuliert dieser Code die Elemente in einem Array und fügt dann die ","-Trennzeichen mit array_to_string hinzu. Ich werde die array_agg()-Deklaration (bevor sie eingebaut wurde) als Modell verwenden und einfach eine Finalizer-Funktion hinzufügen, die das aggregierte Array in Text umwandelt.

CREATE OR REPLACE FUNCTION _group_concat_finalize(anyarray)
RETURNS text AS $$
    SELECT array_to_string($1,',')
$$ IMMUTABLE LANGUAGE SQL;

CREATE AGGREGATE group_concat(anyelement) (
   SFUNC=array_append,
   STYPE=anyarray,
   FFUNC=_group_concat_finalize,
   INITCOND='{}'
);

SELECT group_concat(x) FROM foo;

Das Schöne daran ist, dass es dank der generischen Typen "anyarray" und "anyelement" problemlos für jeden Typ funktionieren sollte.

Ich würde vermuten, dass dies langsamer als string_agg() wäre, wenn string_agg tatsächlich vermeidet, das gesamte Aggregationsarray bei jedem Anhängen zu kopieren. Dies sollte jedoch nur von Bedeutung sein, wenn die Anzahl der in jedem Satz zu gruppierenden Zeilen groß ist. In diesem Fall können Sie wahrscheinlich eine Minute damit verbringen, die SQL-Abfrage zu bearbeiten;)

http://sqlfiddle.com/#!17/c452d/1