SQLはデータベースを操作するための言語で、エンジニア・データアナリスト・データサイエンティストを問わず必須のスキルです。本記事では、SQLの基礎から実践的なデータ分析、パフォーマンス最適化まで体系的に解説します。
SQLとは?なぜ学ぶべきか
SQL(Structured Query Language)はリレーショナルデータベースを操作するための標準言語です。MySQL、PostgreSQL、SQLite、Microsoft SQL Server、Oracle Databaseなど、主要なデータベースシステムすべてでSQLが使われています。
2026年現在、データドリブンな経営が一般化し、SQLは「エンジニアだけのスキル」から「ビジネスパーソン全般に求められるスキル」になっています。実際、Google、Amazon、Metaなどの大企業では、データアナリストの採用要件にSQLが必須項目として含まれています。
SQLの基礎文法:SELECT文をマスターしよう
基本的なSELECT文
-- 全列を取得
SELECT * FROM users;
-- 特定の列を指定
SELECT id, name, email, created_at
FROM users;
-- 条件でフィルタリング
SELECT name, email
FROM users
WHERE age >= 18 AND is_active = true;
-- 結果を並べ替え
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 10;
集計関数(GROUP BY)
-- カテゴリー別の売上集計
SELECT
category,
COUNT(*) AS product_count,
SUM(price) AS total_revenue,
AVG(price) AS avg_price,
MAX(price) AS max_price,
MIN(price) AS min_price
FROM products
GROUP BY category
HAVING COUNT(*) >= 5
ORDER BY total_revenue DESC;
JOIN:複数テーブルを結合する
-- INNER JOIN:両方のテーブルに存在するデータのみ
SELECT
o.id AS order_id,
u.name AS customer_name,
p.name AS product_name,
o.quantity,
o.total_price
FROM orders o
INNER JOIN users u ON o.user_id = u.id
INNER JOIN products p ON o.product_id = p.id
WHERE o.status = 'completed'
ORDER BY o.created_at DESC;
-- LEFT JOIN:左テーブルの全データ + 右テーブルのマッチデータ
SELECT
u.name,
COUNT(o.id) AS order_count,
COALESCE(SUM(o.total_price), 0) AS total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
ORDER BY total_spent DESC;
サブクエリとCTE(Common Table Expression)
-- サブクエリ
SELECT name, salary
FROM employees
WHERE salary > (
SELECT AVG(salary) FROM employees
);
-- CTE(より読みやすい書き方)
WITH avg_salary AS (
SELECT department, AVG(salary) AS dept_avg
FROM employees
GROUP BY department
),
high_earners AS (
SELECT e.name, e.salary, a.dept_avg
FROM employees e
JOIN avg_salary a ON e.department = a.department
WHERE e.salary > a.dept_avg * 1.2
)
SELECT * FROM high_earners
ORDER BY salary DESC;
ウィンドウ関数:高度なデータ分析
-- ROW_NUMBER:行番号の割り当て
SELECT
name,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept
FROM employees;
-- LAG/LEAD:前後の行の値を参照
SELECT
date,
revenue,
LAG(revenue, 1) OVER (ORDER BY date) AS prev_revenue,
revenue - LAG(revenue, 1) OVER (ORDER BY date) AS revenue_change,
ROUND(
(revenue - LAG(revenue, 1) OVER (ORDER BY date)) * 100.0 /
LAG(revenue, 1) OVER (ORDER BY date), 2
) AS growth_rate
FROM daily_sales
ORDER BY date;
-- 累積合計
SELECT
date,
revenue,
SUM(revenue) OVER (ORDER BY date) AS cumulative_revenue
FROM daily_sales;
SQLパフォーマンス最適化
インデックスの活用
-- インデックスを作成
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- 複合インデックスの活用例
SELECT * FROM orders
WHERE user_id = 123
AND created_at >= '2026-01-01';
-- ↑ idx_orders_user_date が効果的に使われる
-- EXPLAIN ANALYZEでクエリの実行計画を確認
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id;
クエリ最適化のベストプラクティス
- SELECT * は避ける:必要な列のみ指定してネットワーク転送量を削減
- WHERE句を活用:できるだけ早い段階でレコードを絞り込む
- JOINの順序を最適化:小さいテーブルを先に結合する
- インデックスを適切に設定:WHERE・JOIN・ORDER BYで使う列にインデックスを張る
- N+1問題を避ける:ループ内でクエリを実行しない
実践:データ分析でよく使うSQLパターン
-- コホート分析(月次リテンション)
WITH first_purchase AS (
SELECT user_id, DATE_TRUNC('month', MIN(created_at)) AS cohort_month
FROM orders
GROUP BY user_id
),
monthly_activity AS (
SELECT
fp.user_id,
fp.cohort_month,
DATE_TRUNC('month', o.created_at) AS activity_month
FROM first_purchase fp
JOIN orders o ON fp.user_id = o.user_id
GROUP BY fp.user_id, fp.cohort_month, DATE_TRUNC('month', o.created_at)
)
SELECT
cohort_month,
EXTRACT(MONTH FROM AGE(activity_month, cohort_month)) AS months_since_first,
COUNT(DISTINCT user_id) AS active_users
FROM monthly_activity
GROUP BY cohort_month, months_since_first
ORDER BY cohort_month, months_since_first;
まとめ:SQLを習得してデータを武器にしよう
SQLは一度習得すれば長期にわたって活用できるスキルです。基本的なSELECT文から始まり、JOINやサブクエリ、ウィンドウ関数まで段階的に習得することで、複雑なデータ分析も自在に行えるようになります。実際のデータセット(Kaggle、公開データなど)を使って手を動かしながら学ぶことが、最も効果的な上達の近道です。