コマンド道場

$ man first-value

FIRST_VALUE / LAST_VALUE

ウィンドウ関数

区切りの中の最初・最後の値を持ってくる。LAST_VALUE は既定のままだと期待どおりに動かない。

呼び出しの形

FIRST_VALUE(式) OVER (PARTITION BY 式 ORDER BY 式)
LAST_VALUE(式) OVER (PARTITION BY 式 ORDER BY 式)
LAST_VALUE(式) OVER (PARTITION BY 式 ORDER BY 式 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

つまずきやすいところ

  • LAST_VALUE は既定のフレームだと自分自身を返します。ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING を明示してください。

  • FIRST_VALUE にはこの問題がありません。片方だけが壊れるので気づきにくいです。

  • 同じ値が並ぶと「最初」「最後」が決まりません。ORDER BY に一意になる列を足して、結果を安定させてください。

実行例

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

部署ごとに最高給与の人の名前を並べる
SELECT busho_id, name, salary, FIRST_VALUE(name) OVER (PARTITION BY busho_id ORDER BY salary DESC, shain_id) AS saikou_kyuuyo_no_hito FROM shain ORDER BY busho_id, salary DESC
busho_idnamesalarysaikou_kyuuyo_no_hito
1鈴木980000鈴木
2佐藤720000佐藤
2中村530000佐藤
2田中520000佐藤
2小林445050佐藤
3山田700000山田
3伊藤530000山田
3高橋480000山田

18(うち 8 行を表示)

最大値ではなく「その行の名前」がほしいときに使います。

LAST_VALUE は既定のままだと自分自身を返す
SELECT busho_id, name, salary, LAST_VALUE(name) OVER (PARTITION BY busho_id ORDER BY salary DESC, shain_id) AS kitai_hazure, LAST_VALUE(name) OVER (PARTITION BY busho_id ORDER BY salary DESC, shain_id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS tadashii FROM shain ORDER BY busho_id, salary DESC
busho_idnamesalarykitai_hazuretadashii
1鈴木980000鈴木鈴木
2佐藤720000佐藤小林
2中村530000中村小林
2田中520000田中小林
2小林445050小林小林
3山田700000山田松本
3伊藤530000伊藤松本
3高橋480000高橋松本

18(うち 8 行を表示)

左の列は各行が自分の名前になります。フレームを明示した右の列が、意図した結果です。

説明

FIRST_VALUE は区切りの中の最初の行LAST_VALUE最後の行の値を返します。「部署ごとの最高給与の人の名前」のように、最大値ではなく、その行の別の列がほしいときに使います。

⚠️ LAST_VALUE は既定のままだと「最後」になりません。ORDER BY を書くとフレームの既定が「最初から現在行まで」になるので、LAST_VALUE は各行で「そこまでの最後」=自分自身を返してしまいます。

本当に区切りの最後がほしいなら、フレームを明示します。

  • ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING

FIRST_VALUE は既定のフレームでも「最初」を指すので、この問題は起きません。片方だけが静かに壊れるのが、この 2 つの厄介なところです。

ほかの製品でも通るか

未確認の製品があります そのまま使える: PostgreSQL / MySQL / MariaDB / SQLite / SQL Server

未確認: Oracle Database / IBM Db2

製品ごとの対応表(根拠つき)を見る

次に読む

根拠にした一次情報