2012-01-28 12 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 
*/ 

、それが可能である各tmp_apps.id
のための明確なtmp_pos.positionpostgresqlの最初の2カンマ区切り取得する方法選択クエリ

+0

+1動作テストケースです。 *あなたの手助けをより簡単にする方法です。 –

答えて

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; 

:9.0で

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

を、string_agg機能を使用します解決策@araqnidが私より少し速く投稿されたように。
CTEまたはサブクエリの場合は、この場合、これを行うには2通りの方法があります。

私のバージョンは1つの重要な側面で異なっている:
個別の値を取得するためにGROUP BY代わりのDISTINCTを使用すると、同じクエリレベルでwindow function row_number()(解決のための重要な要素)を適用していない行うことができます別のサブクエリ(またはCTE)が必要です。

この理由は、DISTINCTが後を印加しながら前に窓関数を適用される集合(GROUP BY)です。多くの場合、DISTINCTGROUP BYは同様に優れたソリューションを提供します。このような場合、微妙な違いを知っていれば良い使い方にすることができます。私はこれがかなり速くなると期待しています。

+0

まずは素晴らしい答えに感謝します。 私は列番号でグループ化することに本当に驚きました。質問したい: 一般的に、この方法は列名によるグループ化と比較して速度が向上しますか? – cetver

+0

@cetver:[GROUP BY'](http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-GROUPBY)と 'ORDER BY'の順序番号を意味する場合は、そうではない。それは単に表記の便利です。パフォーマンスに影響を与えません。 –

0

array_aggまたはstring_agg、Postgresののバージョンによって使用して、これを試してみてください。これがあることを起こる

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

'string_agg'はすべてのレコードを処理しますが、私は別個の値を持つ2つしか必要ありません – 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; 
関連する問題