PostgreSQL 9.0 o successivo:
Le versioni recenti di Postgres (dalla fine del 2010) hanno la string_agg(expression, delimiter)
funzione che farà esattamente quello che la domanda ha posto, anche permettendoti di specificare la stringa del delimitatore:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
Postgres 9.0 ha anche aggiunto la possibilità di specificare una ORDER BY
clausola in qualsiasi espressione aggregata ; in caso contrario, l'ordine non è definito. Quindi ora puoi scrivere:
SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
O davvero:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
PostgreSQL 8.4 o successivo:
PostgreSQL 8.4 (nel 2009) ha introdotto la funzione aggregataarray_agg(expression)
che concatena i valori in un array. Quindi array_to_string()
può essere utilizzato per dare il risultato desiderato:
SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;
string_agg
per le versioni pre-8.4:
Nel caso in cui qualcuno si trovi in cerca di uno shim di compatibilità per database pre-9.0, è possibile implementare tutto string_agg
tranne la ORDER BY
clausola.
Quindi, con la definizione che segue, dovrebbe funzionare come in un DB Postx 9.x:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
Ma questo sarà un errore di sintassi:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
Testato su 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
);
Variazioni personalizzate (tutte le versioni di Postgres)
Prima della 9.0, non c'era alcuna funzione aggregata incorporata per concatenare le stringhe. L'implementazione personalizzata più semplice ( suggerita da Vajda Gabo in questo post della mailing list , tra molti altri) è quella di utilizzare la textcat
funzione integrata (che si trova dietro l' ||
operatore):
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
Ecco la CREATE AGGREGATE
documentazione
Questo semplicemente incolla tutte le stringhe insieme, senza separatore. Per ottenere un "," inserito tra loro senza averlo alla fine, potresti voler creare la tua funzione di concatenazione e sostituirla con il "textcat" sopra. Eccone uno che ho messo insieme e testato l'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;
Questa versione produrrà una virgola anche se il valore nella riga è nullo o vuoto, quindi ottieni un output in questo modo:
a, b, c, , e, , g
Se preferisci rimuovere le virgole aggiuntive per generare questo:
a, b, c, e, g
Quindi aggiungere un ELSIF
segno di spunta alla funzione in questo modo:
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;