個人的なメモメモ。


(SQLが表示されないなどがあったので、適当なとこで折り返しをつけてます)

以下のような表があるとします。



| id | name | stid | ndid |
|  1 | aaa  | 100  | 10   |
|  2 | bbb  | 101  | 20   |
|  3 | ccc  | 102  | 20   |
|  4 | ddd  | 200  | 30   |
|  5 | eee  | 199  | 30   |
|  6 | fff  | 198  | 30   |


この時、"ndid"単位でグループ化して、グループの中の"stid"が最も小さいものを選びたい。

こんな結果が欲しい訳です。


| id | name | stid | ndid |
|  1 | aaa  | 100  | 10   |
|  2 | bbb  | 101  | 20   |
|  6 | fff  | 198  | 30   |



ndid=10のうち最もstidが小さいid=1

ndid=20のうち最もstidが小さいid=2

ndid=30のうち最もstidが小さいid=6

が選ばれています。


この選び方をするのに「partition by」を用いました。


まずはこちらのSQLを実行してみます。表名は"test"で作ってあります。



select
  id,name,ndid,stid,
  row_number()
    over( partition by ndid order by stid ) row_num
from test


結果は以下のようになります。



| id | name | stid | ndid | row_num |
|  1 | aaa  | 100  | 10   | 1       |
|  2 | bbb  | 101  | 20   | 1       |
|  3 | ccc  | 102  | 20   | 2       |
|  6 | fff  | 198  | 30   | 1       |
|  5 | eee  | 199  | 30   | 2       |
|  4 | ddd  | 200  | 30   | 3       |


簡単に言うと、「partition by」で小さなグループに分けられて処理されます。

分けた小さなグループ単位で行数を割り振っています。


ここまで抜ければ、後は条件を1つ足すだけです。



select *
from
(
 select
  id,name,ndid,stid,
  row_number()
    over( partition by ndid order by stid ) row_num
 from test
)
where row_num = 1


結果がこちら。



| id | name | stid | ndid | row_num |
|  1 | aaa  | 100  | 10   | 1       |
|  2 | bbb  | 101  | 20   | 1       |
|  6 | fff  | 198  | 30   | 1       |


抜き出したいものを抜き出すことができました。




(番外編)

ndid単位で抜き出したけど、それぞれ何行がひとまとまりになったのだろうか?

という場合はこちら。



select *
from
(
 select
  id,name,ndid,stid,
  row_number()
    over( partition by ndid order by stid ) row_num,
  count(ndid) over ( partition by ndid ) cn
 from test
)
where row_num = 1

結果がこちら。



| id | name | stid | ndid | row_num | cn |
|  1 | aaa  | 100  | 10   | 1       | 1  |
|  2 | bbb  | 101  | 20   | 1       | 2  |
|  6 | fff  | 198  | 30   | 1       | 3  |


cnを見れば、いくつがまとまったのかが分かります。