SQL基礎完全入門!初心者でもわかるデータベース操作とデータ分析の始め方

近年のビジネスではデータ活用への注目度が高まり、より重要視されるようになってきていますが、データ活用に欠かせないのがSQL(データベース言語)です。

「SQLって何ができるの?」「プログラミング初心者でも学習できる?」「どこから始めればいい?」

こうした疑問を抱く方は多いでしょう。しかし、SQLはプログラミング初心者にとって最も習得しやすい言語の一つなのです。

**SQLを習得すれば、膨大なデータから必要な情報を自由自在に取り出せるようになります。**これは、データ分析やビジネス課題解決において非常に強力なスキルとなります。

本記事では、SQL完全初心者向けに、基本概念から実践的なデータ分析まで、段階的かつ実例を交えて詳しく解説します。SQLについてこれから学び始める方、もう少し深く知りたいという方はぜひご覧ください。

目次

SQLとは何か?

SQLの基本概念

SQL(Structured Query Language)は、データベースに対してデータの検索、追加、更新、削除を行うための専門言語です。「データベースとの会話」をするための言語と考えると理解しやすいでしょう。

SQLは1970年代にIBMによって開発され、現在ではISO(国際標準化機構)によって標準化されています。このため、一度SQLを覚えれば、さまざまなデータベースで利用できる汎用性の高いスキルとなります。

データベースとは

そもそもデータベースとは何なのか確認してみましょう。データベースとは、**特定の情報を集め使いやすい形に整理した「情報のかたまり」**のことです。

身近な例として、以下のようなものがあります:

日常生活でのデータベース例

  • 図書館の蔵書管理システム:本のタイトル、著者、出版年、貸出状況などを管理
  • 銀行の口座管理システム:口座番号、残高、取引履歴などを管理
  • ECサイトの商品管理システム:商品名、価格、在庫数、販売実績などを管理

データベースを利用してデータを管理するメリットは、主に次の3点があります:

  1. 膨大なデータをまとめて管理できる
  2. 目的に応じてかんたんにデータを探せる
  3. かんたんに編集して使える

コンピューター上のデータベースは、何百万件~何千万件という大量のデータも瞬時に整理できるのが最大のメリットです。

SQLでできること

SQLでは、大きくわけると次の4つの操作ができます:

  1. データの検索
  2. データの追加
  3. データの更新
  4. データの削除

さらに詳しく見ていきましょう。

4つの基本操作(CRUD)

1. Create(作成) – データの追加

-- 新しい顧客情報を追加
INSERT INTO customers (name, email, registration_date) 
VALUES ('田中太郎', 'tanaka@example.com', '2024-01-15');

2. Read(読み取り) – データの検索・取得

-- 特定の条件でデータを検索
SELECT name, email FROM customers 
WHERE registration_date >= '2024-01-01';

3. Update(更新) – 既存データの変更

-- 顧客のメールアドレスを更新
UPDATE customers 
SET email = 'new_email@example.com' 
WHERE name = '田中太郎';

4. Delete(削除) – データの削除

-- 特定の顧客データを削除
DELETE FROM customers 
WHERE registration_date < '2023-01-01';

テーブルの結合

SQLでは、異なるテーブルを結合して1つのテーブルを作成することもできます。たとえば、「注文テーブル」と「商品テーブル」を結合して、商品情報が追記された注文テーブルを作成することが可能です。テーブルを結合することで、各データが見やすくなったり、効率的にテーブルを読み込ませることができます。

データ分析での活用例

SQLは単純なデータ操作だけでなく、高度なデータ分析にも活用できます。たとえば、ECサイトの売上データを分析する場合、以下のようなクエリで包括的な分析が可能です:

売上分析の例

-- 月別売上推移の分析
SELECT 
    DATE_FORMAT(order_date, '%Y-%m') as month,
    COUNT(*) as order_count,
    SUM(amount) as total_sales,
    AVG(amount) as average_order_value
FROM orders 
WHERE order_date >= '2024-01-01'
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY month;

この一つのクエリで、注文件数、総売上、平均注文金額という重要な指標を月別で集計できます。これまでExcelで何時間もかかっていた分析が、SQLなら数秒で完了します。このような効率化により、データ分析の精度向上と意思決定の迅速化が実現できるのです。

SQLの3つの種類

SQLは用途に応じて、大きく3つの種類に分類されます。これらの分類を理解することで、SQL学習の全体像を把握できます:

1. DML(Data Manipulation Language)- データ操作言語

データベースに対してデータを追加・更新・削除などを行うためのSQL命令文です。日常的な業務で最も使用頻度が高く、データ分析や業務システムの核となる機能です。

主な命令

  • SELECT:データの検索・取得
  • INSERT:データの追加
  • UPDATE:データの更新
  • DELETE:データの削除

例えば、顧客データベースから特定の条件で顧客を検索する場合、SELECT文を使用します。これにより、数百万件のデータからも瞬時に必要な情報を取得できます。

2. DDL(Data Definition Language)- データ定義言語

テーブルなどを作成・削除したり、設定を変更したりするためのSQL命令文です。データベースの構造を定義する重要な役割を担います。

