SQL

SQL入門

小さなデータベースを作り、問い合わせの結果を確かめながらSQLの基礎を学びましょう。

この講座の例はSQLite 3を基準にしています。

01

SQLとは

SQLは、リレーショナルデータベースへ命令を伝えるための言語です。データは表に似た「テーブル」へ保存されます。横一件分を行、名前や価格のような項目を列と呼びます。

SQLで行う主な操作
  • SELECTでデータを検索する
  • INSERTで新しい行を追加する
  • UPDATEで保存済みの値を変更する
  • DELETEで不要な行を削除する
  • CREATE TABLEで保存場所を定義する

SQLのキーワードは大文字・小文字を区別しない製品が一般的です。この講座では、列名と見分けやすいようキーワードを大文字で書きます。

02

SQLiteで実行してみよう

SQLiteは、サーバーを別に起動せず、一つのファイルで試せるデータベースです。ターミナルでsqlite3 shop.dbを実行すると、練習用のshop.dbを開けます。.headers on.mode columnは結果を表形式で見やすくするSQLiteの設定です。終了は.quitです。

SQLiteを起動して確認SHELL
$ sqlite3 shop.db
SQLite version 3.x.x
sqlite> .headers on
sqlite> .mode column
sqlite> SELECT 'SQLを勉強中' AS message;
message
-------------
SQLを勉強中
sqlite> .quit
別の方法 SQLiteが未導入なら、DB Browser for SQLiteなどのGUIや、SQLを実行できる学習サービスも使えます。入力するSQLは同じですが、表示形式は環境により異なります。
練習用ファイルを使う 更新や削除も学ぶため、仕事やサービスのデータベースへ接続せず、新しい練習用データベースで操作してください。
03

商品テーブルを作る

商品番号、商品名、価格、分類、在庫数を保存するproductsテーブルを作ります。PRIMARY KEYは行を一意に識別し、NOT NULLは値の省略を禁止します。

テーブルと練習データを用意SQL
CREATE TABLE products (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    price INTEGER NOT NULL CHECK (price >= 0),
    category TEXT,
    stock INTEGER NOT NULL DEFAULT 0
);

INSERT INTO products (id, name, price, category, stock) VALUES
    (1, 'SQL入門書', 2800, 'book', 5),
    (2, 'ノート',     300, 'stationery', 12),
    (3, 'ボールペン', 150, 'stationery', 0),
    (4, 'マグカップ', 900, NULL, 3);

価格をINTEGERにしているため、この例では円単位の整数として保存します。お金を浮動小数点数で保存すると丸め誤差が起こる場合があります。

方言の違い SQLには共通部分がありますが、型、自動採番、日付関数などはSQLite、PostgreSQL、MySQLなどで異なります。実務では利用するDBMSの公式資料も確認します。
04

SQLiteの型と型親和性

プログラミング言語の変数の型とは異なり、SQLの型はテーブルの各列へどのような値を保存するかを表します。ただし、SQLiteは値そのものに格納クラスを持たせる、柔軟な型の仕組みを採用しています。

格納クラス保存する値この講座での例
INTEGER符号付き整数商品番号、価格、在庫数
REAL浮動小数点数平均値や測定値
TEXT文字列商品名、分類、ISO 8601形式の日付
BLOB入力したままのバイナリデータ画像や暗号化済みデータなど
NULL値が不明または存在しない状態未設定の分類

typeof()を使うと、SQLiteが実際の値をどの格納クラスとして扱っているか確認できます。

値の格納クラスを確認SQL
SELECT typeof(42) AS integer_type,
       typeof(3.14) AS real_type,
       typeof('SQL') AS text_type,
       typeof(X'53514C') AS blob_type,
       typeof(NULL) AS null_type;
実行結果OUTPUT
integer_type  real_type  text_type  blob_type  null_type
------------  ---------  ---------  ---------  ---------
integer       real       text       blob       null

宣言した型は「型親和性」として働く

SQLiteで列へINTEGERTEXTを宣言すると、その型へ変換できる値をなるべく変換して保存する「型親和性」が決まります。列の親和性にはINTEGER、REAL、TEXT、NUMERIC、BLOBがありますが、通常のテーブルでは変換できない別種の値も保存できることがあります。

INTEGER親和性の列へ文字列を保存SQL
CREATE TABLE affinity_samples (value INTEGER);

