SQLを学ぶとき、最初に触れることが多いのが SELECT 文です。

SELECT は、データベースからデータを取得するための基本構文です。
しかし実務では、単に「テーブルの中身を表示する」だけではありません。

条件で絞り込む、並び替える、集計する、複数テーブルを結合する、重複を除外する、ランキングを作るなど、SELECT には多くの使い方があります。

この記事では、SQLの SELECT 文について、基本から応用までサンプルデータを使いながら解説します。

MySQL、PostgreSQL、SQLite、SQL Serverなど主要なデータベースでも SELECT は共通して使われます。ただし、細かい構文にはデータベースごとの差があります。MySQL公式では、SELECT は1つ以上のテーブルから行を取得する文として説明されており、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT などの句を組み合わせて使用できます。

この記事でわかること

この記事では、以下の内容を解説します。

  • SELECT 文の基本構文
  • 特定の列だけを取得する方法
  • WHERE による条件指定
  • ORDER BY による並び替え
  • LIMIT / OFFSET による件数制限
  • DISTINCT による重複除外
  • GROUP BY による集計
  • HAVING による集計結果の絞り込み
  • JOIN による複数テーブルの結合
  • CASE による条件分岐
  • COALESCE によるNULL対策
  • サブクエリの使い方
  • EXISTS の使い方
  • UNION / UNION ALL の使い方

C#.NETとSQL Server LocalDBで実践をしてみたい方は以下を参考にしてください。
※テーブルデータは以下を参考にしてください。

SELECT文の基本構文

SELECT文の基本形は以下です。

SELECT 列名
FROM テーブル名;

たとえば、usersテーブルからユーザー名を取得する場合は、次のように書きます。

SELECT user_name
FROM users;

複数の列を取得する場合は、カンマで区切ります。

SELECT user_id, user_name, prefecture
FROM users;

すべての列を取得したい場合は 「*」 を使います。

SELECT *
FROM users;

ただし、実務では SELECT * の多用はおすすめしません。

理由は、不要な列まで取得してしまい、処理が重くなったり、後から列が追加されたときに予期しない影響が出たりするためです。基本的には、必要な列だけを明示して取得する方が安全です。

WHEREで条件を指定する

WHEREを使うと、条件に一致する行だけを取得できます。

SELECT user_id, user_name, prefecture
FROM users
WHERE prefecture = 'Tokyo';

このSQLでは、都道府県が Tokyo のユーザーだけを取得します。

比較演算子

WHERE では、以下のような比較演算子を使えます。

演算子意味
=等しい
<>等しくない
>より大きい
<より小さい
>=以上
<=以下

例えば以下のように使用します。
これは価格が10,000円以上の商品を取得します。

SELECT product_name, price
FROM products
WHERE price >= 10000;

AND / ORで複数条件を指定する

複数条件を指定する場合は、ANDOR を使います。

これは、都道府県が Tokyo かつステータスが active のユーザーを取得します。

SELECT user_name, prefecture, status
FROM users
WHERE prefecture = 'Tokyo'
  AND status = 'active';

OR を使うと、どちらかに一致する条件になります。

SELECT user_name, prefecture
FROM users
WHERE prefecture = 'Tokyo'
   OR prefecture = 'Osaka';

条件が増える場合は、カッコを使うと読みやすくなります。

SELECT user_name, prefecture, status
FROM users
WHERE status = 'active'
AND (prefecture = 'Tokyo' OR prefecture = 'Osaka');

INで複数候補を指定する

OR が多くなる場合は、IN を使うとすっきり書けます。

SELECT user_name, prefecture
FROM users
WHERE prefecture IN ('Tokyo', 'Osaka', 'Fukuoka');

これは、以下と同じ意味です。

SELECT user_name, prefecture
FROM users
WHERE prefecture = 'Tokyo'
OR prefecture = 'Osaka'
OR prefecture = 'Fukuoka'

BETWEENで範囲を指定する

BETWEEN は範囲指定に使います。