主な命令

  • CREATE:テーブル・データベースの作成
  • ALTER:テーブル構造の変更
  • DROP:テーブル・データベースの削除
  • TRUNCATE:テーブル内全データの削除

システム開発の初期段階や、データベース設計の変更時に主に使用されます。

3. DCL(Data Control Language)- データ制御言語

データベースのアクセス権限を管理し、データの整合性を保つためのSQL命令文です。セキュリティとデータの一貫性を確保する重要な機能を提供します。

主な命令

  • GRANT:権限付与
  • REVOKE:権限剥奪
  • COMMIT:処理の確定
  • ROLLBACK:処理の取り消し

特に大規模なシステムでは、複数のユーザーが同時にデータベースにアクセスするため、DCLによる制御が不可欠です。

学習の進め方:初心者の方は、まずDMLから学習することをおすすめします。DMLを習得すれば、データの検索・分析といった実用的な作業がすぐに行えるようになります。

SQL学習の準備

学習環境の構築

推奨学習環境

SQL学習を始めるには、実際にデータベースを操作できる環境が必要です。初心者に最もおすすめの環境は以下の通りです:

1. SQLiteブラウザ(最も簡単)

  • インストール不要でブラウザ上で動作
  • 推奨サイト:SQLiteTutorial.net、W3Schools SQL Tryit Editor
  • 特徴:すぐに始められる、サンプルデータが豊富

2. SQLite + DB Browser for SQLite(中級者向け)

  • 軽量でインストールが簡単
  • ファイルベースのデータベース
  • 個人学習に最適

3. MySQL + phpMyAdmin(実践向け)

  • 実際の企業で多く使われている
  • より本格的なデータベース管理システム
  • 将来的な実務活用を見据えた学習

SQLで操作できる代表的なデータベース

主要なデータベースの特徴は次のとおりです:

データベース名価格特徴
MySQL無料(商用利用は有償)オープンソース、シンプルで高速
PostgreSQL無料オープンソース、機能豊富で大規模対応
Oracle Database有償国内で圧倒的なシェアを誇る
SQL Server有償Microsoft製品との連携が強い

無料であれば「MySQL」か「PostgreSQL」のいずれかを選べば間違いありません。MySQLはシンプルな設計で処理速度も早く、PostgreSQLは機能が豊富で大規模なデータベースを扱いやすい特徴があります。

サンプルデータベースの活用

学習には、現実的なデータ構造を持つサンプルデータベースを使用することが重要です。以下のようなサンプルデータベースが学習に適しています:

Northwindデータベース(推奨)

  • Microsoft社が提供する商業データベース
  • 顧客、商品、注文などの関連テーブル
  • ビジネス分析の練習に最適
-- Northwindデータベースの構造例
-- customers(顧客テーブル)
-- orders(注文テーブル)
-- products(商品テーブル)
-- order_details(注文詳細テーブル)
-- employees(従業員テーブル)

予期しないトラブルと「トランザクション制御」

データベースに処理をおこなう際、データ量が多いほど処理に時間がかかります。処理中に予期しないトラブルはつきもので、電源トラブルでパソコンが落ちたり、別のスタッフが異なる処理を実行してしまったりすることがあります。データベースの処理が途中で終了や上書きされると、データの中身がおかしくなってしまいます。

トランザクション制御の重要性

そこで有効なのは「トランザクション制御」という補助機能です。トランザクション制御はSQLに備わる機能であり、処理途中であってもすべての処理をキャンセルし、もとに戻すことができます。

主要なトランザクション制御コマンド

  • COMMIT: データの変更を確定させる
  • ROLLBACK: データの変更をキャンセルして元に戻す
-- トランザクション制御の例
BEGIN TRANSACTION;
UPDATE EMPLOYEE SET SAL = 550000 WHERE NAME = '田中';
-- 処理に問題があった場合
ROLLBACK;  -- 変更を取り消す
-- 処理が正常に完了した場合
COMMIT;    -- 変更を確定する

なお、更新が完了するとデータの復元はできなくなるので、処理をおこなう際は事前にバックアップをとるようにしましょう。

SQLの基本構文ルール

文法の基本原則

SQLを学習する上で理解しておくべき基本的な文法ルールがあります:

1. 大文字・小文字の区別

-- SQLキーワードは大文字でも小文字でもOK
SELECT NAME FROM EMPLOYEE;
select name from employee;  -- 同じ意味

2. セミコロンの使用

-- 文の終わりにはセミコロンを付ける
SELECT * FROM EMPLOYEE;

3. コメントの書き方

-- 単行コメント
SELECT NAME,  /* 複数行
                 コメント */ JOB
FROM EMPLOYEE;

4. 文字列の指定

-- 文字列はシングルクォートで囲む
SELECT * FROM EMPLOYEE WHERE NAME = '田中太郎';

これらのルールを理解しておくことで、エラーの原因を特定しやすくなり、学習がスムーズに進みます。

基本的なSELECT文

データの取得基礎

最もシンプルなSELECT文

SQLの学習は、データを取得するSELECT文から始めるのが一般的です。SELECT文はSQLの中でも最も使用頻度が高く、データ分析の基本となる重要な機能です。

基本的な構文

  SELECT  列名1,列名2,列名3(どの列を検索・表示させるか)
  FROM  表名(どの表から検索するか)
  WHERE  抽出条件

