web-dev-qa-db-ja.com

別のフィールドでグループ化するときに、文字列の最大出現数を正しく選択するにはどうすればよいですか?

Postgresql 9.0を使用しています。テーブルに次のフィールドがあります:id, name

 id    name 
 1     John
 1     Mary
 1     Mary
 1     Mary
 1     John
 1     Mary
 3     Paul
 3     Paul
 3     George
 .     .
 .     .

idごとに、最も多く出現する名前を選択します。どうやってやるの?

次のクエリを試してみましたが、機能しません。

select id, max(name) 
from table 
group by id;
7
Tudor

これは簡単なことではありません。まず、IDと名前でグループ化し、行をカウントします。

_SELECT COUNT(*)
...
GROUP BY id, name
_

次に、すべてのIDの最大数を選択します。これを実現する1つの方法は、ウィンドウ関数を使用することです。 RANK()関数:

_RANK() OVER (PARTITION BY id ORDER BY COUNT(*) DESC)
_

(グループ化が行われた後)結果のすべての行に番号を割り当て、それらを(行)を同じidのパーティションに配置し、COUNT(*) DESCで順序付けするため、すべての(パーティションof)id、最大カウントの行にはランク1が割り当てられます。したがって、上記を派生テーブルに入れ、WHERE条件を使用してこれらのみを保持する必要があります行:

_WHERE rnk = 1
_

最終的なクエリは次のようになります。

_SELECT
    id, name, cnt
FROM
    ( SELECT id, name, COUNT(*) AS cnt,
             RANK() OVER (PARTITION BY id ORDER BY COUNT(*) DESC) AS rnk
      FROM tableX
      GROUP BY id, name
    ) AS tg 
WHERE
    rnk = 1 ;
_

SQL-Fiddleでテスト済み


最初に同点(同じ最大数の2つ以上の名前)がある場合、これらすべてが返されることに注意してください。最終結果のIDごとに厳密に1行が必要な場合は、ROW_NUMBER()の代わりにRANK()を使用し、_ORDER BY_句を変更して、関係は解決されます:

_ROW_NUMBER() OVER (PARTITION BY id ORDER BY COUNT(*) DESC, name ASC) AS rnk
_

テスト済み:SQL-Fiddle test-2

9
ypercubeᵀᴹ