web-dev-qa-db-fra.com

PostgreSQL 9.1: Comment concaténer des lignes dans un tableau sans doublons, JOIN une autre table

J'utilise PostgreSQL 9.1 et j'ai besoin d'aide pour concaténer plusieurs lignes en une. Je dois le faire dans 2 tableaux. Lorsque j'utilise deux fois les fonctions array_agg() j'obtiens des valeurs dupliquées en résultat.

Les tables:

CREATE TABLE rnp (id int, grp_id int, cabinets varchar(15) );

INSERT INTO rnp VALUES
 (1,'11','cabs1')
,(2,'11','cabs2')
,(3,'11','cabs3')
,(4,'11','cabs4')
,(5,'22','c1')
,(6,'22','c2');

CREATE TABLE ips (id int, grp_id int, address varchar(15));

INSERT INTO ips VALUES
 (1,'11','NY')
,(2,'11','CA')
,(3,'22','DC')
,(4,'22','LA');

SQL:

SELECT DISTINCT

  rnp.grp_id,
  array_to_string(array_agg(rnp.cabinets)OVER (PARTITION BY rnp.grp_id), ',') AS cabinets,
  array_to_string(array_agg(ips.address) OVER (PARTITION BY ips.grp_id), ',') AS addresses


FROM rnp JOIN ips ON rnp.grp_id=ips.grp_id

Résultat:

GRP_ID  CABINETS                                             ADDRESSES
11  cabs1,cabs1,cabs2,cabs2,cabs3,cabs3,cabs4,cabs4     NY,CA,NY,CA,NY,CA,NY,CA
22  c1,c1,c2,c2                                             DC,LA,DC,LA

Et ce dont j'ai besoin c'est:

 GRP_ID     CABINETS                 ADDRESSES
    11  cabs1,cabs2,cabs3,cabs4       NY,CA,
    22  c1,c2                         DC,LA

Cet exemple dans SQLFiddle: http://sqlfiddle.com/#!1/4815e/19

Il n'y a aucun problème si vous utilisez une table - SQLFiddle: http://sqlfiddle.com/#!1/4815e/2

Qu'est-ce que je rate? Est-il possible de le faire, grâce à JOIN?

31
lara80

Au lieu d'utiliser des fonctions de fenêtre et des applications, utilisez un GROUP BY de niveau requête et agrégez avec une clause DISTINCT:

SELECT         
  rnp.grp_id,
  array_to_string(array_agg(distinct rnp.cabinets),',') AS cabinets,
  array_to_string(array_agg(distinct ips.address),',')  AS addresses
FROM rnp JOIN ips ON rnp.grp_id=ips.grp_id GROUP BY rnp.grp_id, ips.grp_id;

Résultat:

 grp_id |        cabinets         | addresses 
--------+-------------------------+-----------
     11 | cabs1,cabs2,cabs3,cabs4 | CA,NY
     22 | c1,c2                   | DC,LA
(2 rows)

La clé ici est qu'au lieu d'utiliser les fonctions de fenêtre et les requêtes, vous utilisez un niveau de requête GROUP BY et agréger avec une clause DISTINCT.

Cela fonctionnerait également avec l'approche de la fonction de fenêtre, sauf que PostgreSQL (9.1 au moins) ne prend pas en charge DISTINCT dans les fonctions de fenêtre:

regress=# SELECT DISTINCT
  rnp.grp_id,
  array_to_string(array_agg(distinct rnp.cabinets)OVER (PARTITION BY rnp.grp_id), ',') AS cabinets,                    
  array_to_string(array_agg(distinct ips.address) OVER (PARTITION BY ips.grp_id), ',') AS addresses
FROM rnp JOIN ips ON rnp.grp_id=ips.grp_id;
ERROR:  DISTINCT is not implemented for window functions
LINE 3:   array_to_string(array_agg(distinct rnp.cabinets)OVER (PART...
33
Craig Ringer