実例で学ぶSELECT文
社員管理システムを例に、EMPLOYEE表(NAME(氏名)、AGE(年齢)、JOB(仕事)、SAL(月給)から構成)を使って実際にSQLを実行してみましょう。

-- テーブルのすべてのデータを取得
SELECT * FROM EMPLOYEE;

この文は「EMPLOYEEテーブルのすべての列(*)のすべての行を表示してください」という意味です。*(アスタリスク)は「すべての列」を表す記号です。

特定の列だけを取得

実際の業務では、必要な列だけを取得することがほとんどです:

-- 氏名と月給だけを取得
SELECT NAME, SAL FROM EMPLOYEE;

複数列を指定する場合の注意点

  • 列名はカンマ(,)で区切る
  • 最後の列名の後にはカンマを付けない
  • 列の順序は自由に指定できる
-- 列の順序を変更した例
SELECT SAL, NAME, JOB FROM EMPLOYEE;

条件を指定した検索(WHERE句)

WHERE句を使用することで、特定の条件に一致するデータだけを抽出できます。これがSQLの真の力を発揮する部分です。

実践問題:表の中から、月給が50万円以上の人を探してみましょう。

-- 月給が50万円以上の社員を検索
SELECT * FROM EMPLOYEE
WHERE SAL >= 500000;

実行結果

NAMEAGEJOBSAL
松田65社長950,000
山田43部長680,000
羽生42営業マネージャ600,000

このように、数千件・数万件のデータからでも、条件に一致するデータを瞬時に抽出できます。

列に別名を付ける(AS句)

分析結果を分かりやすくするために、列に別名(エイリアス)を付けることができます:

-- 列に日本語の別名を付ける
SELECT
    NAME AS 氏名,
    SAL AS 月給,
    JOB AS 職種
FROM EMPLOYEE;

AS句の活用例

-- 計算結果に分かりやすい名前を付ける
SELECT
    product_name AS 商品名,
    price AS 単価,
    price * 1.1 AS 税込価格
FROM products;

WHERE句による条件指定

基本的な条件指定

実際のデータ分析では、すべてのデータではなく、特定の条件を満たすデータだけを取得することがほとんどです。WHERE句を使って条件を指定します。

-- 特定の顧客のデータだけを取得
SELECT * FROM customers
WHERE name = '田中太郎';

-- 特定の日付以降の注文データを取得
SELECT * FROM orders
WHERE order_date >= '2024-01-01';

-- 特定の価格以上の商品を取得
SELECT product_name, price FROM products
WHERE price >= 1000;

比較演算子の使い方

SQLでは様々な比較演算子を使って条件を指定できます:

演算子意味使用例
=等しいprice = 1000
!= または <>等しくないstatus != 'inactive'
>より大きいage > 25
>=以上salary >= 300000
<より小さいquantity < 10
<=以下discount <= 0.1

実践例

-- 2024年1月の注文で、金額が10000円以上のデータ
SELECT order_id, customer_name, amount, order_date
FROM orders
WHERE order_date >= '2024-01-01'
  AND order_date < '2024-02-01'
  AND amount >= 10000;

複数条件の組み合わせ

実際のビジネス分析では、複数の条件を組み合わせることが多くあります:

AND条件(すべての条件を満たす)

-- 2024年に登録された、東京都在住の顧客
SELECT name, email, address, registration_date
FROM customers
WHERE registration_date >= '2024-01-01'
  AND address LIKE '%東京都%';

OR条件(いずれかの条件を満たす)

-- 東京都または大阪府在住の顧客
SELECT name, address
FROM customers
WHERE address LIKE '%東京都%'
   OR address LIKE '%大阪府%';

複雑な条件の組み合わせ

-- 高額商品(10000円以上)または割引商品(discount > 0)で、
-- かつ在庫が10個以上ある商品
SELECT product_name, price, discount, stock_quantity
FROM products
WHERE (price >= 10000 OR discount > 0)
  AND stock_quantity >= 10;

LIKE演算子による部分一致検索

基本的なパターンマッチング

LIKE演算子を使うと、文字列の部分一致検索ができます。これは実際のデータ分析で非常によく使われる機能です:

ワイルドカード文字

  • %:0文字以上の任意の文字列
  • _:1文字の任意の文字
-- 名前が「田中」で始まる顧客
SELECT * FROM customers
WHERE name LIKE '田中%';

-- メールアドレスがGmailの顧客
SELECT name, email FROM customers
WHERE email LIKE '%@gmail.com';

-- 商品名に「iPhone」が含まれる商品
SELECT product_name, price FROM products
WHERE product_name LIKE '%iPhone%';

-- 電話番号が「03」で始まる(東京の市外局番)顧客
SELECT name, phone FROM customers
WHERE phone LIKE '03%';

実践的なLIKE演算子の活用

顧客セグメンテーション分析

-- 法人顧客の抽出(社名に「株式会社」「有限会社」が含まれる)
SELECT customer_id, company_name, contact_person
FROM customers
WHERE company_name LIKE '%株式会社%'
   OR company_name LIKE '%有限会社%'
   OR company_name LIKE '%合同会社%';

