コーディング · プログラミング言語
SQL入門:初心者向けチュートリアル
結論
SQLは、PostgreSQL、MySQL、SQLiteなどのリレーショナルデータベースで、データを作成、検索、変更するための標準言語です。SELECT、INSERT、UPDATE、DELETEのような宣言的な文を書くと、実行方法はデータベースが決めます。このページでは、テーブル設計、絞り込み、結合、グループ化、サブクエリ、ウィンドウ関数、トランザクションを学び、PostgreSQL・MySQL・SQLiteの主な違いも紹介します。
SQLとは何か、何に使われるのか
SQL(Structured Query Language)は、行と列からなるテーブルにデータを保存するリレーショナルデータベースを扱うための標準言語です。欲しいデータを記述すると、データベースエンジンがその探し方を決めます。SQLはISO/IEC 9075で標準化されており、主要なデータベースはどれも、標準の中核部分と独自の拡張を実装しています。
開発者、データアナリスト、データエンジニア、データベース管理者は、アプリケーションのデータの保存、業務上の問いへの回答、レポート作成、データパイプラインへのデータ供給のために、毎日SQLを使っています。代表的なオープンソースのエンジンは、PostgreSQL、MySQL(とそのフォークであるMariaDB)、SQLiteです。商用のものには、Microsoft SQL ServerやOracle Databaseがあります。
データベースを用意して最初のクエリを実行する
最も手軽に始められるのはSQLiteです。サーバーが不要で、1つのファイルに保存されるデータベースで、macOSやほとんどのLinuxにはあらかじめ入っています。PostgreSQLとMySQLはサーバーとして動作し、コマンドラインクライアントの psql と mysql が付属します。
sqlite3 shop.db # SQLite: opens or creates a file
psql -U postgres -d shop # PostgreSQL client
mysql -u root -p shop # MySQL clientSELECT 'Hello, world!' AS greeting;
-- greeting
-- Hello, world!SQLのキーワードは大文字と小文字を区別しません。キーワードを大文字、名前を小文字で書くのが一般的な慣例で、クエリが読みやすくなります。文の終わりにはセミコロンを付け、-- でコメントを始めます。
テーブルの作成:データ型と制約
テーブル定義では、列、その型、データの正しさを保つ制約を列挙します。このページのすべての例では、customers と orders の2つのテーブルを使います。
CREATE TABLE customers (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL,
city VARCHAR(50)
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
customer_id INTEGER NOT NULL REFERENCES customers(id),
amount DECIMAL(10, 2) NOT NULL,
ordered_on DATE NOT NULL
);
INSERT INTO customers (id, name, city) VALUES
(1, 'Ann', 'Oslo'), (2, 'Bo', 'Rome'), (3, 'Cy', 'Oslo');
INSERT INTO orders (id, customer_id, amount, ordered_on) VALUES
(1, 1, 30.00, '2026-01-05'),
(2, 1, 45.50, '2026-02-10'),
(3, 2, 12.00, '2026-02-11');| 型 | 格納するもの | 補足 |
|---|---|---|
INTEGER, BIGINT | 整数 | 大きなIDには BIGINT を使う |
DECIMAL(p, s) | 正確な小数 | 金額に使う。FLOAT は決して使わない |
VARCHAR(n), TEXT | 文字列 | TEXT は標準にはないが、広くサポートされている |
DATE, TIMESTAMP | 日付と時刻 | リテラルは '2026-01-05' のように書く |
BOOLEAN | 真偽値 | MySQLでは TINYINT(1) として扱われる |
制約には、PRIMARY KEY(行を一意に識別する)、NOT NULL、UNIQUE、CHECK (condition)、FOREIGN KEY / REFERENCES(値が別のテーブルに存在しなければならない)があります。文字列にはシングルクォートを使い、標準SQLではダブルクォートは識別子用です。
SELECT:絞り込み、並べ替え、件数制限
SELECT はデータを読み取ります。WHERE は行を絞り込み、ORDER BY は並べ替え、LIMIT(または標準の FETCH FIRST n ROWS ONLY)は返す件数を制限します。
SELECT name, city
FROM customers
WHERE city = 'Oslo'
ORDER BY name;
-- Ann | Oslo
-- Cy | Oslo
SELECT id, amount,
CASE WHEN amount >= 40 THEN 'large'
WHEN amount >= 20 THEN 'medium'
ELSE 'small' END AS size
FROM orders
WHERE amount BETWEEN 10 AND 50
ORDER BY amount DESC
LIMIT 2;
-- 2 | 45.50 | large
-- 1 | 30.00 | medium
SELECT name FROM customers WHERE city IS NULL; -- not: city = NULL
SELECT name FROM customers WHERE name LIKE 'A%'; -- AnnJOIN:テーブルを結合する
結合は、通常は外部キーである条件を使って、2つのテーブルの行を対応付けます。INNER JOIN(単に JOIN でも可)は一致する行だけを残し、LEFT JOIN は左のテーブルのすべての行を残して、足りない列を NULL で埋めます。
SELECT c.name, o.amount
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.id
ORDER BY o.amount DESC;
-- Ann | 45.50
-- Ann | 30.00
-- Bo | 12.00
SELECT c.name, o.id AS order_id
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
WHERE o.id IS NULL; -- customers with no orders
-- Cy | NULL| 結合 | 返すもの |
|---|---|
INNER JOIN | 両方のテーブルで一致する行 |
LEFT JOIN | 左のすべての行と、右側で一致した行(なければ NULL) |
RIGHT JOIN | 右のすべての行と、左側で一致した行(なければ NULL) |
FULL OUTER JOIN | 両側のすべての行。MySQLではサポートされない |
CROSS JOIN | 行のすべての組み合わせ(直積) |
GROUP BYと集約関数
COUNT、SUM、AVG、MIN、MAX などの集約関数は、多数の行を1つにまとめます。GROUP BY はグループごとに1行の結果を作り、HAVING は集約後にグループを絞り込みます。一方、WHERE は集約の前に行を絞り込みます。
SELECT c.name,
COUNT(o.id) AS orders,
COALESCE(SUM(o.amount), 0) AS total
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY total DESC;
-- Ann | 2 | 75.50
-- Bo | 1 | 12.00
-- Cy | 0 | 0
SELECT city, COUNT(*) AS n
FROM customers
GROUP BY city
HAVING COUNT(*) > 1;
-- Oslo | 2COUNT(*) は行数を数えますが、COUNT(column) はnullでない値だけを数えます。そのため、上の結果でCyの注文数は0になっています。COALESCE は、nullでない最初の引数を返します。
サブクエリ、CTE、ウィンドウ関数
サブクエリは、別のクエリの中に書くクエリです。共通テーブル式(CTE)は WITH で書き、サブクエリに名前を付けて、長いクエリを読みやすくします。ROW_NUMBER、RANK、SUM(...) OVER などのウィンドウ関数は、関連する行にまたがる値を、グループにまとめずに計算します。
SELECT name FROM customers
WHERE id IN (SELECT customer_id FROM orders WHERE amount > 20);
-- Ann
WITH totals AS (
SELECT customer_id, SUM(amount) AS total
FROM orders
GROUP BY customer_id
)
SELECT c.name, t.total,
RANK() OVER (ORDER BY t.total DESC) AS rnk
FROM totals AS t
JOIN customers AS c ON c.id = t.customer_id;
-- Ann | 75.50 | 1
-- Bo | 12.00 | 2CTEとウィンドウ関数は、PostgreSQL、SQLite 3.25以降、MySQL 8.0以降でサポートされています。
データの変更:INSERT、UPDATE、DELETE、トランザクション
UPDATE と DELETE は、WHERE 句に一致するすべての行に作用します。トランザクションは複数の文をまとめ、すべて成功するか、すべて失敗するかのどちらかにします。
UPDATE customers SET city = 'Paris' WHERE id = 2;
DELETE FROM orders WHERE amount < 15;
BEGIN;
UPDATE orders SET amount = amount - 10 WHERE id = 1;
UPDATE orders SET amount = amount + 10 WHERE id = 2;
COMMIT; -- or ROLLBACK; to undo both
SELECT id, amount FROM orders;
-- 1 | 20.00
-- 2 | 55.50PostgreSQL、MySQL、SQLiteの違い
SQLの中核部分は移植できますが、細部はエンジンごとに異なります。以下は、初心者が最初に出会う違いです。
| 機能 | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| 自動採番ID | GENERATED ALWAYS AS IDENTITY または SERIAL | AUTO_INCREMENT | INTEGER PRIMARY KEY |
| 名前の引用 | "name" | 名前を囲むバッククォート | "name" |
| 行数の制限 | LIMIT n または FETCH FIRST n ROWS ONLY | LIMIT n | LIMIT n |
| 文字列の連結 | a || b | CONCAT(a, b) | a || b |
| 真偽値 | 本物の BOOLEAN 型 | TINYINT(1) | 0と1として保存される |
| 型付け | 厳格 | デフォルトの厳格モードでは厳格 | 柔軟。ただしテーブルを STRICT と宣言した場合を除く |
| アップサート | ON CONFLICT ... DO UPDATE | ON DUPLICATE KEY UPDATE | ON CONFLICT ... DO UPDATE |
そのほかの違いには、日付関数(PostgreSQLとMySQLでは NOW()、SQLiteでは datetime('now'))、文字列比較の大文字小文字の区別、MySQLにはない完全外部結合のサポートなどがあります。
よくある間違いと次のステップ
- ユーザー入力を連結してクエリを組み立てる。SQLインジェクションの原因になります。プログラミング言語から、必ずプレースホルダ(
?や$1など)を使ったパラメータ化クエリを使ってください。 - グループ化したクエリで、
GROUP BYにも集約関数の中にもない列を選択する。 - 金額に
DECIMALではなくFLOATを使う。 - 結合や絞り込みに使う列にインデックスを付け忘れる。
CREATE INDEX idx_orders_customer ON orders(customer_id);とEXPLAINが役に立ちます。 ORDER BYなしで、行が決まった順序で返ってくると思い込む。
さらに学ぶには、公式マニュアルを読みましょう。PostgreSQL tutorial、MySQL Reference Manual、SQLite SQL language referenceがあります。実際のデータセットで、日本語で問いを書き、それぞれをクエリに直す練習をしましょう。
よくある質問
SQLはプログラミング言語ですか?
SQLは宣言的なクエリ言語で、結果を得る手順ではなく、欲しい結果を記述します。PL/pgSQLやT-SQLといったベンダー独自の拡張では、変数、ループ、プロシージャが加わります。
初心者はどのデータベースから始めるべきですか?
SQLiteはサーバーが不要で、学習に最適です。PostgreSQLは、実際のアプリケーション向けに標準準拠のSQLを学ぶのに適しており、MySQLはWebホスティングでよく使われています。
WHEREとHAVINGの違いは何ですか?
WHERE はグループ化の前に個々の行を絞り込み、HAVING は集約関数の計算後にグループを絞り込みます。
INNER JOINとLEFT JOINの違いは何ですか?
INNER JOIN は、両方のテーブルで一致する行だけを返します。LEFT JOIN は左のテーブルのすべての行を返し、一致がない場合は右のテーブルの列を NULL で埋めます。
SQLインジェクションを防ぐには、どうすればよいですか?
ユーザー入力をSQL文に決して埋め込まないでください。パラメータ化クエリやプリペアドステートメントを使い、データベースにクエリと値を別々に渡します。