SQL でデータベースからデータを取り出す操作はすべて SELECT 文で行います。シンプルな全件取得から、条件を組み合わせた複雑な抽出まで、SELECT は最も頻繁に使う SQL 文です。
この記事では SELECT 文の基本構文・列の選択方法・WHERE による絞り込みを丁寧に解説するとともに、SQL がどの順番で処理されるか(実行順序)という重要なポイントを図解します。「なぜ WHERE 句で SELECT のエイリアスが使えないのか」など、初学者がつまずきやすい理由もここで理解できます。
SELECT 文の基本構文
SELECT 文の完全な構文は以下の通りです。[ ] で囲まれた部分は省略可能です。
SELECT [DISTINCT] 列1, 列2, ... -- 取得する列を指定 FROM テーブル名 -- データ元のテーブル [JOIN 別テーブル ON 結合条件] -- 複数テーブルの結合(省略可) [WHERE 絞り込み条件] -- 行の絞り込み(省略可) [GROUP BY グループ化する列] -- グループ集計(省略可) [HAVING グループへの条件] -- 集計後の絞り込み(省略可) [ORDER BY ソート列 ASC|DESC] -- 並び替え(省略可) [LIMIT n OFFSET m]; -- 取得件数・開始位置(省略可)
-- サンプルテーブル: employees(従業員テーブル) -- id | name | department | salary | hire_date | manager_id -- ---+------------+------------+--------+------------+----------- -- 1 | 田中 太郎 | 営業 | 55000 | 2020-04-01 | NULL -- 2 | 鈴木 花子 | 開発 | 70000 | 2019-10-01 | 1 -- 3 | 佐藤 一郎 | 営業 | 48000 | 2021-07-01 | 1 -- 4 | 高橋 美咲 | 開発 | 80000 | 2018-01-15 | NULL -- 5 | 伊藤 健二 | 人事 | 52000 | 2022-01-01 | 4 -- 6 | 渡辺 さくら| 開発 | NULL | 2023-04-01 | 4
SELECT で指定できるもの
SELECT の後には列名だけでなく、式・計算・関数・定数・サブクエリなどを指定できます。
-- ① 全列を取得(アスタリスク)
SELECT * FROM employees;
-- ② 特定の列を指定
SELECT name, department, salary FROM employees;
-- ③ 計算式(salary に 1.1 を掛けて 10% 増しの給与を計算)
SELECT name, salary, salary * 1.1 AS salary_after_raise
FROM employees;
-- ④ 文字列の結合
-- MySQL / PostgreSQL:
SELECT CONCAT(name, ' (', department, ')') AS name_dept FROM employees;
-- Oracle / SQL Server:
-- SELECT name || ' (' || department || ')' AS name_dept FROM employees;
-- ⑤ 関数の使用
SELECT name, UPPER(department) AS dept_upper,
LENGTH(name) AS name_len
FROM employees;
-- ⑥ 定数(全行に同じ値を付与)
SELECT name, 'active' AS status FROM employees;
-- ⑦ スカラーサブクエリ(全従業員の平均給与を各行に付与)
SELECT name, salary,
(SELECT AVG(salary) FROM employees) AS avg_salary
FROM employees;
SELECT * は手軽ですが、①テーブルに列が追加されると意図しない列が返るようになる、②必要以上のデータを転送してネットワーク・メモリを無駄にする、③どの列を使っているか明示されないためコードの可読性・保守性が落ちる、という問題があります。本番の SQL では必要な列を明示して指定してください。SQL の実行順序(書く順番 ≠ 処理される順番)
SQL は書いた順番とは異なる順序で処理されます。これを理解していないと「なぜエラーになるのか」が分からず詰まってしまいます。
| 処理順 | 句 | 何をするか |
|---|---|---|
| ① | FROM / JOIN |
どのテーブルからデータを取るかを決める。結合も行う |
| ② | WHERE |
個々の行を条件で絞り込む(集計前) |
| ③ | GROUP BY |
指定した列でグループ化する |
| ④ | HAVING |
グループに対して条件で絞り込む(集計後) |
| ⑤ | SELECT |
取得する列・式を計算してエイリアス名を付ける |
| ⑥ | DISTINCT |
重複行を除去する |
| ⑦ | ORDER BY |
結果を並び替える |
| ⑧ | LIMIT / OFFSET |
取得件数を制限する |
- WHERE でエイリアスが使えない理由: WHERE(②)は SELECT(⑤)より先に処理されるため、エイリアス名がまだ確定していない
- ORDER BY ではエイリアスが使える理由: ORDER BY(⑦)は SELECT(⑤)より後に処理されるため、エイリアス名を参照できる
- WHERE で集計関数(COUNT, SUM 等)が使えない理由: 集計はGROUP BY(③)以降で行われ、WHERE(②)はその前だから
- 集計後の絞り込みは HAVING を使う理由: HAVING(④)は GROUP BY(③)の後のため
-- NG: WHERE でエイリアスを参照しようとするとエラー -- (WHERE はエイリアスが確定する SELECT より先に処理される) SELECT salary * 1.1 AS new_salary FROM employees WHERE new_salary > 60000; -- ERROR: unknown column 'new_salary' -- OK: 元の式を WHERE に書く SELECT salary * 1.1 AS new_salary FROM employees WHERE salary * 1.1 > 60000; -- OK: HAVING を使う(集計後の絞り込み) SELECT department, AVG(salary) AS avg_sal FROM employees GROUP BY department HAVING AVG(salary) > 60000; -- OK: ORDER BY ではエイリアスが使える(SELECT より後に処理されるため) SELECT name, salary * 1.1 AS new_salary FROM employees ORDER BY new_salary DESC; -- エイリアスで並び替えられる
WHERE 句で行を絞り込む
WHERE 句で条件を指定すると、条件を満たす行だけが返ります。複数の条件は AND / OR で組み合わせます。
-- 等しい(=)
SELECT * FROM employees WHERE department = '開発';
-- 等しくない(<> または !=)
SELECT * FROM employees WHERE department <> '営業';
-- 大小比較
SELECT * FROM employees WHERE salary >= 60000;
SELECT * FROM employees WHERE salary < 50000;
-- 範囲(BETWEEN … AND …)
SELECT * FROM employees WHERE salary BETWEEN 50000 AND 70000;
-- リストの中に含まれる(IN)
SELECT * FROM employees WHERE department IN ('営業', '人事');
-- パターンマッチ(LIKE)
SELECT * FROM employees WHERE name LIKE '田%'; -- 「田」で始まる名前
| 演算子 | 意味 | 詳細記事 |
|---|---|---|
= / <> |
等しい / 等しくない | — |
> / < / >= / <= |
大小比較 | — |
BETWEEN A AND B |
A 以上 B 以下の範囲 | IN/BETWEEN完全ガイド |
IN (値1, 値2, ...) |
リストのいずれかと一致 | IN/BETWEEN完全ガイド |
LIKE 'パターン' |
文字列のパターン一致(% と _) | LIKEで部分一致検索 |
IS NULL / IS NOT NULL |
NULL かどうか | NULL以外を抽出する方法 |
NOT IN / NOT LIKE |
否定条件 | 一致しないデータを抽出する方法 |
-- AND: 両方の条件を満たす行 SELECT * FROM employees WHERE department = '開発' AND salary >= 70000; -- OR: どちらかの条件を満たす行 SELECT * FROM employees WHERE department = '営業' OR salary < 50000; -- AND と OR の混在(OR のグループは括弧で囲む) SELECT * FROM employees WHERE (department = '営業' OR department = '人事') AND salary >= 50000;
AND は OR より優先度が高いため、A OR B AND C は A OR (B AND C) と解釈されます。意図した条件にならない場合は括弧 () で明示的にグループ化してください。NULL の検索:IS NULL / IS NOT NULL
NULL は「値が存在しない(不明)」という特別な状態で、通常の比較演算子では比較できません。
-- NG: = NULL は使えない(常に結果が返らない) SELECT * FROM employees WHERE salary = NULL; -- 0件(正しく動作しない) SELECT * FROM employees WHERE manager_id = NULL; -- 0件 -- OK: IS NULL を使う SELECT * FROM employees WHERE salary IS NULL; -- 行6(渡辺) SELECT * FROM employees WHERE manager_id IS NULL; -- 行1(田中)、行4(高橋) -- OK: IS NOT NULL で NULL 以外を取得 SELECT * FROM employees WHERE salary IS NOT NULL;
NULL は「不明な値」を表すため、
NULL = NULL は TRUE ではなく UNKNOWN になります。SQL では WHERE 条件が UNKNOWN の行は結果に含まれません。NULL の比較には専用の IS NULL / IS NOT NULL を使ってください。NULL を含む列での集計や JOIN にも同様の注意が必要です。DISTINCT で重複を除いてユニークな値を取得する
DISTINCT を付けると結果の重複行を除去します。
-- 部門名の一覧(重複なし) SELECT DISTINCT department FROM employees; -- 結果: -- department -- ---------- -- 営業 -- 開発 -- 人事 -- 複数列に DISTINCT を付けた場合(すべての列の組み合わせで重複除去) SELECT DISTINCT department, manager_id FROM employees; -- DISTINCT と COUNT の組み合わせ(種類数のカウント) SELECT COUNT(DISTINCT department) AS dept_count FROM employees; -- 結果: 3
ORDER BY で結果を並び替える
ORDER BY で取得結果を昇順(ASC)または降順(DESC)に並び替えます。ORDER BY を指定しない場合、結果の順序は保証されません。
-- 給与の昇順(低い順) SELECT name, salary FROM employees ORDER BY salary ASC; -- ASC は省略可 -- 給与の降順(高い順) SELECT name, salary FROM employees ORDER BY salary DESC; -- 複数列でのソート(部門名の昇順、同じ部門内では給与の降順) SELECT name, department, salary FROM employees ORDER BY department ASC, salary DESC; -- NULL のソート順(NULL は ASC では最後、DESC では最初になるのがデフォルト) -- MySQL: NULL は最小値として扱われる(ASC では先頭) -- PostgreSQL / Oracle: ASC では最後、DESC では最初(NULLS LAST / NULLS FIRST で制御可) SELECT name, salary FROM employees ORDER BY salary;
NULL の並び順制御(NULLS FIRST / NULLS LAST)、関数でのソート、エイリアスでのソート、RDBMS ごとの違いなどはORDER BY 完全ガイドで解説しています。
LIMIT で取得件数を制限する
大量データの中から先頭 N 件だけ取得したい場合や、ページネーションを実装する場合に LIMIT / OFFSET を使います。
-- 給与上位5人を取得 SELECT name, salary FROM employees ORDER BY salary DESC LIMIT 5; -- 11〜20件目を取得(ページネーション) SELECT name, salary FROM employees ORDER BY id LIMIT 10 OFFSET 10; -- 10件取得、先頭10件をスキップ -- RDBMS ごとの書き方の違い -- MySQL / PostgreSQL / SQLite: LIMIT n OFFSET m -- SQL Server: SELECT TOP n ... / OFFSET m ROWS FETCH NEXT n ROWS ONLY -- Oracle 12c+: FETCH FIRST n ROWS ONLY
OFFSET を使ったページネーション実装・大きな OFFSET のパフォーマンス問題・RDBMS ごとの構文の違いはLIMIT/OFFSET完全ガイドで解説しています。
AS でエイリアス(別名)を付ける
列やテーブルに別名を付けると、SQL が読みやすくなり、計算結果に分かりやすい名前を付けられます。
-- 列にエイリアスを付ける(日本語名も可、ただし引用符が必要な場合がある)
SELECT
name AS 氏名,
department AS 部門,
salary AS 月給,
salary * 12 AS 年収
FROM employees;
-- テーブルにエイリアスを付ける(特に JOIN で有用)
SELECT e.name, e.salary
FROM employees AS e
WHERE e.department = '開発';
-- AS は省略可能(可読性のため付けることを推奨)
SELECT name 氏名, salary 月給
FROM employees e;
JOIN で複数テーブルを結合して抽出する
実務では複数テーブルを結合して SELECT することが頻繁にあります。結合の基本だけ押さえておきましょう。
-- 従業員とそのマネージャー名を結合して取得
-- (自己結合:同じテーブルを2つの別名で使う)
SELECT
e.name AS employee_name,
m.name AS manager_name
FROM employees AS e
LEFT JOIN employees AS m ON e.manager_id = m.id;
-- 結果(manager_id が NULL の行も LEFT JOIN で取得できる):
-- employee_name | manager_name
-- -------------+-------------
-- 田中 太郎 | NULL ← マネージャーなし(LEFT JOIN で残る)
-- 鈴木 花子 | 田中 太郎
-- ...
INNER JOIN・LEFT JOIN・RIGHT JOIN・FULL JOIN の違い、複数テーブルの結合、ON と USING の使い分けはJOIN完全ガイドで解説しています。
実務でよく使う SELECT パターン集
-- 2022年以降に入社した従業員を新しい順に取得 SELECT name, hire_date, department FROM employees WHERE hire_date >= '2022-01-01' ORDER BY hire_date DESC; -- 最近1ヶ月以内のデータを取得(MySQL) SELECT * FROM orders WHERE created_at >= DATE_SUB(NOW(), INTERVAL 1 MONTH); -- PostgreSQL -- WHERE created_at >= NOW() - INTERVAL '1 month'
-- 開発部門で給与が60000以上、または営業部門で給与が50000以上
SELECT name, department, salary
FROM employees
WHERE (department = '開発' AND salary >= 60000)
OR (department = '営業' AND salary >= 50000)
ORDER BY department, salary DESC;
-- 特定の部門を除く全従業員(NOT IN)
SELECT name, department, salary
FROM employees
WHERE department NOT IN ('人事')
ORDER BY salary DESC;
-- salary の NULL を除いた平均(AVG は NULL を自動除外)
SELECT AVG(salary) AS avg_including_null_rows -- salaryがNULLの行は除外して平均
FROM employees;
-- NULL を 0 として扱いたい場合(COALESCE で NULL を置換)
SELECT AVG(COALESCE(salary, 0)) AS avg_treating_null_as_zero
FROM employees;
-- NULL が含まれる列の件数確認
SELECT
COUNT(*) AS total_rows, -- 6
COUNT(salary) AS salary_filled, -- 5(NULL除外)
COUNT(*) - COUNT(salary) AS salary_nulls -- 1
FROM employees;
よくある質問(FAQ)
HAVING COUNT(*) >= 2 のように集計関数が使えます。まとめると:「絞り込みたい条件が個々の行に対するものなら WHERE、集計結果に対するものなら HAVING」です。SELECT * はいつ使っていいですか?IS NULL でしか検索できませんが、空文字は = '' で検索できます。例: WHERE memo IS NULL(NULL 行のみ)と WHERE memo = ''(空文字のみ)は別の結果になります。NULL の詳細な扱いについてはNULL以外のデータを抽出する方法を参照してください。_ci(case-insensitive)なら大文字小文字を区別しません。PostgreSQL は区別するため LOWER(column) = LOWER('検索値') または ILIKE 演算子(LIKE の大文字小文字無視版)を使います。Oracle は UPPER(column) = UPPER('検索値') か、照合順序の設定で制御します。まとめ
| やりたいこと | 書き方・ポイント |
|---|---|
| 全行・全列を取得 | SELECT * FROM テーブル(本番では列名を明示) |
| 特定列だけ取得 | SELECT 列1, 列2 FROM テーブル |
| 条件で絞り込む | WHERE 条件(AND / OR / IN / BETWEEN / LIKE) |
| NULL を検索する | WHERE 列 IS NULL(= NULL は使えない) |
| 重複を除いて取得 | SELECT DISTINCT 列名 |
| 並び替え | ORDER BY 列名 ASC|DESC |
| 件数を制限 | LIMIT n(RDBMS により構文が異なる) |
| 別名を付ける | 列名 AS エイリアス名 |
| 集計後に絞り込む | GROUP BY ... HAVING 条件(WHERE ではなく HAVING を使う) |
| SQLの実行順序 | FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY→LIMIT |
各条件演算子の詳細についてはIN/BETWEEN/EXISTS完全ガイド・LIKEで部分一致検索する方法・LIMIT/OFFSET完全ガイドもあわせてご覧ください。データの重複を除く方法はDISTINCTで重複データを削除する方法で詳しく解説しています。

