PostgreSQL 9.0 ou version ultérieure:
Les versions récentes de Postgres (depuis fin 2010) ont la string_agg(expression, delimiter)
fonction qui fera exactement ce que la question demandait, vous permettant même de spécifier la chaîne de délimitation:
SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;
Postgres 9.0 a également ajouté la possibilité de spécifier une ORDER BY
clause dans n'importe quelle expression agrégée ; sinon, la commande n'est pas définie. Vous pouvez donc maintenant écrire:
SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;
Ou bien:
SELECT string_agg(actor_name, ', ' ORDER BY first_appearance)
PostgreSQL 8.4 ou version ultérieure:
PostgreSQL 8.4 (en 2009) a introduit la fonction d'agrégationarray_agg(expression)
qui concatène les valeurs dans un tableau. Ensuite, array_to_string()
peut être utilisé pour donner le résultat souhaité:
SELECT company_id, array_to_string(array_agg(employee), ', ')
FROM mytable
GROUP BY company_id;
string_agg
pour les versions antérieures à 8.4:
Dans le cas où quelqu'un rencontre ce problème à la recherche d'un module de compatibilité pour les bases de données antérieures à la version 9.0, il est possible de tout mettre en œuvre à l' string_agg
exception de la ORDER BY
clause.
Ainsi, avec la définition ci-dessous, cela devrait fonctionner de la même manière que dans une base de données Postgres 9.x:
SELECT string_agg(name, '; ') AS semi_colon_separated_names FROM things;
Mais ce sera une erreur de syntaxe:
SELECT string_agg(name, '; ' ORDER BY name) AS semi_colon_separated_names FROM things;
--> ERROR: syntax error at or near "ORDER"
Testé sur 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
);
Variations personnalisées (toutes les versions Postgres)
Avant la version 9.0, il n'y avait pas de fonction d'agrégation intégrée pour concaténer les chaînes. L'implémentation personnalisée la plus simple ( suggérée par Vajda Gabo dans cette publication de liste de diffusion , entre autres) consiste à utiliser la textcat
fonction intégrée (qui se trouve derrière l' ||
opérateur):
CREATE AGGREGATE textcat_all(
basetype = text,
sfunc = textcat,
stype = text,
initcond = ''
);
Voici la CREATE AGGREGATE
documentation.
Cela colle simplement toutes les cordes ensemble, sans séparateur. Pour obtenir un "," inséré entre eux sans l'avoir à la fin, vous pouvez créer votre propre fonction de concaténation et la remplacer par le "textcat" ci-dessus. En voici un que j'ai assemblé et testé le 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;
Cette version affichera une virgule même si la valeur de la ligne est nulle ou vide, vous obtenez donc une sortie comme celle-ci:
a, b, c, , e, , g
Si vous préférez supprimer les virgules supplémentaires pour afficher ceci:
a, b, c, e, g
Ajoutez ensuite une ELSIF
vérification à la fonction comme ceci:
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;