現代のビジネスシーンにおいて、データは「新たな石油」とも称されるほど価値のある資産となりました。
そのデータを自在に操り、必要な情報を引き出すために欠かせないスキルがSQL (Structured Query Language)です。
マーケティング分析からアプリケーション開発、システム運用に至るまで、SQLは職種を問わず多くのビジネスパーソンに求められる共通言語となっています。
本記事では、実務で頻繁に使用されるSQL命令文を中心に、基礎から応用までを体系的に解説します。
データの抽出、フィルタリング、集計、そして更新といった一連の操作をマスターすることで、膨大なデータ群から価値あるインサイトを導き出せるようになります。
SQLの基本構造とRDBMSの役割
SQLを学ぶ前に、まず理解しておくべきはRDBMS (リレーショナルデータベース管理システム)との関係性です。
MySQL、PostgreSQL、SQL Server、Oracleといった主要なデータベースは、すべて表形式 (テーブル) でデータを管理しており、その操作にSQLを使用します。
SQLの命令文は、大きく分けて以下の3つのカテゴリーに分類されます。
- DML (Data Manipulation Language):データの抽出、挿入、更新、削除を行う命令 (SELECT, INSERT, UPDATE, DELETEなど)
- DDL (Data Definition Language):テーブルやデータベースの構造を定義する命令 (CREATE, ALTER, DROPなど)
- DCL (Data Control Language):権限の設定やトランザクションの制御を行う命令 (GRANT, REVOKE, COMMIT, ROLLBACKなど)
実務において最も触れる機会が多いのは、データの検索や分析を行うためのDML (データ操作言語)です。
まずは、このDMLの基本構文をしっかりと身につけることが、SQLマスターへの第一歩となります。
データ抽出の基本:SELECT文
SQLの基本中の基本であり、最も多用されるのがSELECT文です。
特定のテーブルから必要な列を指定してデータを取り出します。
列の指定と全選択
特定の列だけを取得する場合は列名をコンマ区切りで指定し、すべての列を取得する場合はアスタリスク * を使用します。
-- 指定した列のみを抽出する
SELECT
product_id,
product_name,
price
FROM
products;
product_id | product_name | price
-----------|--------------|-------
1 | 椅子 | 5000
2 | デスク | 15000
3 | ランプ | 3000
実務においては、パフォーマンスの観点から必要な列のみを明示的に指定することが推奨されます。
不要なデータまで取得すると、ネットワーク負荷やメモリ消費が増大する原因となるためです。
重複の除外 (DISTINCT)
特定の列に含まれるユニークな値だけを知りたい場合は、DISTINCTキーワードを使用します。
-- カテゴリの一覧を重複なく取得する
SELECT DISTINCT
category_name
FROM
products;
データの絞り込み:WHERE句
テーブル内のすべてのデータが必要なケースは稀です。
多くの場合、特定の条件に合致するデータのみを抽出します。
その際に使用するのがWHERE句です。
比較演算子と論理演算子
数値の大小比較や文字列の一致確認には比較演算子を使用します。
複数の条件を組み合わせる場合は AND や OR を用います。
-- 価格が5000円以上、かつカテゴリが '家具' の商品を抽出
SELECT
*
FROM
products
WHERE
price >= 5000
AND category = '家具';
主な比較演算子は以下の通りです。
| 演算子 | 意味 |
|---|---|
| = | 等しい |
| <> または != | 等しくない |
| < , > | より小さい、より大きい |
| <= , >= | 以下、以上 |
曖昧検索 (LIKE)
文字列の一部が含まれているデータを検索するには LIKE 演算子とワイルドカード % (0文字以上の任意の文字列) を使用します。
-- 商品名に 'デスク' を含むものを検索 (部分一致)
SELECT
*
FROM
products
WHERE
product_name LIKE '%デスク%';
範囲指定とリスト指定 (BETWEEN, IN)
特定の範囲を指定する場合は BETWEEN、複数の候補値のいずれかに合致するかを確認する場合は IN が便利です。
-- IDが1, 3, 5のいずれか、かつ価格が1000円から5000円の間
SELECT
*
FROM
products
WHERE
id IN (1, 3, 5)
AND price BETWEEN 1000 AND 5000;
データの並び替えと取得件数の制限
抽出結果を見やすく整理したり、上位数件のみを表示したりする操作も実務では頻出します。
ORDER BYによるソート
ORDER BY句を使用すると、指定した列を基準に昇順 (ASC) または降順 (DESC) で並び替えることができます。
デフォルトは昇順です。
-- 価格が高い順に並び替える
SELECT
product_name,
price
FROM
products
ORDER BY
price DESC;
LIMITとOFFSET
大量のデータがある場合、最初の10件だけを表示したい、あるいはページネーションのために21件目から10件取得したいといった場面があります。
-- 価格の高い順にトップ5件を取得
SELECT
product_name,
price
FROM
products
ORDER BY
price DESC
LIMIT 5;
データの集計とグループ化
売上合計や平均価格、ユーザー数など、統計的な数値を算出する際には集計関数とGROUP BY句を組み合わせて使用します。
主要な集計関数
集計関数は、複数の行をまとめて一つの値を返します。
COUNT():行数を数えるSUM():合計値を算出するAVG():平均値を算出するMAX() / MIN():最大値・最小値を求める
GROUP BYによるグループ化
特定のカテゴリごとに集計を行いたい場合に GROUP BY を使用します。
-- カテゴリごとの商品数と平均価格を算出
SELECT
category,
COUNT(*) AS product_count,
AVG(price) AS average_price
FROM
products
GROUP BY
category;
HAVING句による集計後の絞り込み
WHERE句は「集計前」の行に対して条件判定を行いますが、「集計結果」に対して条件を適用したい場合は HAVING 句を使用します。
-- 商品数が10個以上のカテゴリのみを表示
SELECT
category,
COUNT(*) AS product_count
FROM
products
GROUP BY
category
HAVING
COUNT(*) >= 10;
WHEREは集計前、HAVINGは集計後のフィルタリングという違いを明確に理解しておきましょう。
複数テーブルの結合 (JOIN)
リレーショナルデータベースの真骨頂は、複数のテーブルを関連付けて結合することにあります。
実務では一つのテーブルだけですべてが完結することは少なく、IDなどをキーにして情報を紐付けます。
INNER JOIN (内部結合)
両方のテーブルに存在するデータのみを結合して取得します。
-- 注文データに顧客名を紐付ける
SELECT
orders.order_id,
customers.customer_name,
orders.order_date
FROM
orders
INNER JOIN customers
ON orders.customer_id = customers.id;
LEFT JOIN (左外部結合)
左側のテーブル (FROM句に書かれたテーブル) のデータをすべて残し、右側のテーブルに一致するデータがあれば結合します。
一致しない場合は NULL が入ります。
-- すべての顧客と、もしあればその注文履歴を表示
SELECT
customers.customer_name,
orders.order_id
FROM
customers
LEFT JOIN orders
ON customers.id = orders.customer_id;
「一度も注文していない顧客」も含めてリストアップしたい場合に非常に有効な手法です。
サブクエリとCTE (共通テーブル式)
複雑な分析を行うようになると、クエリの結果を別のクエリで利用する必要が出てきます。
サブクエリ (副問い合わせ)
WHERE句やFROM句の中に、別の SELECT 文を記述する方法です。
-- 全商品の平均価格より高い商品のみを抽出
SELECT
product_name,
price
FROM
products
WHERE
price > (SELECT AVG(price) FROM products);
WITH句 (CTE)
サブクエリが深くなると可読性が低下します。
2026年現在のモダンなSQL開発では、WITH句を使用した共通テーブル式 (CTE) を用いるのが一般的です。
一時的な結果セットに名前を付け、後続のクエリで使い回すことができます。
-- 部署ごとの平均給与を算出し、その結果を使ってさらにフィルタリング
WITH DeptAvgSalary AS (
SELECT
dept_id,
AVG(salary) AS avg_sal
FROM
employees
GROUP BY
dept_id
)
SELECT
e.name,
e.salary,
d.avg_sal
FROM
employees e
JOIN DeptAvgSalary d
ON e.dept_id = d.dept_id
WHERE
e.salary > d.avg_sal;
データの更新と管理 (INSERT, UPDATE, DELETE)
参照だけでなく、データの登録や書き換えも重要な操作です。
データの挿入 (INSERT)
新しいレコードをテーブルに追加します。
-- 新規商品を登録
INSERT INTO products (product_name, price, category)
VALUES ('高機能オフィスチェア', 45000, '家具');
データの更新 (UPDATE)
既存のレコードを書き換えます。
ここで最も注意すべき点はWHERE句を忘れないことです。
WHERE句を指定しないと、テーブル内の全データが更新されてしまいます。
-- 特定の商品の価格を改定
UPDATE
products
SET
price = 48000
WHERE
id = 101;
データの削除 (DELETE)
不要になったレコードを削除します。
UPDATE同様、WHERE句の指定が必須と言えるほど重要です。
-- 販売終了した商品を削除
DELETE FROM
products
WHERE
status = 'discontinued';
実務で役立つモダンSQLの機能
近年のデータベースエンジンでは、より高度な分析を簡潔に記述できる機能が追加されています。
ウィンドウ関数
GROUP BYと異なり、行を集約せずに「現在の行の周辺データ」を参照して計算を行う機能です。
ランキングの作成や移動平均の算出に便利です。
-- 商品カテゴリ内での価格順位を表示
SELECT
category,
product_name,
price,
RANK() OVER (PARTITION BY category ORDER BY price DESC) as price_rank
FROM
products;
CASE式による条件分岐
クエリの中で if-then-else のようなロジックを実装できます。
-- 価格帯によってラベルを付与
SELECT
product_name,
CASE
WHEN price >= 10000 THEN '高額'
WHEN price >= 5000 THEN '中額'
ELSE '低額'
END AS price_range
FROM
products;
SQLを書く際のベストプラクティス
効率的でミスのないSQLを書くためには、以下のポイントを意識することが推奨されます。
- インデントと改行を活用する:SQLは記述の自由度が高いですが、予約語 (SELECT, FROMなど) で改行し、ネストを揃えることで可読性が劇的に向上します。
- コメントを記述する:なぜその抽出条件にしたのか、複雑な計算式は何を意味しているのかを
--や/* ... */で残しておきましょう。 - 大文字と小文字の使い分け:SQLの命令文 (予約語) を大文字、テーブル名や列名を小文字に統一すると、視覚的に構造を把握しやすくなります。
- 破壊的な操作の前にSELECTで確認:
UPDATEやDELETEを実行する前に、同じWHERE条件でSELECTを実行し、対象となるデータが正しいかを確認する癖をつけましょう。
まとめ
SQLは、単なるプログラミング言語ではなく、データをビジネスの武器に変えるための「思考ツール」です。
基本となる SELECT, FROM, WHERE の習得から始まり、JOIN によるデータ連携や GROUP BY による集計、さらには WITH 句やウィンドウ関数を活用した高度な分析へとステップアップしていくことが可能です。
本記事で紹介した命令文は、いずれも実務の現場で即座に役立つものばかりです。
まずは手元の環境や練習用のデータセットで実際にクエリを叩き、実行結果を確認しながら構文を身体に馴染ませていきましょう。
正確にデータを抽出・操作できるスキルは、あなたのエンジニア・アナリストとしてのキャリアを強力に支える基盤となるはずです。
