2012-01-28 4 views
2
create temp table tmp_apps (
    id integer 
); 

create temp table tmp_pos (
    tmp_apps_id integer, 
    position integer 
); 

insert into tmp_apps 
select 1 id union 
select 2 id 
; 

insert into tmp_pos (tmp_apps_id, position) 
select 1 tmp_apps_id, 1 as position union all 
select 1 tmp_apps_id, 1 as position union all 
select 1 tmp_apps_id, 2 as position union all 
select 1 tmp_apps_id, 3 as position union all 
select 1 tmp_apps_id, 3 as position union all 
select 2 tmp_apps_id, 1 as position 
; 
/* 
Expected result: 
tmp_apps_id tmp_pos_position 
1   1,2 
2   1 
*/ 

Comment obtenir d'abord séparé par des virgules 2, tmp_pos.position distincte pour chaque tmp_apps.id
Il est possible?postgresql requête de sélection

+0

+1 pour un test de fonctionnement. * C'est * comment vous rendre plus facile de vous aider. –

Répondre

1
WITH x AS (
    SELECT tmp_apps_id 
     , position 
     , row_number() OVER (PARTITION BY tmp_apps_id ORDER BY position) AS rn 
    FROM tmp_pos 
    GROUP BY 1, 2 
    ORDER BY 1, 2 
    ) 
SELECT tmp_apps_id, string_agg(position::text, ', ') 
FROM x 
WHERE rn < 3 
GROUP BY 1; 

Cela arrive à être Tout comme la solution @araqnid posté un peu plus vite que moi.
CTE ou sous-requête, c'est juste deux façons de faire la même chose dans ce cas.

Ma version est différente dans un aspect important:
En utilisant GROUP BY au lieu de DISTINCT pour obtenir des valeurs distinctes, vous pouvez appliquer le window function row_number() (élément clé pour la solution) dans le même niveau de requête et ne pas besoin d'une autre sous-requête (ou CTE).

La raison en est que l'agrégation (GROUP BY) est appliquée avant fonctions de fenêtre tandis que l'on applique DISTINCTaprès. Dans de nombreuses situations DISTINCT et GROUP BY offrent des solutions tout aussi bonnes. Dans un cas comme celui-ci, vous pouvez mettre à profit la différence subtile si vous la connaissez. Je m'attends à ce que ce soit un peu plus rapide.

+0

Je voudrais d'abord vous remercier pour l'excellente réponse. Je suis vraiment surpris par le regroupement par numéro de colonne et je veux demander: En général, cette manière donne une augmentation de la vitesse par rapport au regroupement par nom de colonne? – cetver

+0

@cetver: Si vous voulez dire les nombres ordinaux dans ['GROUP BY'] (http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-GROUPBY) et' ORDER BY', alors non. C'est juste une commodité de notation. Aucun effet sur la performance. –

0

Essayez ceci à l'aide array_agg ou string_agg, en fonction de votre version de Postgres:

SELECT tmp_apps_id, array_agg(tmp_pos_position) 
FROM tmp_pos_position 
GROUP BY tmp_apps_id 

En 9.0, utilisez la fonction string_agg:

SELECT tmp_apps_id, string_agg(tmp_pos_position, ',') 
FROM tmp_pos_position 
GROUP BY tmp_apps_id 
+0

'string_agg' traite tous les enregistrements, mais j'ai seulement besoin de 2 avec des valeurs distinctes – cetver

1
select tmp_apps_id, string_agg(position::text,',') 
from (
select tmp_apps_id, position, 
     row_number() over (partition by tmp_apps_id order by position) 
from (
    select distinct tmp_apps_id, tmp_pos.position from tmp_pos 
) x 
) x 
where row_number <= 2 
group by tmp_apps_id;