商品カテゴリ分析

-- IT関連商品の売上分析
SELECT
    product_name,
    SUM(quantity * unit_price) AS total_sales
FROM order_details od
JOIN products p ON od.product_id = p.product_id
WHERE p.product_name LIKE '%PC%'
   OR p.product_name LIKE '%パソコン%'
   OR p.product_name LIKE '%コンピュータ%'
GROUP BY product_name
ORDER BY total_sales DESC;

データの並び替えと制限

ORDER BY句による並び替え

基本的な並び替え

データを分析する際、結果を特定の順序で表示することは非常に重要です。ORDER BY句を使ってデータを並び替えることができます。

-- 顧客を名前の昇順(アルファベット順)で並び替え
SELECT name, email, registration_date
FROM customers 
ORDER BY name;

-- 商品を価格の降順(高い順)で並び替え
SELECT product_name, price
FROM products 
ORDER BY price DESC;

-- 注文を日付の降順(新しい順)で並び替え
SELECT order_id, customer_name, order_date, amount
FROM orders 
ORDER BY order_date DESC;

並び替えの方向

  • ASC:昇順(小さい順、古い順)※省略可能
  • DESC:降順(大きい順、新しい順)

複数列による並び替え

実際のビジネス分析では、複数の基準で並び替えることがよくあります:

-- まず都道府県で並び替え、同じ都道府県内では市区町村で並び替え
SELECT name, prefecture, city, registration_date
FROM customers 
ORDER BY prefecture, city;

-- まず注文日で並び替え、同じ日の注文は金額の降順で並び替え
SELECT order_date, customer_name, amount
FROM orders 
ORDER BY order_date DESC, amount DESC;

複数列並び替えの実践例

-- 売上分析:まず売上高の降順、売上高が同じ場合は商品名の昇順
SELECT 
    product_name,
    SUM(quantity * unit_price) AS total_sales,
    COUNT(*) AS order_count
FROM order_details od
JOIN products p ON od.product_id = p.product_id
GROUP BY product_name
ORDER BY total_sales DESC, product_name ASC;

LIMIT句による結果の制限

上位N件の取得

大量のデータから上位や下位の一部だけを取得したい場合、LIMIT句を使用します:

-- 売上上位10商品
SELECT product_name, price
FROM products 
ORDER BY price DESC
LIMIT 10;

-- 最新の注文5件
SELECT order_id, customer_name, order_date, amount
FROM orders 
ORDER BY order_date DESC
LIMIT 5;

OFFSET句と組み合わせたページネーション

Webアプリケーションでよく使われる「ページング」機能を実現できます:

-- 11番目から20番目の商品(2ページ目を表示)
SELECT product_name, price
FROM products 
ORDER BY product_name
LIMIT 10 OFFSET 10;

-- 21番目から30番目の顧客(3ページ目を表示)
SELECT name, email, registration_date
FROM customers 
ORDER BY registration_date DESC
LIMIT 10 OFFSET 20;

実践的な活用例

-- 売上上位3商品の詳細分析
SELECT 
    p.product_name,
    p.price,
    SUM(od.quantity) AS total_quantity_sold,
    SUM(od.quantity * od.unit_price) AS total_revenue,
    COUNT(DISTINCT od.order_id) AS number_of_orders
FROM products p
JOIN order_details od ON p.product_id = od.product_id
GROUP BY p.product_id, p.product_name, p.price
ORDER BY total_revenue DESC
LIMIT 3;

集計関数とGROUP BY

基本的な集計関数

主要な集計関数

集計関数は、複数の行のデータから一つの値を計算する関数です。データ分析において最も重要な機能の一つです。

5つの基本集計関数

-- COUNT: 行数をカウント
SELECT COUNT(*) AS 総顧客数 FROM customers;
SELECT COUNT(email) AS メールアドレス登録済み顧客数 FROM customers;

-- SUM: 合計値を計算
SELECT SUM(amount) AS 総売上 FROM orders;

-- AVG: 平均値を計算
SELECT AVG(price) AS 平均価格 FROM products;

-- MAX: 最大値を取得
SELECT MAX(order_date) AS 最新注文日 FROM orders;

-- MIN: 最小値を取得
SELECT MIN(price) AS 最安価格 FROM products;

実践的な集計分析

売上分析の例

-- 2024年の売上概要
SELECT
    COUNT(*) AS 注文件数,
    SUM(amount) AS 総売上,
    AVG(amount) AS 平均注文金額,
    MAX(amount) AS 最高注文金額,
    MIN(amount) AS 最低注文金額
FROM orders
WHERE order_date >= '2024-01-01'
  AND order_date < '2025-01-01';

商品分析の例

-- 商品価格の分布分析
SELECT
    COUNT(*) AS 商品数,
    AVG(price) AS 平均価格,
    MAX(price) AS 最高価格,
    MIN(price) AS 最低価格,
    MAX(price) - MIN(price) AS 価格レンジ
FROM products;

GROUP BYによるグループ化

基本的なグループ化

GROUP BY句を使うと、特定の列の値ごとにデータをグループ化して集計できます。これは「セグメント分析」の基本となる重要な機能です。

-- 都道府県別の顧客数
SELECT
    prefecture AS 都道府県,
    COUNT(*) AS 顧客数