価格が3,000円以上15,000円以下の商品を取得します。

SELECT product_name, price
FROM products
WHERE price BETWEEN 3000 AND 15000;

日付にも使えます。

SELECT order_id, order_date
FROM orders
WHERE order_date BETWEEN '2025-04-01' AND '2025-04-15';

LIKEで部分一致検索をする

文字列の一部を検索したい場合は LIKE を使います。

SELECT product_name
FROM products
WHERE product_name LIKE '%phone%';

%」 は任意の文字列を表します。

ORDER BYで並び替える

ORDER BY を使うと、取得結果を並び替えできます。

SELECT product_name, price
FROM products
ORDER BY price ASC;

※ASCは昇順、DESCは降順です。

複数条件で並び替えることもできます。

SELECT product_name, price
FROM products
ORDER BY price DESC, product_id ASC;

ORDER BY を指定しない場合、結果の順番は保証されません。PostgreSQL公式でも、ORDER BY がない場合の行順は明確に保証されないものとして説明されています。

LIMIT / OFFSETで取得件数を制限する

取得件数を制限したい場合は LIMIT を使います。

SELECT product_name, price
FROM products
ORDER BY price DESC
LIMIT 3;

価格が高い順に3件だけ取得します。

OFFSET を使うと、指定した件数をスキップできます。

SELECT order_id, order_date
FROM orders
ORDER BY order_date ASC
LIMIT 2 OFFSET 1;

これは、先頭1件をスキップして、次の2件を取得します。

DISTINCTで重複を除外する

DISTINCT を使うと、重複した値を除外できます。

SELECT DISTINCT prefecture
FROM users;

結果は以下のようになります。

prefecture
Tokyo
Osaka
Fukuoka
Hokkaido

Tokyo は複数ユーザーに存在しますが、DISTINCT によって1回だけ表示されます。

COUNTで件数を数える

COUNT は件数を数える集計関数です。

SELECT COUNT(*) AS user_count
FROM users;

結果は以下のようになります。

user_count
5

条件を付けて数えることもできます。

SELECT COUNT(*) AS active_user_count
FROM users
WHERE status = 'active';

SUMで合計を求める

SUM は合計を求める関数です。

SELECT SUM(quantity * unit_price) AS total_sales
FROM order_items;

注文詳細全体の売上合計を取得します。

AVGで平均を求める

AVG は平均を求める関数です。

SELECT AVG(price) AS average_price
FROM products;

PostgreSQL公式では、avg はNULLを除いた入力値の平均を計算する集計関数として説明されています。

MIN / MAXで最小値・最大値を取得する

MIN は最小値、MAX は最大値を求める関数です。

SELECT
MIN(price) AS min_price,
MAX(price) AS max_price
FROM products;

結果は以下のようになります。

min_pricemax_price
1800120000

GROUP BYでグループごとに集計する

GROUP BY を使うと、グループ単位で集計できます。

たとえば、都道府県ごとのユーザー数を取得します。

SELECT prefecture, COUNT(*) AS user_count
FROM users
GROUP BY prefecture;

結果は以下のようになります。

prefectureuser_count
Tokyo2
Osaka1
Fukuoka1
Hokkaido1

HAVINGで集計結果を絞り込む

WHERE集計前の行を絞り込むために使います。
一方、HAVING集計後の結果を絞り込むために使います。

SELECT 
user_name,
SUM(quantity * unit_price) AS total_sales
FROM users
JOIN orders
JOIN user_id = user_id
JOIN order_items
JOIN order_id = order_id
GROUP BY user_name
HAVING SUM(quantity * unit_price) >= 50000;

結果は以下のようになります。

user_nametotal_sales
Aki146400
Dai138000

JOINで複数テーブルを結合する

JOIN を使うと、複数のテーブルを関連付けて取得できます。

INNER JOIN

INNER JOIN は、両方のテーブルで一致するデータだけを取得します。

SELECT 
order_id,
user_name,
order_date
FROM orders
INNER JOIN users
JOIN user_id = user_id;

