2012-01-28 49 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;