背景
お気に入り数/フォロー数など、ユーザーマイページで使う
ユーザーIDに紐づく集計されたデータ件数をSQLで取得したい場面がありました。
今回、テーブル構成がユーザーIDに対して
お気に入りレシピ (1:n)
とレシピ (1:n)
となっており、
それぞれが持つ集計カラムのグルーピングが必要になったため、その取得例を記載します。
取得したいデータ
対象:Aさんがお気に入りに登録しているレシピ
条件:調理時間を5分以内 / 10分 / 15分 / 20分 / 25分 / 30分 / 31分以上~ の区分として集計
※以内・以上について、データには細かい刻みも存在する(1分,4分,60分,120分など)
テーブルA (お気に入りレシピ)
誰が何のレシピをお気に入りしているかの情報。
user_id
単位でグルーピングして集計したい。
id | user_id | recipe_id | delete_flag | ... |
---|---|---|---|---|
1 | 51 | 10000 | 0 | |
2 | 54 | 10001 | 0 | |
3 | 51 | 10002 | 0 | |
4 | 51 | 10003 | 0 | |
5 | 54 | 10004 | 0 |
テーブルB (レシピ)
各レシピの情報。
調理時間(cook_time)
をグルーピングさせて集計したい。
テーブルAとはid
=A.recipe_id
で結合
id | title | cook_time | delete_flag | ... |
---|---|---|---|---|
10000 | hoge焼き | 5 | 0 | |
10001 | fuga麺 | 10 | 0 | |
10002 | piyo巻き | 15 | 0 | |
10003 | foo和え | 15 | 0 | |
10004 | barおろし | 10 | 0 |
GroupByの場合
SELECT
recipes.cook_time Recipe__cook_time,
count(*)
FROM
recipe_cooks, recipes
WHERE
recipe_cooks.recipe_id = recipes.id
AND recipes.delete_flag = 0
AND recipe_cooks.delete_flag = 0
AND recipe_cooks.user_id = ?
GROUP BY recipes.cook_time
ORDER BY recipes.cook_time ASC
とれた!でもこれじゃない・・・
このままだと再度、5分以内・31分以上の集計をさせないといけなくなる。
結果
case文で条件を当てる形で取得できました。
SELECT
sum(case when recipes.cook_time <= 5 then 1 else 0 end) as "5分以下",
sum(case when recipes.cook_time = 10 then 1 else 0 end)as "10分",
sum(case when recipes.cook_time = 15 then 1 else 0 end)as "15分",
sum(case when recipes.cook_time = 20 then 1 else 0 end)as "20分",
sum(case when recipes.cook_time = 30 then 1 else 0 end)as "30分",
sum(case when recipes.cook_time >= 31 then 1 else 0 end)as "31分以上"
FROM recipe_cooks, recipes
WHERE
recipe_cooks.recipe_id = recipes.id
AND recipes.delete_flag = 0
AND recipe_cooks.delete_flag = 0
AND recipe_cooks.user_id = ?
case文で範囲指定して真なら(+1)する形で集計が取れた。
ただカラム名にStringが入るため、取り扱い時に注意が必要。