エクセルとともだち、という名を名乗っている。プロフィールにもエクセルのこととか書いていきたいと思います、と書いている。だがしかし、振り返るとエクセルのことはほぼ書いてない、SQLとかぬか漬けとかばっかり。嘘ついてすみません。
でも、自他ともに認める相思相愛なのはやはりエクセルさん。(他ってだれ?)
アクセスさんにはおずおずとアプローチしているけどまだまだ壁があり、友達になれない。あこがれのpythonさんや、postgresさんにはほのかな思いを寄せているだけでアプローチすらしていない。
っていうかこんなことブツブツ言っている時点でキチガイだな。人と付き合おうよ~。
それはさておき、「達人に学ぶSQL徹底指南書」を読んで(眺めて)最初の章が「CASE式のススメ」でCASE式はSQLを使いこなすうえで大切なものらしい。しかし、アクセスのSQLではCASEは使えず代わりにSWITCHを使うということが分かった。
【access/SQL】accessSQLではできないこと~CASE式を使おうと思ったら使えない(SWITCHが代用)コメントが書けない
本に書いてあることを参考に、SWITCHでやってみようと思ったのでその記録。
難しくないところだけやってます。
①SWITCHの基本の使い方
②SWITCHを分類集計に使う(GROUP BY)
③SWITCHを使って横展開する(クロス集計みたいなVIEW表を作る)
④条件を分岐させたUPDATE
◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇
①SWITCHの基本の使い方
SWITCHを使うと複数の条件分岐ができます
基本構文はこうです。
SWITCH(条件1, 条件1がTRUEの場合の値 [ , 条件2, 条件2がTRUEの場合の値 ,・・・])
なお、すべての条件に当てはまらなかった場合の値を出したいときは「条件」の部分を「TRUE」とし、判定をせずにすべてがTRUEとなるようにします。
例 : SWITCH(条件1, 値1 , 条件2, 値2 , TRUE, 値3)
上の例で条件1がTRUEの場合、値1が返ります。
条件1がFalseの場合、かつ条件2がTRUEの場合、値2が返ります。
条件1・条件2ともFalseの場合、そもそもTRUEなので判定は何もせず、値3が返ります。
以下のテーブルを使っていろいろやっていきます。
〇点数でランク分けをして列名「ランク」として表示
80点以上ランクA,、60点以上ランクB、60点未満ランクC
SELECT 生徒id, 生徒名, 教科, 点数,
SWITCH(点数>=80, ‘A’, 点数>=60, ‘B’, 点数<60, ‘C’) AS ランク
FROM T期末テスト;
以下のようにしても同じ結果が返ります。
SELECT 生徒id, 生徒名, 教科, 点数,
SWITCH(点数>=80, ‘A’, 点数>=60, ‘B’, TRUE, ‘C’) AS ランク
FROM T期末テスト;
②SWITCHを分類集計に使う(GROUP BY)
点数でランク分けをしてランク毎の個数をカウントします
SELECT
Switch(点数>=80,’A’,点数>=60,’B’,True,’C’) AS ランク,
COUNT(ランク) AS ランク個数
FROM T期末テスト
GROUP BY Switch(点数>=80,’A’,点数>=60,’B’,True,’C’);
集計関数で別名が使えるのが便利ですね。GROUP BY句の後ろには別名は使えませんのでSWITCH関数の部分をコピペします。
以下のようにしても同じ結果が返ります。
SELECT
Switch(点数>=80,’A’,点数>=60,’B’,True,’C’) AS ランク,
COUNT(Switch(点数>=80,’A’,点数>=60,’B’,True,’C’) AS ランク個数
FROM T期末テスト
GROUP BY Switch(点数>=80,’A’,点数>=60,’B’,True,’C’);
ランク個数降順で並べる場合は以下のようにします。
ORDER BY句の後にも別名は使えませんのでランク個数およびSWITCH関数の部分をコピペします。
SELECT
Switch(点数>=80,’A’,点数>=60,’B’,True,’C’) AS ランク,
COUNT(ランク) AS ランク個数
FROM T期末テスト
GROUP BY Switch(点数>=80,’A’,点数>=60,’B’,True,’C’)
ORDER BY COUNT(Switch(点数>=80,’A’,点数>=60,’B’,True,’C’)) DESC;
③SWITCHを使って横展開する(クロス集計みたいなビュー表を作る)
(1)教科ごとにランク毎の個数をクロス集計みたいに表示。
SELECT 教科,
SUM(Switch(点数>=80,1,TRUE, 0)) AS ランクA,
SUM(Switch(点数<80 AND 点数>=60,1,TRUE, 0)) AS ランクB,
SUM(Switch(点数<60,1,TRUE, 0)) AS ランクC
FROM T期末テスト
GROUP BY 教科;
■解説
教科を列(縦の項目)に持ってきて、
点数が80点以上の場合、その行を「1」とする。
80点未満の場合、その行を「0」とする。
その列名をランクAとする。
ランクBは点数が80点未満かつ60点以上の行を1とする。
点数が80点以上または60点未満の行は0。
イメージは以下のようになります。
それを教科で集計すると
英語のランクAは0+0+1+0=1,ランクBは0+1+0+0=1,ランクCは1+0+0+1=2
数学のランクAは0+0+0+0=0,ランクBは1+1+1+0=3,ランクCは0+0+0+1=1
■結果
(2)生徒ごとの教科の点数を横展開表示。
SELECT 生徒id,生徒名,
SUM(Switch(教科=’英語’,点数,TRUE, 0)) AS 英語点数,
SUM(Switch(教科=’数学’,点数,TRUE, 0)) AS 数学点数
FROM T期末テスト
GROUP BY 生徒id,生徒名;
■解説
生徒id、生徒名を列(縦の項目)に持ってきて、
教科が英語の場合、その行の点数を保持、数学の場合は0点とする。
その列名を英語点数とする
教科が数学の場合、その行の点数を保持、英語の場合は0点とする。
その列名を数学点数とする。
集計途中のイメージは以下の通り
それを生徒毎で集計すると
田中太郎の英語点数は55+0=55、数学点数は0+75=75
ほかの生徒も同様に集計。
■結果
④異なる条件の集計を一つのSQLで行う
点数が50以上の場合点数を6割にする、点数が50点未満の場合点数に20点加算する。という操作をしたいとします。(ありえない、ひどい話ですが)
なお、更新クエリUPDATEの基本構文はこうです。
UPDATE テーブル名 SET 列名 = 更新したい値 ( WHERE 条件 )
2回UPDATE分を発行(ダメな例)
1回目
UPDATE T期末テスト
SET 点数 = 点数* 0.6
WHERE 点数 >=50;
2回目
UPDATE T期末テスト
SET 点数 = 点数 + 20
WHERE 点数 < 50;
でもこれではだめです。
例えば田中君は英語の点数が55点のため、55×0.6 = 33点になるべきです。
でも、2回目のUPDATEの50点未満に引っかかり、55+20=75点に再度点数が変更になってしまいます。
SWITCHを使った場合
UPDATE T期末テスト
SET 点数 = SWITCH(点数>=50,点数*0.6,点数<50,点数+20);
1回ですっきり
なお、60点以上は10点プラス、40点以下は10点マイナス、41~59点はそのままにしたい場合
UPDATE T期末テスト
SET 点数 = SWITCH(点数>=60, 点数+10, 点数<40, 点数-10,TRUE, 点数);
となります。
最後のそのままにしたい場合の分岐TRUEを忘れると、41~59点はNULL値になってしまいますので注意が必要です(私はよく忘れるので)
UPDATE T期末テスト
SET 点数 = SWITCH(点数>=60, 点数+10, 点数<40, 点数-10);
↑これだと41~59点はNULL値になる
以上、自分が理解するためにやったことを書き出しました。
わかりやすく解説できていればこれ幸いです。
お読みいただきありがとうございました。
参考にした書籍
(リンクは第二版のものです。私が中古で購入したのは第二版と書いてないので初版だと思われる。)
参考とさせていただいた情報のURL
コメント