SQL実践:データ集計と複雑なクエリの最適化パターン

複数値のフィルタリング(IN句の活用)

特定のカラムに対して複数の値を指定してフィルタリングを行う際、IN演算子を使用することでクエリを簡潔に記述できます。

SELECT user_id, gender, age, school, gpa 
FROM user_accounts 
WHERE school IN ('北京大学', '復旦大学', '山東大学');

集計関数を用いたフィルタリング(HAVING句)

WHERE句では集計関数(AVG, COUNTなど)の結果に基づいてレコードを絞り込むことはできません。その場合はGROUP BYの後にHAVING句を使用します。

SELECT school, 
       ROUND(AVG(post_count), 3) AS avg_posts, 
       ROUND(AVG(answer_count), 3) AS avg_answers
FROM user_accounts
GROUP BY school
HAVING AVG(post_count) < 5 OR AVG(answer_count) < 20;

複数テーブルの結合と平均値の算出

複数のテーブルを結合して、ユーザー1人あたりの平均回答数を算出する場合、重複を除去したユーザーID(DISTINCT)で除算する必要があります。

SELECT u.school, 
       COUNT(p.question_id) / COUNT(DISTINCT p.user_id) AS avg_per_user
FROM practice_logs AS p
INNER JOIN user_accounts AS u ON p.user_id = u.user_id
GROUP BY u.school;

難易度別の集計(3テーブル結合)

ユーザー情報、演習ログ、問題詳細の3つのテーブルを結合し、学校および難易度ごとの平均回答数を集計する例です。

SELECT u.school, 
       q.difficulty,
       ROUND(COUNT(p.question_id) / COUNT(DISTINCT p.user_id), 4) AS avg_answers
FROM practice_logs AS p
LEFT JOIN user_accounts AS u ON u.user_id = p.user_id
LEFT JOIN question_info AS q ON q.question_id = p.question_id
GROUP BY u.school, q.difficulty;

結果の統合(UNION ALL)

異なる条件の結果を重複を排除せずにマージする場合は、UNION ALLを使用します。

SELECT user_id, gender, age, gpa
FROM user_accounts
WHERE school = '山東大学'
UNION ALL
SELECT user_id, gender, age, gpa
FROM user_accounts
WHERE gender = 'male';

CASE式による条件分岐とグルーピング

年齢層などの特定のセグメントを作成するには、CASE WHEN構文を利用します。

SELECT 
    CASE 
        WHEN age < 25 OR age IS NULL THEN '25歳未満'
        ELSE '25歳以上'
    END AS age_segment,
    COUNT(user_id) AS total_users
FROM user_accounts
GROUP BY age_segment;

日付関数を利用した時系列集計

日付型データから「日」の部分だけを取り出すには、DAY()関数を使用します。

SELECT DAY(action_date) AS day_of_month, 
       COUNT(question_id) AS daily_total
FROM practice_logs
WHERE action_date LIKE '2021-08%'
GROUP BY action_date;

文字列の分割と抽出(SUBSTRING_INDEX)

カンマ区切りの文字列から特定のデータ(例:年齢)を抽出する場合、MySQLではSUBSTRING_INDEXを組み合わせて使用します。

SELECT 
    SUBSTRING_INDEX(SUBSTRING_INDEX(profile_info, ',', 3), ',', -1) AS extracted_age,
    COUNT(user_id) AS count
FROM user_submissions
GROUP BY extracted_age;

サブクエリを用いたグループ内最小値の取得

各学校でGPAが最も低い学生を抽出する場合、サブクエリで各学校の最小GPAを取得し、それをメインクエリの条件(WHERE IN)に渡します。

SELECT user_id, school, gpa
FROM user_accounts
WHERE (school, gpa) IN (
    SELECT school, MIN(gpa) 
    FROM user_accounts 
    GROUP BY school
)
ORDER BY school;

条件付き集計と正解率の計算

特定の期間内に、特定の大学のユーザーが回答した問題の正解率を算出します。IF関数とAVGを組み合わせることで効率的に計算可能です。

SELECT q.difficulty,
       AVG(IF(p.result = 'right', 1, 0)) AS correct_rate
FROM user_accounts AS u
INNER JOIN practice_logs AS p ON u.user_id = p.user_id
INNER JOIN question_info AS q ON q.question_id = p.question_id
WHERE u.school = '浙江大学'
GROUP BY q.difficulty
ORDER BY correct_rate ASC;

タグ: MySQL SQL DataAggregation Subquery JOIN

8月6日 09:34 投稿