SQL とは
SQL(Structured Query Language)はリレーショナルデータベースを操作するための標準言語です。大きく 3 種類のコマンドがあります。
| 分類 | コマンド | 用途 |
|---|---|---|
| DML | SELECT / INSERT / UPDATE / DELETE | データ操作 |
| DDL | CREATE / ALTER / DROP | テーブル定義 |
| DCL | GRANT / REVOKE | 権限管理 |
SELECT の基本
SELECT 列名1, 列名2
FROM テーブル名
WHERE 条件
ORDER BY 列名 ASC|DESC
LIMIT 件数;
実例:ユーザー一覧
-- 全列取得(開発時のみ。本番では列を明示)
SELECT * FROM users;
-- 特定の列だけ取得
SELECT id, name, email FROM users;
-- 条件で絞り込む
SELECT * FROM users
WHERE created_at >= '2026-01-01'
AND is_active = true;
-- 新しい順に 10 件
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 10;
文字列・数値・日付フィルタ
-- LIKE:部分一致(%は任意の文字列)
SELECT * FROM products WHERE name LIKE '%スマホ%';
-- IN:複数の値のどれかに一致
SELECT * FROM orders WHERE status IN ('pending', 'processing');
-- BETWEEN:範囲
SELECT * FROM sales
WHERE amount BETWEEN 1000 AND 50000;
-- IS NULL / IS NOT NULL
SELECT * FROM users WHERE deleted_at IS NULL;
集計関数と GROUP BY
-- 件数
SELECT COUNT(*) FROM orders;
-- 合計・平均・最大・最小
SELECT
SUM(amount) AS 売上合計,
AVG(amount) AS 平均単価,
MAX(amount) AS 最高額,
MIN(amount) AS 最低額
FROM orders;
-- ユーザーごとの注文数と合計金額
SELECT
user_id,
COUNT(*) AS 注文数,
SUM(amount) AS 合計金額
FROM orders
GROUP BY user_id
ORDER BY 合計金額 DESC;
-- HAVING:GROUP BY 後の絞り込み(WHERE は集計前)
SELECT user_id, COUNT(*) AS cnt
FROM orders
GROUP BY user_id
HAVING COUNT(*) >= 3; -- 3回以上注文したユーザーのみ
JOIN — テーブルの結合
INNER JOIN(内部結合)
両テーブルに存在する行だけを返します。
SELECT
o.id AS 注文ID,
u.name AS 顧客名,
o.amount AS 金額,
o.ordered_at AS 注文日時
FROM orders o
INNER JOIN users u ON o.user_id = u.id
WHERE o.ordered_at >= '2026-04-01';
LEFT JOIN(左外部結合)
左テーブルの全行を返し、右テーブルにマッチしなければ NULL。
-- 注文がないユーザーも含む
SELECT
u.name,
COUNT(o.id) AS 注文数
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id, u.name
ORDER BY 注文数 DESC;
複数テーブルの結合
SELECT
o.id,
u.name AS 顧客,
p.name AS 商品,
oi.quantity AS 数量
FROM orders o
INNER JOIN users u ON u.id = o.user_id
INNER JOIN order_items oi ON oi.order_id = o.id
INNER JOIN products p ON p.id = oi.product_id;
サブクエリ
-- 平均より高い注文を抽出
SELECT * FROM orders
WHERE amount > (SELECT AVG(amount) FROM orders);
-- EXISTS:関連レコードが存在するか
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id
);
ウィンドウ関数(分析関数)
集計しながら元の行を保持できる強力な機能。
-- 各ユーザーの注文を金額降順でランク付け
SELECT
user_id,
id,
amount,
RANK() OVER (PARTITION BY user_id ORDER BY amount DESC) AS rank
FROM orders;
-- 累積合計(売上推移)
SELECT
ordered_at::date AS 日付,
SUM(amount) AS 日次売上,
SUM(SUM(amount)) OVER (ORDER BY ordered_at::date) AS 累積売上
FROM orders
GROUP BY 日付
ORDER BY 日付;
パフォーマンスの基本
-- EXPLAIN ANALYZE でクエリの実行計画を確認
EXPLAIN ANALYZE
SELECT * FROM orders WHERE user_id = 123;
-- Seq Scan(全件スキャン)が出たらインデックス不足の可能性
-- → CREATE INDEX idx_orders_user_id ON orders(user_id);
実務メモ:N+1 問題(ループ内でクエリを実行)は JOIN または IN でまとめて解決する。
まとめ
- SELECT + WHERE + ORDER BY + LIMIT が基本形
- GROUP BY + HAVING で集計・絞り込み
- INNER JOIN は共通レコード、LEFT JOIN は左テーブル全件
- サブクエリとウィンドウ関数で複雑な分析も対応
- EXPLAIN ANALYZE でボトルネックを特定する習慣を