FROM customers
GROUP BY prefecture
ORDER BY 顧客数 DESC;

-- 月別の売上集計
SELECT
    DATE_FORMAT(order_date, '%Y-%m') AS 年月,
    COUNT(*) AS 注文件数,
    SUM(amount) AS 売上合計
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 年月;

複数列でのグループ化

より詳細な分析のため、複数の列でグループ化することもできます:

-- 都道府県・市区町村別の顧客分布
SELECT
    prefecture AS 都道府県,
    city AS 市区町村,
    COUNT(*) AS 顧客数
FROM customers
GROUP BY prefecture, city
ORDER BY prefecture, 顧客数 DESC;

-- 年月・商品カテゴリ別の売上分析
SELECT
    DATE_FORMAT(o.order_date, '%Y-%m') AS 年月,
    p.category AS カテゴリ,
    COUNT(*) AS 注文件数,
    SUM(od.quantity * od.unit_price) AS 売上
FROM orders o
JOIN order_details od ON o.order_id = od.order_id
JOIN products p ON od.product_id = p.product_id
GROUP BY DATE_FORMAT(o.order_date, '%Y-%m'), p.category
ORDER BY 年月, 売上 DESC;

HAVING句による集計結果の絞り込み

WHEREとHAVINGの違い

  • WHERE:グループ化する前の行を絞り込む
  • HAVING:グループ化した後の結果を絞り込む
-- 売上が100万円以上の月だけを表示
SELECT
    DATE_FORMAT(order_date, '%Y-%m') AS 年月,
    SUM(amount) AS 月間売上
FROM orders
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
HAVING SUM(amount) >= 1000000
ORDER BY 年月;

-- 顧客数が50人以上の都道府県だけを表示
SELECT
    prefecture AS 都道府県,
    COUNT(*) AS 顧客数
FROM customers
GROUP BY prefecture
HAVING COUNT(*) >= 50
ORDER BY 顧客数 DESC;

実践的なHAVING句の活用

優良顧客の特定

-- 年間購入金額が10万円以上の優良顧客
SELECT
    customer_id,
    customer_name,
    COUNT(*) AS 年間注文回数,
    SUM(amount) AS 年間購入金額,
    AVG(amount) AS 平均注文金額
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY customer_id, customer_name
HAVING SUM(amount) >= 100000
ORDER BY 年間購入金額 DESC;

人気商品の分析

-- 月間販売数が100個以上の人気商品
SELECT
    p.product_name AS 商品名,
    SUM(od.quantity) AS 月間販売数,
    SUM(od.quantity * od.unit_price) AS 月間売上
FROM order_details od
JOIN products p ON od.product_id = p.product_id
JOIN orders o ON od.order_id = o.order_id
WHERE o.order_date >= '2024-01-01'
  AND o.order_date < '2024-02-01'
GROUP BY p.product_id, p.product_name
HAVING SUM(od.quantity) >= 100
ORDER BY 月間販売数 DESC;

複数テーブルの結合(JOIN)

JOINの基本概念

なぜJOINが必要なのか

実際のデータベースでは、効率的なデータ管理のため、関連する情報を複数のテーブルに分けて保存します。例えば:

  • customersテーブル:顧客の基本情報(名前、住所、電話番号)
  • ordersテーブル:注文情報(注文日、金額、顧客ID)
  • productsテーブル:商品情報(商品名、価格、カテゴリ)

これらのテーブルを組み合わせることで、「どの顧客が、いつ、何を購入したか」という包括的な分析が可能になります。

リレーションシップの理解

テーブル間の関係性を理解することがJOINの鍵となります:

-- テーブル構造の例
-- customers テーブル
-- customer_id (主キー) | name     | email
-- 1                    | 田中太郎  | tanaka@example.com
-- 2                    | 佐藤花子  | sato@example.com

-- orders テーブル  
-- order_id (主キー) | customer_id (外部キー) | order_date | amount
-- 101              | 1                      | 2024-01-15 | 15000
-- 102              | 2                      | 2024-01-16 | 25000

INNER JOINの活用

基本的なINNER JOIN

INNER JOINは、両方のテーブルに一致するデータがある行のみを取得します:

-- 顧客名と注文情報を組み合わせて表示
SELECT 
    c.name AS 顧客名,
    o.order_date AS 注文日,
    o.amount AS 金額
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
ORDER BY o.order_date DESC;

INNER JOINの特徴

  • 両方のテーブルに一致するデータがある場合のみ結果に含まれる
  • 注文履歴がない顧客は結果に表示されない
  • 最も一般的に使用されるJOIN

3つ以上のテーブルの結合

実際のビジネス分析では、複数のテーブルを組み合わせることが一般的です:

-- 顧客名、商品名、注文詳細を組み合わせた包括的な売上分析
SELECT 
    c.name AS 顧客名,
    p.product_name AS 商品名,
    od.quantity AS 数量,
    od.unit_price AS 単価,
    od.quantity * od.unit_price AS 小計,
    o.order_date AS 注文日
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN order_details od ON o.order_id = od.order_id
INNER JOIN products p ON od.product_id = p.product_id
WHERE o.order_date >= '2024-01-01'
ORDER BY o.order_date DESC, c.name;

