cv.cm

コーディング · プログラミング言語

SQL入門:初心者向けチュートリアル

約13分で読めます

結論

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 client
SELECT '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%'; -- Ann

JOIN:テーブルを結合する

結合は、通常は外部キーである条件を使って、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 | 2

COUNT(*) は行数を数えますが、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 | 2

CTEとウィンドウ関数は、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.50

PostgreSQL、MySQL、SQLiteの違い

SQLの中核部分は移植できますが、細部はエンジンごとに異なります。以下は、初心者が最初に出会う違いです。

機能PostgreSQLMySQLSQLite
自動採番IDGENERATED ALWAYS AS IDENTITY または SERIALAUTO_INCREMENTINTEGER PRIMARY KEY
名前の引用"name"名前を囲むバッククォート"name"
行数の制限LIMIT n または FETCH FIRST n ROWS ONLYLIMIT nLIMIT n
文字列の連結a || bCONCAT(a, b)a || b
真偽値本物の BOOLEAN 型TINYINT(1)0と1として保存される
型付け厳格デフォルトの厳格モードでは厳格柔軟。ただしテーブルを STRICT と宣言した場合を除く
アップサートON CONFLICT ... DO UPDATEON DUPLICATE KEY UPDATEON 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文に決して埋め込まないでください。パラメータ化クエリやプリペアドステートメントを使い、データベースにクエリと値を別々に渡します。

コーディング講座の一覧