トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

9-1 複数行を1行に変換

SQLパズル

Namesテーブル
name
-------
Al
Ben
Charlie
David
Ed
Frank
Greg
Howard
Ida
Joe
Ken
Larry
Mike

Namesテーブルのname列を
5行ごとに、1行で表示する(最終行の余った列は、nullとする)
出力順は、行も列も、Namesテーブルのname列の昇順とする。

出力例(2行を1行に変換)
name1    name2
-------  ------
Al       Ben
Charlie  David
Ed       Frank
Greg     Howard
Ida      Joe
Ken      Larry
Mike     null

出力例(3行を1行に変換)
name1  name2   name3
-----  ------  -------
Al     Ben     Charlie
David  Ed      Frank
Greg   Howard  Ida
Joe    Ken     Larry
Mike   null    null

出力例(4行を1行に変換)
name1  name2  name3    name4
-----  -----  -------  ------
Al     Ben    Charlie  David
Ed     Frank  Greg     Howard
Ida    Joe    Ken      Larry
Mike   null   null     null

出力例(5行を1行に変換)
name1  name2  name3    name4  name5
-----  -----  -------  -----  -----
Al     Ben    Charlie  David  Ed
Frank  Greg   Howard   Ida    Joe
Ken    Larry  Mike     null   null

SQLパズル 第2版のパズル62 [レポートの整形] を参考にさせていただきました


データ作成スクリプト

create table Names(name char(10) primary key);

insert into Names values('Al');
insert into Names values('Ben');
insert into Names values('Charlie');
insert into Names values('David');
insert into Names values('Ed');
insert into Names values('Frank');
insert into Names values('Greg');
insert into Names values('Howard');
insert into Names values('Ida');
insert into Names values('Joe');
insert into Names values('Ken');
insert into Names values('Larry');
insert into Names values('Mike');


SQL

--■■■window関数を使う方法■■■
select
max(case rn%5 when 0 then name end) as name1,
max(case rn%5 when 1 then name end) as name2,
max(case rn%5 when 2 then name end) as name3,
max(case rn%5 when 3 then name end) as name4,
max(case rn%5 when 4 then name end) as name5
from (select name,
      -1+Row_Number() over(order by name) as rn
        from Names) a
group by rn/5
order by rn/5;

--■■■window関数を使わない方法■■■
select
max(case rn%5 when 0 then name end) as name1,
max(case rn%5 when 1 then name end) as name2,
max(case rn%5 when 2 then name end) as name3,
max(case rn%5 when 3 then name end) as name4,
max(case rn%5 when 4 then name end) as name5
from (select name,
      (select count(*)
         from Names b
        where b.name < a.name) as rn
        from Names a) c
group by rn/5
order by rn/5;


解説

-1+Row_Number() over(order by name)として、C言語やJavaの配列の感覚で考えてます。

PostgreSQLの/演算子による整数型/整数型
は、C言語やJavaの/演算子と同じように、小数以下を切り捨てます。

int i=9;
i/=5; // iは1です(小数以下を切り捨て)

9.3. 算術関数と演算子

OracleSQLパズル 9-1 複数行を1行に変換