LEFT JOINの活用

INNER JOINとLEFT JOINの違い

LEFT JOINは、左側のテーブル(FROMで指定したテーブル)のすべての行を取得し、右側のテーブルに一致するデータがない場合はNULLで表示します:

-- すべての顧客を表示し、注文履歴がある場合は注文情報も表示
SELECT 
    c.name AS 顧客名,
    c.registration_date AS 登録日,
    COUNT(o.order_id) AS 注文回数,
    COALESCE(SUM(o.amount), 0) AS 総購入金額
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name, c.registration_date
ORDER BY 総購入金額 DESC;

非アクティブ顧客の分析

LEFT JOINは、「データがない」ことを分析する際に非常に有用です:

-- 2024年に注文履歴がない顧客(非アクティブ顧客)の特定
SELECT 
    c.customer_id,
    c.name AS 顧客名,
    c.registration_date AS 登録日,
    c.email AS メールアドレス
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id 
                   AND o.order_date >= '2024-01-01'
WHERE o.order_id IS NULL
ORDER BY c.registration_date;

活用場面

  • 休眠顧客の特定
  • 商品を購入していない顧客の分析
  • リテンション分析(顧客維持率の分析)

実践的なデータ分析例

売上分析

月別売上トレンド分析

実際のビジネスでよく行われる分析を、SQLで実装してみましょう:

-- 月別売上トレンドと前年同月比
SELECT 
    DATE_FORMAT(order_date, '%Y-%m') AS 年月,
    COUNT(*) AS 注文件数,
    SUM(amount) AS 売上金額,
    AVG(amount) AS 平均注文金額,
    -- 前月比の計算(簡易版)
    LAG(SUM(amount)) OVER (ORDER BY DATE_FORMAT(order_date, '%Y-%m')) AS 前月売上,
    ROUND(
        (SUM(amount) - LAG(SUM(amount)) OVER (ORDER BY DATE_FORMAT(order_date, '%Y-%m'))) 
        / LAG(SUM(amount)) OVER (ORDER BY DATE_FORMAT(order_date, '%Y-%m')) * 100, 
        2
    ) AS 前月比
FROM orders 
WHERE order_date >= '2023-01-01'
GROUP BY DATE_FORMAT(order_date, '%Y-%m')
ORDER BY 年月;

商品カテゴリ別パフォーマンス分析

-- カテゴリ別売上分析と商品数
SELECT 
    p.category AS カテゴリ,
    COUNT(DISTINCT p.product_id) AS 商品数,
    COUNT(od.order_id) AS 注文件数,
    SUM(od.quantity) AS 総販売数,
    SUM(od.quantity * od.unit_price) AS 売上金額,
    AVG(od.quantity * od.unit_price) AS 平均注文金額,
    -- 売上構成比
    ROUND(
        SUM(od.quantity * od.unit_price) * 100.0 / 
        (SELECT SUM(quantity * unit_price) FROM order_details), 
        2
    ) AS 売上構成比
FROM products p
INNER JOIN order_details od ON p.product_id = od.product_id
INNER JOIN orders o ON od.order_id = o.order_id
WHERE o.order_date >= '2024-01-01'
GROUP BY p.category
ORDER BY 売上金額 DESC;

顧客分析

顧客セグメンテーション(RFM分析)

RFM分析は、顧客を以下の3つの指標で分類する手法です:

  • Recency(最新性):最後の購入からの日数
  • Frequency(頻度):購入回数
  • Monetary(金額):購入金額
-- RFM分析のベーステーブル作成
WITH customer_rfm AS (
    SELECT 
        c.customer_id,
        c.name AS 顧客名,
        -- Recency: 最後の注文からの日数
        DATEDIFF(CURRENT_DATE, MAX(o.order_date)) AS recency_days,
        -- Frequency: 注文回数
        COUNT(o.order_id) AS frequency,
        -- Monetary: 総購入金額
        SUM(o.amount) AS monetary
    FROM customers c
    LEFT JOIN orders o ON c.customer_id = o.customer_id
    WHERE o.order_date >= '2023-01-01'  -- 直近1年間のデータ
    GROUP BY c.customer_id, c.name
),
-- RFMスコアの計算
rfm_scores AS (
    SELECT *,
        -- Recencyスコア(日数が少ないほど高スコア)
        CASE 
            WHEN recency_days <= 30 THEN 5
            WHEN recency_days <= 60 THEN 4
            WHEN recency_days <= 90 THEN 3
            WHEN recency_days <= 180 THEN 2
            ELSE 1
        END AS r_score,
        -- Frequencyスコア
        CASE 
            WHEN frequency >= 10 THEN 5
            WHEN frequency >= 7 THEN 4
            WHEN frequency >= 4 THEN 3
            WHEN frequency >= 2 THEN 2
            ELSE 1
        END AS f_score,
        -- Monetaryスコア
        CASE 
            WHEN monetary >= 100000 THEN 5
            WHEN monetary >= 50000 THEN 4
            WHEN monetary >= 20000 THEN 3
            WHEN monetary >= 10000 THEN 2
            ELSE 1
        END AS m_score
    FROM customer_rfm
    WHERE frequency > 0  -- 購入履歴がある顧客のみ
)
-- 顧客セグメントの分類
SELECT 
    顧客名,
    recency_days AS 最終購入からの日数,
    frequency AS 購入回数,
    monetary AS 総購入金額,
    CONCAT(r_score, f_score, m_score) AS RFMスコア,
    -- セグメント分類
    CASE 
        WHEN r_score >= 4 AND f_score >= 4 AND m_score >= 4 THEN '最優良顧客'
        WHEN r_score >= 3 AND f_score >= 3 AND m_score >= 3 THEN '優良顧客'
        WHEN r_score >= 4 AND f_score <= 2 THEN '新規顧客'
        WHEN r_score <= 2 AND f_score >= 3 THEN '離脱リスク顧客'
        WHEN r_score <= 2 AND f_score <= 2 THEN '休眠顧客'
        ELSE '一般顧客'
    END AS 顧客セグメント
