達人に学ぶSQL徹底指南書を読んで知見を得つつ、
これRailsのActiveRecordで書こうと思ったらどうなるのかと思ったのでやってみた
CASE式
select, group
これを一発で行うには
SELECT
CASE prefecture_name
WHEN '徳島' then '四国'
WHEN '香川' then '四国'
WHEN '愛媛' then '四国'
WHEN '高知' then '四国'
WHEN '福岡' then '九州'
WHEN '佐賀' then '九州'
WHEN '長崎' then '九州'
ELSE 'その他'
END AS district,
sum(population)
FROM prefectures
GROUP BY `district`
と、CASE式を使い、group byでCASE式のエイリアスを指定してやれば可能
これをActiveRecordでやると
Population.select("
case prefecture_name
when '徳島' then '四国'
when '香川' then '四国'
when '愛媛' then '四国'
when '高知' then '四国'
when '福岡' then '九州'
when '佐賀' then '九州'
when '長崎' then '九州'
else 'その他'
end as district,
sum(population) as population
")
.group(:district)
selectの中をゴリゴリ書く必要がある... 🦍
scopeを作ってやればすっきりして可読性は増す、気がする
scope :per_region, -> (){
select("
case prefecture_name
when '徳島' then '四国'
when '香川' then '四国'
when '愛媛' then '四国'
when '高知' then '四国'
when '福岡' then '九州'
when '佐賀' then '九州'
when '長崎' then '九州'
else 'その他' end as district
")
.group(:district)
}
Population.per_region.select("sum(population) as population")
update
updateのset句でもCASEは使用できる
以下の様に、
1️⃣給料が30万以上の社員は、給料を10%減
2️⃣給料が25万以上28万未満の社員は、給料を20%増
という更新をしたい
1️⃣と2️⃣でupdate文を一回ずつ流すと、欲しい結果が得られないので失敗する
1回のupdateで終わらせるには、
set句でCASEを使用すれば可能
UPDATE salaries
SET salary = CASE
WHEN salary >= 300000 THEN salary * 0.9
WHEN salary >= 250000 AND salary < 280000 THEN salary * 1.2
ELSE salary
END;
これをActiveRecordで実行する場合
Salary.update_all("
salary = CASE
WHEN salary >= 300000 THEN salary * 0.9
WHEN salary >= 250000 AND salary < 280000 THEN salary * 1.2
ELSE salary
END;
")
う~ん... そのまんま書き過ぎ? ( ŏㅁŏ;)
効率的なクエリは複雑になるから、
逆にSQLビルダーライブラリでは対応し切れないということなのだろうか?