PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment concaténer les chaînes d'un champ de chaîne dans une requête "group by" PostgreSQL ?

PostgreSQL 9.0 ou version ultérieure :

Postgres moderne (depuis 2010) a le string_agg(expression, delimiter) fonction qui fera exactement ce que le demandeur recherchait :

SELECT company_id, string_agg(employee, ', ')
FROM mytable
GROUP BY company_id;

Postgres 9 a également ajouté la possibilité de spécifier un ORDER BY clause dans toute expression agrégée ; sinon vous devez ordonner tous vos résultats ou traiter un ordre indéfini. Vous pouvez donc maintenant écrire :

SELECT company_id, string_agg(employee, ', ' ORDER BY employee)
FROM mytable
GROUP BY company_id;

PostgreSQL 8.4.x :

PostgreSQL 8.4 (en 2009) a introduit la fonction d'agrégation array_agg(expression) qui collecte les valeurs dans un tableau. Puis 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;

PostgreSQL 8.3.x et versions antérieures :

Lorsque cette question a été posée à l'origine, 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 cet article de liste de diffusion, parmi tant d'autres) consiste à utiliser le textcat intégré fonction (qui se trouve derrière le || opérateur):

CREATE AGGREGATE textcat_all(
  basetype    = text,
  sfunc       = textcat,
  stype       = text,
  initcond    = ''
);

Voici le CREATE AGGREGATE documents.

Cela colle simplement toutes les cordes ensemble, sans séparateur. Afin d'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 un ELSIF vérifiez 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;