FROM rfm_scores
ORDER BY (r_score + f_score + m_score) DESC, 総購入金額 DESC;

在庫分析

商品回転率と在庫効率の分析

-- 商品別の販売実績と在庫効率分析
SELECT 
    p.product_name AS 商品名,
    p.price AS 価格,
    p.stock_quantity AS 現在在庫数,
    COALESCE(SUM(od.quantity), 0) AS 月間販売数,
    -- 在庫回転率(月間販売数 ÷ 現在在庫数)
    CASE 
        WHEN p.stock_quantity > 0 THEN 
            ROUND(COALESCE(SUM(od.quantity), 0) / p.stock_quantity, 2)
        ELSE NULL 
    END AS 在庫回転率,
    -- 売上貢献度
    COALESCE(SUM(od.quantity * od.unit_price), 0) AS 月間売上,
    -- 在庫状況の判定
    CASE 
        WHEN p.stock_quantity <= 0 THEN '在庫切れ'
        WHEN COALESCE(SUM(od.quantity), 0) = 0 THEN '売れ行き不調'
        WHEN COALESCE(SUM(od.quantity), 0) / p.stock_quantity > 1 THEN '高回転'
        WHEN COALESCE(SUM(od.quantity), 0) / p.stock_quantity > 0.5 THEN '適正在庫'
        ELSE '過剰在庫'
    END AS 在庫状況
FROM products p
LEFT JOIN order_details od ON p.product_id = od.product_id
LEFT JOIN orders o ON od.order_id = o.order_id 
    AND o.order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)
GROUP BY p.product_id, p.product_name, p.price, p.stock_quantity
ORDER BY 在庫回転率 DESC NULLS LAST;

SQLスキルアップのためのTips

効率的な学習方法

段階的学習アプローチ

SQLスキルを効率的に向上させるための学習順序をご紹介します:

Phase 1: 基礎固め(1-2ヶ月)

-- 1. 基本クエリのマスター
SELECT, WHERE, ORDER BY, LIMIT

-- 2. 集計関数の習得
COUNT, SUM, AVG, MAX, MIN

-- 3. グループ化の理解
GROUP BY, HAVING

Phase 2: 応用スキル(2-3ヶ月)

-- 1. テーブル結合の習得
INNER JOIN, LEFT JOIN, RIGHT JOIN

-- 2. サブクエリの活用
IN, EXISTS, サブクエリ

-- 3. ウィンドウ関数(中級者向け)
ROW_NUMBER(), RANK(), LAG(), LEAD()

Phase 3: 実践活用(3ヶ月以降)

-- 1. 複雑な分析クエリの作成
-- 2. パフォーマンス最適化
-- 3. ストアドプロシージャ、トリガー

実践的な練習方法

1. 日常業務での活用

-- Excelで行っていた分析をSQLで置き換える
-- 例: 売上集計、顧客分析、在庫管理

2. オンライン練習サイトの活用

  • SQLBolt: インタラクティブなSQL学習
  • HackerRank: SQLチャレンジ問題
  • Kaggle Learn: 実践的なデータ分析

3. 実データでの練習

-- 公開データセットを使った分析練習
-- 例: 政府統計データ、オープンデータ

よくあるエラーと対処法

初心者がよく遭遇するエラー

1. 構文エラー

-- ❌ 間違い: カンマの位置が不適切
SELECT name, email, FROM customers;

-- ✅ 正しい
SELECT name, email FROM customers;

-- ❌ 間違い: クォートの不一致
SELECT * FROM customers WHERE name = "田中太郎';

-- ✅ 正しい
SELECT * FROM customers WHERE name = '田中太郎';

2. GROUP BY関連のエラー

-- ❌ 間違い: GROUP BYに含まれていない列をSELECTしている
SELECT name, COUNT(*) 
FROM orders 
GROUP BY customer_id;

-- ✅ 正しい
SELECT customer_id, COUNT(*) 
FROM orders 
GROUP BY customer_id;

3. JOIN関連のエラー

-- ❌ 間違い: 結合条件が不適切で意図しない結果
SELECT c.name, o.amount
FROM customers c, orders o;  -- カルテシアン積が発生

-- ✅ 正しい
SELECT c.name, o.amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

パフォーマンス最適化の基本

インデックスの重要性

