はじめに
データベースを扱う上で最も頻繁に使用するのが、データを取り出す操作です。PostgreSQLでは、SELECT文を使ってテーブルに保存されたデータを自由自在に抽出できます。
本記事では、PostgreSQL 16におけるSELECT文の基本から応用まで、実践的な例を交えながら丁寧に解説します。データベース初心者の方でも、この記事を読み終える頃には、業務で使える実用的なデータ抽出スキルが身につくでしょう。
この記事で分かること
この記事を読むことで、以下のスキルを習得できます。
- SELECT文の基本構文と使い方
- 特定の列だけを取り出す方法
- WHERE句を使った条件指定によるデータ絞り込み
- ORDER BY句を使ったデータの並び替え
- LIMIT句を使った取得件数の制限
- 複数の条件を組み合わせた高度な検索方法
- 実務で役立つSELECT文の応用テクニック
稼働環境
本記事の操作は、以下の環境で動作確認を行っています。
- OS: Windows Server 2025(64bit)
- データベース: PostgreSQL16
- 接続ツール: psql(PostgreSQL標準コマンドラインツール)
※他のOSやPostgreSQLのバージョンでも基本的な操作は同じですが、一部の機能や表示が異なる場合があります。
サンプルテーブルの準備
実際にSELECT文を試すため、まずサンプルデータを含むテーブルを作成しましょう。以下のSQL文を実行してください。
-- 社員テーブルの作成
CREATE TABLE employees (
employee_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
department VARCHAR(50),
salary INTEGER,
hire_date DATE
);
-- サンプルデータの挿入
INSERT INTO employees (name, department, salary, hire_date) VALUES
('山田太郎', '営業部', 350000, '2020-04-01'),
('佐藤花子', '開発部', 420000, '2019-07-15'),
('鈴木一郎', '営業部', 380000, '2021-01-10'),
('田中美咲', '人事部', 320000, '2022-03-01'),
('高橋健太', '開発部', 450000, '2018-10-20'),
('伊藤真由美', '営業部', 360000, '2020-08-15'),
('渡辺拓也', '開発部', 400000, '2021-06-01');このコマンドを実行すると、7名の社員情報を持つテーブルが作成されます。
SELECT文の基本構文
PostgreSQLにおけるSELECT文の基本構文は次の通りです。
SELECT 列名1, 列名2, ...
FROM テーブル名
WHERE 条件
ORDER BY 並び替えの基準
LIMIT 取得件数;それぞれの要素について、順番に詳しく見ていきましょう。
全データの取得
最もシンプルなSELECT文は、テーブルの全データを取得する方法です。アスタリスク(*)を使うことで、すべての列を一度に取得できます。
SELECT * FROM employees;このクエリを実行すると、employeesテーブルに保存されているすべての社員データが表示されます。開発段階でテーブルの内容を確認したいときに便利な方法です。
特定の列だけを取得
実際の業務では、すべての列が必要とは限りません。必要な列だけを指定して取得することで、データ転送量を削減し、処理速度を向上させられます。
SELECT name, department FROM employees;このクエリでは、社員名と所属部署の2列だけを取得します。複数の列を指定する場合は、カンマで区切って記述します。
WHERE句による条件指定
WHERE句を使うと、特定の条件に合致するデータだけを抽出できます。これはデータベース操作の中でも特に重要な機能です。
等価条件での絞り込み
特定の値と一致するデータを取得する例です。
SELECT * FROM employees
WHERE department = '開発部';このクエリは、開発部に所属する社員だけを抽出します。文字列を条件に使う場合は、シングルクォーテーションで囲む必要があります。
比較演算子を使った条件
数値データに対しては、大小比較を使った条件指定が可能です。
SELECT name, salary FROM employees
WHERE salary >= 400000;この例では、給与が40万円以上の社員を抽出しています。PostgreSQLで使える主な比較演算子は以下の通りです。
=: 等しい<>または!=: 等しくない>: より大きい<: より小さい>=: 以上<=: 以下
複数条件の組み合わせ(AND)
複数の条件をすべて満たすデータを取得するには、ANDを使います。
SELECT * FROM employees
WHERE department = '営業部'
AND salary > 350000;このクエリは、営業部に所属し、かつ給与が35万円を超える社員を抽出します。ANDで結んだ条件は、すべてを同時に満たす必要があります。
複数条件の組み合わせ(OR)
いずれかの条件を満たすデータを取得するには、ORを使います。
SELECT * FROM employees
WHERE department = '開発部'
OR salary >= 400000;このクエリは、開発部に所属しているか、または給与が40万円以上の社員を抽出します。ORで結んだ条件は、どちらか一方を満たせば該当します。
日付条件での絞り込み
日付型のデータに対しても条件を指定できます。
SELECT name, hire_date FROM employees
WHERE hire_date >= '2020-01-01';この例では、2020年1月1日以降に入社した社員を抽出しています。日付もシングルクォーテーションで囲んで指定します。
LIKE演算子によるあいまい検索
完全一致ではなく、部分的な一致でデータを検索したい場合は、LIKE演算子を使用します。
SELECT * FROM employees
WHERE name LIKE '%田%';この例では、名前に「田」という文字を含む社員を検索します。パーセント記号(%)は任意の文字列を表すワイルドカードです。
'田%': 「田」で始まる'%田': 「田」で終わる'%田%': 「田」を含む
また、アンダースコア(_)を使うと、任意の1文字を表現できます。
SELECT * FROM employees
WHERE name LIKE '___太郎';このクエリは、「〇〇〇太郎」のように、太郎の前に3文字がある名前を検索します。
IN演算子による複数値の指定
複数の値のいずれかに一致するデータを取得する場合、IN演算子が便利です。
SELECT * FROM employees
WHERE department IN ('営業部', '開発部');この例では、営業部または開発部に所属する社員を抽出します。ORを何度も書くよりも、コードが読みやすくなります。
BETWEEN演算子による範囲指定
数値や日付の範囲を指定する場合は、BETWEEN演算子が使えます。
SELECT name, salary FROM employees
WHERE salary BETWEEN 350000 AND 400000;このクエリは、給与が35万円以上40万円以下の社員を抽出します。BETWEENは境界値を含む点に注意してください。
NULL値の扱い
データベースでは、値が存在しないことを表すNULLという特殊な値があります。NULLかどうかを判定するには、専用の演算子を使います。
-- NULLのデータを検索
SELECT * FROM employees
WHERE department IS NULL;
-- NULLでないデータを検索
SELECT * FROM employees
WHERE department IS NOT NULL;通常の比較演算子(=や<>)はNULLに対して使えないため、必ずIS NULLまたはIS NOT NULLを使用してください。
ORDER BY句によるデータの並び替え
取得したデータを特定の順序で並び替えるには、ORDER BY句を使用します。
昇順での並び替え
SELECT * FROM employees
ORDER BY salary;この例では、給与の低い順(昇順)に社員データを表示します。デフォルトは昇順(ASC)なので、ASCキーワードは省略可能です。
降順での並び替え
SELECT * FROM employees
ORDER BY salary DESC;DESCキーワードを追加することで、給与の高い順(降順)に並び替えられます。
複数列での並び替え
SELECT * FROM employees
ORDER BY department, salary DESC;この例では、まず部署名で昇順に並び替え、同じ部署内では給与の高い順に並び替えます。カンマで区切って複数の並び替え条件を指定できます。
LIMIT句による取得件数の制限
大量のデータから上位数件だけを取得したい場合、LIMIT句を使用します。
SELECT * FROM employees
ORDER BY salary DESC
LIMIT 3;このクエリは、給与が高い順に上位3名の社員データを取得します。ページネーション機能を実装する際にも、LIMITは非常に重要な役割を果たします。
OFFSET句と組み合わせたページング処理
OFFSETを使うと、指定した件数分だけデータをスキップできます。
SELECT * FROM employees
ORDER BY employee_id
LIMIT 3 OFFSET 3;この例では、最初の3件をスキップして、4件目から6件目までを取得します。Webアプリケーションで「次のページ」機能を実装する際に活用できます。
DISTINCT句による重複行の除外
重複したデータを除いて、一意な値だけを取得したい場合はDISTINCTを使います。
SELECT DISTINCT department FROM employees;このクエリは、社員テーブルに存在する部署名を重複なく一覧表示します。同じ部署に複数の社員がいても、部署名は1回だけ表示されます。
集計関数との組み合わせ
SELECT文では、データを集計する関数も使用できます。
-- 社員数のカウント
SELECT COUNT(*) FROM employees;
-- 平均給与の計算
SELECT AVG(salary) FROM employees;
-- 最高給与の取得
SELECT MAX(salary) FROM employees;
-- 最低給与の取得
SELECT MIN(salary) FROM employees;
-- 給与の合計
SELECT SUM(salary) FROM employees;これらの集計関数は、データ分析やレポート作成で頻繁に使用されます。
GROUP BY句によるグループ化
特定の列でデータをグループ化し、グループごとに集計を行うことができます。
SELECT department, COUNT(*), AVG(salary)
FROM employees
GROUP BY department;このクエリは、部署ごとの社員数と平均給与を計算します。GROUP BYを使う際は、SELECT句に指定する列は、GROUP BYで指定した列か集計関数のいずれかである必要があります。
HAVING句によるグループの絞り込み
GROUP BYで作成したグループに対して条件を適用するには、HAVING句を使います。
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) >= 380000;この例では、平均給与が38万円以上の部署だけを表示します。WHERE句は個別の行に対する条件、HAVING句はグループに対する条件という違いがあります。
実践的なSELECT文の例
ここまで学んだ知識を組み合わせた、より実践的な例を見てみましょう。
SELECT
department,
COUNT(*) AS employee_count,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
MIN(salary) AS min_salary
FROM employees
WHERE hire_date >= '2020-01-01'
GROUP BY department
HAVING COUNT(*) >= 2
ORDER BY avg_salary DESC;このクエリは以下の処理を行います。
- 2020年以降に入社した社員に絞り込み
- 部署ごとにグループ化
- 各部署で2名以上の社員がいる部署のみ抽出
- 部署ごとの人数、平均給与、最高給与、最低給与を計算
- 平均給与の高い順に並び替え
AS句を使って列に別名(エイリアス)を付けることで、結果がより分かりやすくなります。
つまずきポイントと解決策
PostgreSQLのSELECT文を使う際、初心者がよく遭遇するエラーと解決方法を紹介します。
エラー1: 列名の指定ミス
エラーメッセージ: column "列名" does not exist
原因: 存在しない列名を指定している、または列名のスペルミスがあります。
解決策: テーブル定義を確認し、正確な列名を使用してください。PostgreSQLは大文字小文字を区別することがあるので注意が必要です。
-- テーブルの列名を確認
\\d employeesエラー2: 文字列の引用符忘れ
エラーメッセージ: syntax error at or near "営業部"
原因: 文字列値をシングルクォーテーションで囲んでいません。
解決策: 文字列は必ずシングルクォーテーションで囲みます。
-- 誤り
SELECT * FROM employees WHERE department = 営業部;
-- 正しい
SELECT * FROM employees WHERE department = '営業部';エラー3: GROUP BYでのエラー
エラーメッセージ: column "列名" must appear in the GROUP BY clause or be used in an aggregate function
原因: GROUP BY句を使用する際、SELECT句に指定した列がGROUP BYに含まれていないか、集計関数でラップされていません。
解決策: SELECT句の列は、GROUP BYに含めるか、集計関数を使用してください。
-- 誤り
SELECT name, department, AVG(salary)
FROM employees
GROUP BY department;
-- 正しい(nameを削除)
SELECT department, AVG(salary)
FROM employees
GROUP BY department;
-- または正しい(nameをGROUP BYに追加)
SELECT name, department, AVG(salary)
FROM employees
GROUP BY department, name;エラー4: NULLの比較ミス
エラーメッセージ: 特にエラーは出ませんが、期待したデータが取得できません。
原因: NULL値に対して通常の比較演算子を使用しています。
解決策: NULLの判定には必ずIS NULLまたはIS NOT NULLを使用します。
-- 誤り(データが取得できない)
SELECT * FROM employees WHERE department = NULL;
-- 正しい
SELECT * FROM employees WHERE department IS NULL;エラー5: ORDER BYの位置ミス
エラーメッセージ: syntax error at or near "ORDER"
原因: ORDER BY句をWHERE句の前に書いてしまっています。
解決策: SQL文の句の順序を守ってください。正しい順序は、SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMITです。
-- 誤り
SELECT * FROM employees ORDER BY salary WHERE department = '営業部';
-- 正しい
SELECT * FROM employees WHERE department = '営業部' ORDER BY salary;パフォーマンス向上のヒント
大量のデータを扱う場合、SELECT文の書き方によって処理速度が大きく変わります。
必要な列だけを指定する
-- 遅い(すべての列を取得)
SELECT * FROM large_table;
-- 速い(必要な列だけ取得)
SELECT id, name FROM large_table;アスタリスク(*)は開発時の確認には便利ですが、本番環境では必要な列だけを明示的に指定しましょう。
WHERE句で早期に絞り込む
-- データを絞り込んでから処理
SELECT department, AVG(salary)
FROM employees
WHERE hire_date >= '2020-01-01'
GROUP BY department;可能な限り早い段階でデータ量を減らすことで、後続の処理が高速になります。
インデックスを活用する
頻繁に検索条件に使う列にはインデックスを作成することで、検索速度が劇的に向上します。
-- departmentにインデックスを作成
CREATE INDEX idx_department ON employees(department);インデックスについては、シリーズの別記事で詳しく解説する予定です。
よくある質問(FAQ)
Q1: SELECTとSELECT ALLの違いは何ですか?
PostgreSQLでは、SELECTとSELECT ALLは同じ動作をします。ALLキーワードは省略可能で、デフォルトでALLが適用されます。重複行を除外したい場合は、SELECT DISTINCTを使用してください。
Q2: 大文字小文字は区別されますか?
SQLのキーワード(SELECT、FROM、WHEREなど)は大文字小文字を区別しません。ただし、テーブル名や列名を二重引用符で囲んだ場合は区別されます。また、文字列データの比較では大文字小文字が区別されます。大文字小文字を区別せずに検索したい場合は、ILIKEを使用するか、LOWER関数で統一してから比較してください。
Q3: 複数のテーブルからデータを取得するにはどうすればよいですか?
複数のテーブルからデータを取得するには、JOIN句を使用します。JOINについては、このシリーズの次回以降の記事で詳しく解説します。基本的な例を示すと次のようになります。
SELECT e.name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;Q4: 計算結果に基づいて並び替えることはできますか?
はい、可能です。ORDER BY句では、計算式や集計関数の結果に基づいて並び替えできます。
SELECT name, salary, salary * 12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC;Q5: 同じ値を持つ行が複数ある場合、どの順序で返されますか?
ORDER BY句を指定しない場合、PostgreSQLはデータベース内部の物理的な格納順序でデータを返しますが、この順序は保証されません。特定の順序が必要な場合は、必ずORDER BY句を使用してください。また、ORDER BYで指定した列に同じ値がある場合、その中での順序は不定です。完全に順序を制御したい場合は、複数の列を指定してください。
まとめ
本記事では、PostgreSQL 16におけるSELECT文の基本から応用まで、幅広く解説しました。重要なポイントをまとめます。
SELECT文はデータベース操作の基本であり、最も頻繁に使用するSQL文です。基本的な全件取得から始まり、WHERE句による条件指定、ORDER BY句での並び替え、LIMIT句での件数制限など、段階的に学習することで確実にスキルアップできます。
実務では、これらの要素を組み合わせて複雑なクエリを作成します。GROUP BYやHAVING句を使った集計処理は、データ分析やレポート作成に不可欠なスキルです。また、パフォーマンスを意識したSQL文の書き方も重要になります。
まずは基本的なSELECT文から始めて、少しずつ複雑な条件や機能を追加していくことで、実践的なデータベーススキルが身につきます。サンプルデータを使って、本記事で紹介した様々なパターンを実際に試してみてください。