コマンド道場

$ man percent-rank

PERCENT_RANK / CUME_DIST

ウィンドウ関数

順位を 0〜1 の割合で返す。2 つは端の扱いが違う。

呼び出しの形

PERCENT_RANK() OVER (ORDER BY 式)
CUME_DIST() OVER (ORDER BY 式)

つまずきやすいところ

  • PERCENT_RANK は最初の行が必ず 0CUME_DIST は 0 より大きい値から始まります。「上位何 %」を出すなら CUME_DIST のほうが素直です。

  • 1 行しかない区切りでは PERCENT_RANK が 0 になります。区切りごとに計算していると、少数の区切りで値が跳ねます。

  • 戻り値は double precision です。表示桁をそろえるなら numeric に変換してから丸めてください。

実行例

結果は実際に流したものです。同じ SQL を 自由に打てる画面 で試すと、同じ結果になります。

2 つを並べて端の違いを見る
SELECT name, salary, ROUND(PERCENT_RANK() OVER (ORDER BY salary DESC)::numeric, 3) AS percent_rank, ROUND(CUME_DIST() OVER (ORDER BY salary DESC)::numeric, 3) AS cume_dist FROM shain ORDER BY salary DESC
namesalarypercent_rankcume_dist
鈴木9800000.0000.056
佐藤7200000.0590.111
山田7000000.1180.167
清水6500000.1760.222
加藤6100000.2350.278
伊藤5300000.2940.389
中村5300000.2940.389
田中5200000.4120.444

18(うち 8 行を表示)

PERCENT_RANK は先頭が 0、CUME_DIST は 0 より大きい値から始まります。

1 人だけの部署では値が跳ねる
SELECT busho_id, name, ROUND(PERCENT_RANK() OVER (PARTITION BY busho_id ORDER BY salary DESC)::numeric, 3) AS pr, ROUND(CUME_DIST() OVER (PARTITION BY busho_id ORDER BY salary DESC)::numeric, 3) AS cd FROM shain ORDER BY busho_id, pr
busho_idnameprcd
1鈴木0.0001.000
2佐藤0.0000.250
2中村0.3330.500
2田中0.6670.750
2小林1.0001.000
3山田0.0000.250
3伊藤0.3330.500
3高橋0.6670.750

18(うち 8 行を表示)

1 行しかない区切りでは PERCENT_RANK が 0、CUME_DIST が 1 になります。

説明

順位を件数によらない割合で表す関数です。母数が違う集団を比べるときに使います。

  • PERCENT_RANK(順位 - 1) ÷ (総行数 - 1)最初の行が必ず 0、最後が 1
  • CUME_DIST … 累積分布。0 より大きく 1 以下で、最後が必ず 1

「上位何 % か」を出したいなら CUME_DIST、「先頭からの相対位置」なら PERCENT_RANK が素直です。

⚠️ 同じ値には同じ割合が付きます。 位置ではなく順位を使うためで、NTILE のように同値が別のグループへ分かれることはありません。

⚠️ 行が 1 行しかないとき、PERCENT_RANK は 0 になります(分母が 0 になるので特別扱いされます)。CUME_DIST は 1 です。区切りごとに計算していると、1 件だけの区切りで値が跳ねるので注意してください。

次に読む

根拠にした一次情報