【PostgresSQL】縦持ちデータを横並びにする
経緯
業務で使用しているシステム(PostgresSQL) で、以下のような抽出をしたかったが断念したことがあり、方法を調べました。
やりたいこと
個人コード | 資料ID |
---|---|
0001 | 11111111 |
0002 | 22222222 |
0001 | 33333333 |
0002 | 44444444 |
0001 | 55555555 |
上記のようなデータについて、
下記の通りに個人ごとに資料を並べたい。
個人コード | 資料1 | 資料2 | 資料3 |
---|---|---|---|
0001 | 11111111 | 33333333 | 55555555 |
0002 | 22222222 | 44444444 | (null) |
やったこと
以下のサイトを使うと、ブラウザ上でデータベース環境やSQLの使用可。 sqlfiddle.com
データを用意。
CREATE TABLE Siryo (kojin_cd CHAR(4) NOT NULL, siryo_no VARCHAR(10) NOT NULL, PRIMARY KEY (siryo_no)); BEGIN TRANSACTION; INSERT INTO Siryo VALUES ('0001', '11111111'); INSERT INTO Siryo VALUES ('0002', '22222222'); INSERT INTO Siryo VALUES ('0001', '33333333'); INSERT INTO Siryo VALUES ('0002', '44444444'); INSERT INTO Siryo VALUES ('0001', '55555555'); COMMIT;
このサイトを参考にし、以下のSQLを作ってみた。 dev.classmethod.jp
select tmp.kojin_cd ,max(case tmp.seq when 1 then tmp.siryo_no else null end) as 資料1 ,max(case tmp.seq when 2 then tmp.siryo_no else null end) as 資料2 ,max(case tmp.seq when 3 then tmp.siryo_no else null end) as 資料3 from ( select kojin_cd ,siryo_no ,row_number() over (partition by kojin_cd) as seq from Siryo ) tmp group by tmp.kojin_cd ;
すると、以下のように抽出できた。
個人コード | 資料1 | 資料2 | 資料3 |
---|---|---|---|
0001 | 11111111 | 33333333 | 55555555 |
0002 | 22222222 | 44444444 | (null) |
処理の流れ
まず、サブクエリ部分で、個人ごとに持っている資料に連番を振っている。
select kojin_cd ,siryo_no ,row_number() over (partition by kojin_cd) as seq from Siryo
個人コード | 資料ID | seq |
---|---|---|
0001 | 11111111 | 1 |
0001 | 33333333 | 2 |
0001 | 55555555 | 3 |
0002 | 22222222 | 1 |
0002 | 44444444 | 2 |
そして、上記のサブクエリの抽出結果を使用し、 個人コードでグループ化する。 連番が各個人コードごとで、資料に1から順に振られていることを利用し、caseで連番をそれぞれ取り出し、横並びにしている。
調べたこと
row_number() とは?
=> ウィンドウ関数の1つ。抽出順に1から始まる行番号を付ける。
ウィンドウ関数とは?
ウィンドウ関数は現在の行に何らかとも関係するテーブル行の一纏まり全般の計算を行うhttps://www.postgresql.jp/document/9.1/html/tutorial-window.html より引用)
=> よくわからん
「何らかの条件で並んでいるデータに対して、特定の範囲のデータのみ参照できるようにする機能が用意されており、これをWindowと呼んでいます。ちょうど窓を開けて全体の中の一部を覗くようなイメージでです。そして、このWindowに対して、最大、最小、合計、平均などの集計を行う関数が用意されており、これらのことをWindow関数と呼んでいます」 【ひたすら図で説明】一番やさしい SQL window 関数(分析関数) の使い方 | 趣味や仕事に役立つ初心者DIYプログラミング入門
=> なんとなくわかった。 そして、SUMとかMAXとかMINとか、普段使っている集計関数のこと、Window関数っていうのね...(無知)
ウィンドウ関数は OVER句と一緒に使う
OVER句の( )内には、ORDER BYか、PARTITION BYが入る。PARTITION BY は指定した項目でグループ化するもの、 ORDER BY は指定した項目でソートするもの。 ORDER BYは並び変えであり、グループ化するわけではないので、今回の用途では不向き。
select kojin_cd ,siryo_no ,row_number() over (order by kojin_cd) as seq from Siryo
個人コード | 資料ID | seq |
---|---|---|
0001 | 11111111 | 1 |
0001 | 33333333 | 2 |
0001 | 55555555 | 3 |
0002 | 22222222 | 4 |
0002 | 44444444 | 5 |