3

次のような単純なテーブルがあります。

user    letter
--------------
1       A
1       A
1       B
1       B
1       B
1       C

2       A
2       B
2       B
2       C
2       C
2       C

次のように、ユーザーごとに「手紙」の上位2回の出現を取得したい

user    letter  rank(within user group)
--------------------
1       B       1
1       A       2

2       C       1
2       B       2

またはさらに良い:列に折りたたまれています

user    1st-most-occurrence  2nd-most-occurrence
1       B                   A
2       C                   B

postgresでこれを達成するにはどうすればよいですか?

4

3 に答える 3

2

このようなもの:

select *
from (
    select userid, 
           letter, 
           dense_rank() over (partition by userid order by count(*) desc) as rnk
    from letters
    group by userid, letter
) t
where rnk <= 2
order by userid, rnk;

列に予約語を使用するのは悪い習慣であるため、 に置き換えuserたことに注意してください。userid

SQLFiddle は次のとおりです: http://sqlfiddle.com/#!12/ec3ec/1

于 2013-09-05T09:48:16.593 に答える
1
with cte as (
    select 
        t.user_id, t.letter,
        row_number() over(partition by t.user_id order by count(*) desc) as row_num
    from Table1 as t
    group by t.user_id, t.letter
)
select
    c.user_id,
    max(case when c.row_num = 1 then c.letter end) as "1st-most-occurance",
    max(case when c.row_num = 2 then c.letter end) as "2st-most-occurance"
from cte as c
where c.row_num <= 2
group by c.user_id

=> sql フィドルのデモ

于 2013-09-05T11:53:36.960 に答える
0

必要な機能:

CREATE OR REPLACE FUNCTION sortCountLimitOffset(anyarray, int, int)
  RETURNS anyarray AS 'select array_agg(x) from (select x from (select unnest($1) as x) as t group by x order by count(*) desc offset $2 limit $3) t;'
  LANGUAGE sql VOLATILE
  COST 100;

解決策 1: (文字列として連結されたすべての文字を返す)

select
    usr,
    array_to_string(sortCountLimitOffset(array_agg(letter), 0, 5), ',')
from ttt
group by usr;

出力:

 usr | array_to_string
-----+-----------------
   1 | B,A,C
   2 | C,B,A
(2 Zeilen)

解決策 2: (n 番目の文字をそれぞれ別の列に返す)

select
    usr,
    array_to_string(sortCountLimitOffset(array_agg(letter), 0, 1), ',') letter1,
    array_to_string(sortCountLimitOffset(array_agg(letter), 1, 1), ',') letter2,
    array_to_string(sortCountLimitOffset(array_agg(letter), 2, 1), ',') letter3,
    array_to_string(sortCountLimitOffset(array_agg(letter), 3, 1), ',') letter4,
    array_to_string(sortCountLimitOffset(array_agg(letter), 4, 1), ',') letter5
from ttt
group by usr;

出力:

 usr | letter1 | letter2 | letter3 | letter4 | letter5
-----+---------+---------+---------+---------+---------
   1 | B       | A       | C       |         |
   2 | C       | B       | A       |         |
(2 Zeilen)

関数が呼び出される関数から SELECT をインライン化することも可能です。しかし、現在の方法では、コードの再利用と保守が容易になっています。

于 2014-02-13T16:14:17.763 に答える