SQL集合関数を列方向(横方向)に用いて集計を行う

 SQL集合関数(Sum関数など)や定義域集合関数(DSum関数など)は大変便利ですが、Excelの関数と違って複数のフィールド(列)の間で値を集計することはできません。
 Accessの場合、基本的にテーブルを分割して正規化したうえで運用することが前提となっていますので仕方がありませんが、現実問題として値を横持ちにしているケースは多いです。また、そのようなケースで分散や最大値を求めるのはなかなか面倒ですので、方法をここにメモしておきます。

f:id:accs2014:20161217163345p:plain:right:w600

 例として右のようなテーブルを用います。


f:id:accs2014:20161217163343p:plain:right:w600

 まず、それぞれの選手ごとの点数の標準偏差(点数A~Eの5つの値の標準偏差)を求めてみます。
 クエリのデザインビューで次のような列を設けます。



点数標準偏差: (SELECT StDevP([点数]) FROM
(SELECT 選手ID,点数A AS 点数 FROM 成績テーブル AS x
UNION ALL SELECT 選手ID,点数B from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数C from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数D from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数E from 成績テーブル AS x)
WHERE x.選手ID=成績テーブル.選手ID)

 簡単に言ってUNION ALLにより、横に並んでいる値を縦に並べ替えることでStDevP関数を適用しています。タイトルに偽りありという気もしますがご容赦を;-o-)
 なお、UNION ALLではなくUNIONを使うと重複する値が1つにまとめられてしまい集計結果が変わってしまいますので注意してください。
 決して短くはないですが列が増えても1行増えるだけなので、他の方法を考えれば納得できるレベルかと思います。ただ、レコードが増えると激重になりそうな感じはします。

f:id:accs2014:20161217163342p:plain:right:w600

 データシートビューです。


f:id:accs2014:20161217163340p:plain:right:w600

 次に選手ごとの点数の最大値を求めてみます。IIf関数などでやるとなかなか面倒ですが、関数をMax関数に代えるだけでOKです。
 つまり次のようになります。



点数最大: (SELECT Max([点数]) FROM
(SELECT 選手ID,点数A AS 点数 FROM 成績テーブル AS x
UNION ALL SELECT 選手ID,点数B from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数C from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数D from 成績テーブル AS x
UNION ALL SELECT 選手ID,点数E from 成績テーブル AS x)
WHERE x.選手ID=成績テーブル.選手ID)

f:id:accs2014:20161217163339p:plain:right:w600

 データシートビューです。

 SQLを入力するのも慣れていないとなかなか面倒ですし、ユーザー定義関数を利用する方法も考えられますが、SQL集合関数を取り換えるだけで集計内容を変更できるというのは大きなメリットかと思います。