PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Possiamo definire una funzione GROUP_CONCAT in PostgreSQL?

C'è un builtin string_agg() che fa quello che vuoi, ma chiedi specificamente che sia chiamato group_concat per la compatibilità con MySQL. Sfortunatamente, string_agg() utilizza un tipo di dati interno per l'accumulo (presumibilmente per evitare di copiare l'intero buffer su ogni append, non ho guardato la fonte però) e non ho trovato un modo per dichiarare un aggregato SQL identico a string_agg( ).

Anche la definizione della funzione group_concat() non funzionerebbe, poiché pg deve essere consapevole del fatto che si tratta di un aggregato, non di una funzione con un aggregato nascosto all'interno, che non funzionerebbe. Tale funzione opererebbe su una riga alla volta:qualsiasi aggregato all'interno aggregherebbe semplicemente una singola riga e la restituirebbe invariata...

Pertanto, questo codice accumulerà gli elementi in un array, quindi aggiungerà i delimitatori "," con array_to_string. Userò la dichiarazione array_agg() (prima che diventasse un built-in) come modello e aggiungerò semplicemente una funzione finalizzatore che convertirà l'array aggregato in testo.

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;

La cosa bella è che dovrebbe funzionare bene per qualsiasi tipo, senza problemi, grazie ai tipi generici "anyarray" e "anyelement".

Presumo che questo sarebbe più lento di string_agg() se string_agg evita effettivamente di copiare l'intero array di aggregazione su ogni append. Questo dovrebbe avere importanza solo se il numero di righe da raggruppare in ogni set è grande, però. In questo caso, probabilmente puoi dedicare un minuto alla modifica della query SQL;)

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