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

如何獲得第2逗號分隔,不同tmp_pos.position每個tmp_apps.id
這是可能的嗎?PostgreSQL的選擇查詢

+0

工作測試用例+1。 *這是*你如何更容易地幫助你。 – 2012-01-29 00:05:52

回答

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; 

這恰好是很像解決方案@araqnid的發佈速度比我快。
CTE或子查詢,這只是在這種情況下做同樣的兩種方法。

我的版本是一個重要的方面不同:
使用GROUP BY,而不是DISTINCT得到不同的值,可以在相同的查詢級別應用window function row_number()(該解決方案的關鍵要素)和不需要另一個子查詢(或CTE)。

這樣做的原因是,聚合(GROUP BY),同時DISTINCT被之後施加施加之前窗函數。在很多情況下,DISTINCTGROUP BY提供同樣好的解決方案。在這樣的情況下,如果你知道的話,你可以把這個微妙的區別變得好用。我預計這會更快一點。

+0

首先我要感謝您的出色答案。 我真的很驚訝,按列號分組,我想問: 在一般情況下,與列名分組相比,這種方式會提高速度嗎? – cetver 2012-01-28 22:59:33

+0

@cetver:如果您指的是['GROUP BY'](http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-GROUPBY)和'ORDER BY'中的序數,那就不要。這只是符號的便利。對性能沒有影響。 – 2012-01-29 00:10:05

0

試試這個使用array_aggstring_agg,這取決於你的版本的Postgres:

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

在9.0,使用string_agg功能:

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

'string_agg'處理所有記錄,但我只需要2個不同的值 – cetver 2012-01-28 21:45:29

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;