-- インデックスが効果的な場合
SELECT * FROM orders WHERE customer_id = 123;  -- customer_idにインデックスがある場合

-- インデックスが効果的でない場合
SELECT * FROM orders WHERE amount * 1.1 > 1000;  -- 計算が含まれる条件

効率的なクエリの書き方

1. 必要な列だけを取得

-- ❌ 非効率: すべての列を取得
SELECT * FROM large_table;

-- ✅ 効率的: 必要な列のみ取得
SELECT customer_id, order_date, amount FROM large_table;

2. 適切な条件の配置

-- ❌ 非効率: 結合後に条件フィルタ
SELECT c.name, o.amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= '2024-01-01';

-- ✅ 効率的: 結合前に条件フィルタ
SELECT c.name, o.amount
FROM customers c
INNER JOIN (
    SELECT customer_id, amount 
    FROM orders 
    WHERE order_date >= '2024-01-01'
) o ON c.customer_id = o.customer_id;

SQLの将来性と学習メリット

SQLの将来性

レガシーシステムと最新技術の双方で活用

SQLはプログラミング言語とは異なり、データベースの世界において寡占状態にあります。RDB用言語としては事実上、SQL以外にほぼ選択肢がない状態が続いています。そのためシステムの新旧に関わらず、依然としてSQLのスキルが役立ちます。

クラウドサービスへの適応

クラウドサービスを使用する際にも、SQLは欠かせない技術です。実際にAWSではデフォルトのRDBとして、MySQLが採用されています。最新のクラウドサーバーに移行しても、決してすたれることのない言語のひとつがSQLなのです。

ほぼすべてのIT分野で必須

AIやIoTといった先端IT分野の活用が急激に広がると考えられ、これからは一部の業界や企業だけでなく広く一般化していくことでしょう。先端ITではいずれもデータ収集と分析が必須であるため、どちらの分野においてもRDBとSQLの知識が役立つことは間違いありません。

SQLを学ぶメリット

キャリアパスの幅が広がる

近年は業界業種を問わず、データ活用が進んでいます。あらゆる分析はデータを活用する時代と言っても過言ではありません。どの企業でもデータ分析や加工は日常的に行われており、データベースの重要性も増しています。

例えばプログラマーがSQLを習得することで、テーブルからのデータ取得効率の向上によるパフォーマンスアップを図れます。さらに近年急速に台頭してきたデータサイエンティストにとっても、SQLは必須のスキルです。

国際規格で汎用性が高い

SQLはISO(国際標準化機構)によって標準化されていて、IT業界全体の「共通言語」としての側面も持ち合わせています。言語仕様やデータベースソフトウェアによって多少の違いはあるものの、基本的な仕様はほぼ同じです。

非エンジニアでも活用できる

近年は「ビッグデータ」に注目されていますが、ビッグデータは必ずデータベースに格納されており、SQLの操作は欠かせません。データの活用は小売業界の顧客分析にとどまらず、医療や農業など幅広い分野で活用の動きが見られます。非エンジニアであっても、SQLの知識が必須となる時代はすぐそこかもしれません。

まとめ

SQLはデータベースを操作するためのデータベース言語です。SQLは国際標準化されているため、一度覚えてしまえば、さまざまなデータベースで利用できます。

プログラミング言語とは異なるものであることも覚えておきましょう。ただし、プログラミング言語の記述のなかで、データベースを操作するためにSQLを利用すること(SQLの埋め込み)が可能です。

具体的にSQLの種類として、次の3つの種類をご紹介しました。これらの中で、DMLは一般的によく利用されるため、まずはDMLの使い方から身に付けてみてはいかがでしょうか。

  • データ操作言語(DML)
  • データ定義言語(DDL)
  • データ制御言語(DCL)

今日から始める実践ステップ

Step 1: 学習環境の構築

  • ブラウザベースのSQL学習サイトで練習開始
  • サンプルデータベースを使った基本クエリの実行

Step 2: 基本スキルの習得

  • SELECT文のマスター(WHERE、ORDER BY、LIMIT)
  • 集計関数の活用(COUNT、SUM、AVG、MAX、MIN)
  • GROUP BY、HAVINGでのグループ化分析

Step 3: 実務での活用

  • 業務データや公開データセットでの実践
  • Excel分析のSQLへの置き換え
  • データドリブンな意思決定への活用

継続学習のポイント

  • 毎日少しずつ: 10-15分の短時間でも継続が重要
  • 実データで練習: 実際の業務データや公開データセットを活用
  • エラーを恐れない: 試行錯誤しながら学習することで理解が深まる

次のステップ

SQLの基礎をマスターしたあなたは、以下の記事でさらなるスキルアップを目指しましょう:

  1. Python データ分析 入門: SQLと組み合わせた高度な分析手法
  2. データサイエンス 勉強法: 体系的なデータ分析スキルの習得方法
  3. データサイエンティスト スキル: 実務で求められる総合的なスキルセット

SQLは「データとの対話」を可能にする強力なツールです。今日から実際にクエリを書いて、データ分析の面白さを体験してください。継続的な学習により、必ずあなたの強力な武器となるはずです。

この記事をシェアする
  • URLをコピーしました!

この記事を書いた人

私は、データラーニングメディア運営の~です。

目次