INSERT INTO affinity_samples VALUES ('42'), ('変換できない文字列');

SELECT value, typeof(value) AS stored_as
FROM affinity_samples;
実行結果OUTPUT
value               stored_as
------------------  ---------
42                  integer
変換できない文字列   text

文字列の'42'は整数へ変換されますが、変換できない文字列はTEXTのまま保存されます。PostgreSQLなど、宣言した列型と合わない値を原則として拒否するDBMSとは挙動が異なります。SQLiteでもSTRICTテーブルを使うと、受け入れる型をより厳密に制限できます。

SQLiteで日付をTEXTにする理由

SQLiteには専用のDATE格納クラスがありません。この講座では、文字列の並び順と日付順が一致し、日付関数でも扱いやすいYYYY-MM-DDのISO 8601形式をTEXTへ保存します。時刻を含める場合も形式とタイムゾーンを統一することが重要です。PostgreSQLやMySQLなどにはDATETIMETIMESTAMPといった専用型があるため、利用するDBMSに合う型を選びます。

型を制約と組み合わせる SQLiteの通常テーブルでは宣言型だけに頼らず、NOT NULLCHECK、必要に応じてSTRICTテーブルを使って、保存できる値のルールを表します。
05

SELECTでデータを検索する

SELECTの後ろに表示する列、FROMの後ろに読み取るテーブルを書きます。必要な列だけを指定すると、結果の意味が明確になります。

商品名と価格を取り出すSQL
SELECT name, price
FROM products;
実行結果OUTPUT
name        price
----------  -----
SQL入門書   2800
ノート       300
ボールペン   150
マグカップ   900

SELECT *は全列を返します。内容を手早く確認するときには便利ですが、アプリでは列の追加によって結果が変わるため、通常は必要な列を列挙します。

計算結果と別名

税込価格を計算するSQL
SELECT name, price, price * 110 / 100 AS price_with_tax
FROM products;
実行結果OUTPUT
name        price  price_with_tax
----------  -----  --------------
SQL入門書   2800   3080
ノート       300    330
ボールペン   150    165
マグカップ   900    990

ASで計算結果に分かりやすい列名を付けられます。

06

WHEREで行を絞り込む

WHEREは条件を満たす行だけを対象にします。文字列はシングルクォートで囲みます。

500円以上で在庫がある商品SQL
SELECT name, price, stock
FROM products
WHERE price >= 500 AND stock > 0;
実行結果OUTPUT
name        price  stock
----------  -----  -----
SQL入門書   2800   5
マグカップ   900   3
よく使う条件
  • =<><<=>>=で比較する
  • ANDで両方、ORでどちらかを満たす条件にする
  • BETWEEN 100 AND 500で範囲を指定する
  • IN ('book', 'stationery')で候補を並べる
  • LIKE 'SQL%'で「SQLから始まる」文字列を探す

ANDORより先に評価されます。意図が伝わりにくい組み合わせは、WHERE (category = 'book' OR category IS NULL) AND stock > 0のように丸括弧を使います。

07

ORDER BYで並べ替える

テーブルの行に決まった順序はありません。順番が必要ならORDER BYを指定します。ASCは昇順、DESCは降順です。

価格が高い順に2件SQL
SELECT name, price
FROM products
ORDER BY price DESC, id ASC
LIMIT 2;
実行結果OUTPUT
name        price
----------  -----
SQL入門書   2800
マグカップ   900

価格が同じ行の順序も安定させるため、二つ目の基準にidを指定しています。LIMITの構文はDBMSによって異なる場合があります。

08

NULLを正しく扱う

NULLは、値が不明または存在しない状態です。0や空文字とは異なります。= NULLではなく、IS NULLで調べます。

分類が未設定の商品SQL
SELECT name
FROM products
WHERE category IS NULL;
実行結果OUTPUT
name
----------
マグカップ

NULLを含む算術演算の結果も通常はNULLです。表示用の代替値が必要なら、COALESCE(category, '未分類')のように最初のNULLでない値を返す関数を使えます。

09

GROUP BYで集計する

集計関数は複数行をまとめます。COUNTは件数、SUMは合計、AVGは平均、MINMAXは最小・最大を求めます。

分類ごとの商品数と平均価格SQL
SELECT COALESCE(category, '未分類') AS category_name,
       COUNT(*) AS product_count,
       AVG(price) AS average_price