結果は以下のようになります。

order_iduser_nameorder_date
1001Aki2025-04-01
1002Aki2025-04-15
1003Bora2025-04-03
1004Bora2025-04-20
1005Dai2025-04-25

LEFT JOIN

LEFT JOIN は、左側のテーブルをすべて残し、右側に一致するデータがあれば結合します。

SELECT 
ser_name,
order_id
FROM users
LEFT JOIN orders
JOIN user_id = user_id
ORDER BY user_id;

結果は以下のようになります。

user_nameorder_id
Aki1001
Aki1002
Bora1003
Bora1004
ChinNULL
Dai1005
EmaNULL

注文していない Chin や Ema も表示されます。

PostgreSQL公式では、LEFT OUTER JOIN は左側の行を残し、一致しない右側の列にはNULLを入れる結合として説明されています。

CASEで条件分岐する

CASE を使うと、SQLの中で条件分岐できます。

SELECT 
  order_id,
  status,
  CASE
    WHEN status = 'paid' THEN '支払い済み'
    WHEN status = 'shipped' THEN '発送済み'
    WHEN status = 'cancelled' THEN 'キャンセル'
    ELSE 'その他'
  END AS status_label
FROM orders;

結果は以下のようになります。

order_idstatusstatus_label
1001paid支払い済み
1002shipped発送済み
1003paid支払い済み
1004cancelledキャンセル
1005paid支払い済み

SQL Server公式でも、CASE は条件リストを評価して結果式の1つを返す構文として説明されています。

COALESCEでNULLを別の値に置き換える

COALESCE は、NULLの場合に別の値を返したいときに使います。

SELECT 
  order_id,
  COALESCE(coupon_code, 'クーポンなし') AS coupon_label
FROM orders;

結果は以下のようになります。

order_idcoupon_label
1001SPRING10
1002クーポンなし
1003クーポンなし
1004クーポンなし
1005VIP

NULLをそのまま表示したくない帳票や一覧画面で便利です。

サブクエリを使う

サブクエリとは、SQLの中に書く別のSQLです。

たとえば、平均価格より高い商品を取得します。

SELECT product_name, price
FROM products
WHERE price > (
  SELECT AVG(price)
  FROM products
);

このSQLでは、まず内側のSQLで平均価格を求め、その平均価格より高い商品だけを取得します。

EXISTSを使う

EXISTS は、サブクエリの結果が存在するかどうかを判定します。

注文したことがあるユーザーを取得する例です。

SELECT user_name
FROM users
WHERE EXISTS (
  SELECT 1
  FROM orders
  WHERE user_id = user_id
);

結果は以下のようになります。

user_name
Aki
Bora
Dai

注文したことがないユーザーを取得する場合は NOT EXISTS を使います。

SELECT u.user_name
FROM users
WHERE NOT EXISTS (
  SELECT 1
  FROM orders
  WHERE user_id = user_id
);

結果は以下のようになります。

user_name
Chin
Ema

UNIONで結果を結合する

UNION は、複数のSELECT結果を縦に結合します。

SELECT status
FROM users
UNION
SELECT status
FROM orders;

※UNIONは重複を除外します。

重複を残したい場合は UNION ALL を使います。

SELECT status
FROM users
UNION ALL
SELECT status
FROM orders;

実務では、重複除外が不要なら UNION ALL の方が意図が明確です。

まとめ

SELECT 文は、SQLの中でも最も基本的で、最もよく使う構文です。
最初は以下の形だけ覚えれば問題ありません。

実務で特に重要なのは、次の4つです。

  1. 必要な列だけ取得する
  2. 条件は WHERE に正しく書く
  3. 集計後の条件は HAVING に書く
  4. 複数テーブルを扱うときは JOIN の意味を理解する

SELECT は単なるデータ取得文ではありません。
データを「どう見せるか」「どう集計するか」「どう活用するか」を決める、SQLの中心となる構文です。