FROM products
GROUP BY category
ORDER BY category_name;
実行結果OUTPUT
category_name  product_count  average_price
-------------  -------------  -------------
book           1              2800.0
stationery     2              225.0
未分類          1              900.0

WHEREは集計前の行を、HAVINGは集計後のグループを絞ります。詳しい例は検索と集計で扱います。

10

JOINでテーブルを結合する

注文を別テーブルへ保存し、商品番号で商品と関係付けます。外部キーは、存在しない商品番号が保存されるのを防ぐ制約です。

注文テーブルを用意SQL
PRAGMA foreign_keys = ON;

CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    product_id INTEGER NOT NULL,
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    ordered_at TEXT NOT NULL,
    FOREIGN KEY (product_id) REFERENCES products(id)
);

INSERT INTO orders VALUES
    (1, 1, 2, '2026-09-01'),
    (2, 2, 3, '2026-09-02');
商品名付きで注文を表示SQL
SELECT orders.id, products.name, orders.quantity
FROM orders
INNER JOIN products
    ON orders.product_id = products.id
ORDER BY orders.id;
実行結果OUTPUT
id  name       quantity
--  ---------  --------
1   SQL入門書  2
2   ノート      3

ONには、どの列同士が同じ関係かを書きます。結合の種類と一対多の集計は結合と副問い合わせで詳しく学びます。

11

データを追加・更新・削除する

INSERTで追加し、UPDATEで変更し、DELETEで削除します。更新と削除ではWHEREを忘れると全行が対象になります。

一件ずつ操作するSQL
INSERT INTO products (id, name, price, category, stock)
VALUES (5, '付せん', 250, 'stationery', 8);

UPDATE products
SET stock = stock - 2
WHERE id = 1 AND stock >= 2;

DELETE FROM products
WHERE id = 5;
更新後の対象商品SQL
SELECT id, name, stock FROM products WHERE id = 1;
実行結果OUTPUT
id  name       stock
--  ---------  -----
1   SQL入門書  3
先に対象を確認 UPDATEDELETEを実行する前に、同じWHEREを使ったSELECTで対象行を確認します。アプリから値を渡すときは文字列連結をせず、プレースホルダーを使ってSQLインジェクションを防ぎます。
12

トランザクションで安全に更新する

複数の変更をまとめて成功または失敗させる仕組みがトランザクションです。BEGINで始め、問題がなければCOMMIT、取り消すならROLLBACKを実行します。

確認してから確定するSQL
BEGIN;

UPDATE products SET stock = stock - 1
WHERE id = 2 AND stock >= 1;

SELECT id, name, stock FROM products WHERE id = 2;

COMMIT;

更新件数が想定と違うときはCOMMITせずROLLBACKします。分離レベルや同時実行時の注意は更新とトランザクションで学びます。

PRACTICE

練習問題

問題1:在庫切れの商品

在庫が0の商品名と価格を表示してください。

解答例SQL
SELECT name, price
FROM products
WHERE stock = 0;
実行結果OUTPUT
name        price
----------  -----
ボールペン   150
問題2:在庫金額を求める

各商品の「価格×在庫数」をstock_valueという名前で表示し、大きい順に並べてください。

解答例SQL
SELECT name, price * stock AS stock_value
FROM products
ORDER BY stock_value DESC, id ASC;
実行結果OUTPUT
name        stock_value
----------  -----------
SQL入門書   8400
ノート       3300
マグカップ   2700
ボールペン   0
問題3:注文金額を表示する

商品と注文を結合し、注文番号、商品名、数量、価格×数量の合計を表示してください。

解答例SQL
SELECT o.id, p.name, o.quantity,
       p.price * o.quantity AS total
FROM orders AS o
INNER JOIN products AS p ON p.id = o.product_id
ORDER BY o.id;
実行結果OUTPUT
id  name       quantity  total
--  ---------  --------  -----
1   SQL入門書  2         5600
2   ノート      3         900
練習の進め方 まず欲しい結果を表に書き、必要なテーブル、列、行の条件を分けて考えます。答えが出たら0件、同額、NULLなどのデータを追加して動きを確かめましょう。
NEXT

次に学ぶこと

基本を読み終えたら、次の4テーマで、検索から安全なデータ管理へ理解を広げましょう。