/14分で読めます

SQLとは?Structured Query Languageの完全ガイド

SNS、銀行、ECサイトなど、日常的に使うほとんどのアプリはリレーショナルデータベースにデータを保存し、SQLで取り出しています。SQLを理解することは、ソフトウェア開発、データ分析、ITでとても役立つスキルです。

SQLとは?

SQLStructured Query Languageの略です。リレーショナルデータベースでデータを作成、検索、更新、管理するために使われる標準化された言語です。

SQLは宣言型の言語です。取得したいデータを記述すると、データベースエンジンが効率的な取得方法を判断します。そのため、JavaScriptやPythonのように手順を細かく書くプログラミング言語とは性質が異なります。

SQLはPostgreSQL、MySQL、SQLite、SQL Server、Oracle Database、多くの分析システムを支える中核技術として今も広く使われています。

発音

SQLは「sequel」と読む場合も、「S-Q-L」と1文字ずつ読む場合もあります。どちらも広く通じます。チームでは、使っているデータベースコミュニティで一般的な読み方に合わせることが多いです。

SQLの簡単な歴史

SQLは、1970年にEdgar F. Coddが提唱したリレーショナルモデルから始まりました。その後、IBMのDonald ChamberlinとRaymond Boyceがリレーショナルデータを問い合わせるためにSEQUELを作り、これがSQLになりました。

出来事
1970Edgar F. Coddがリレーショナルモデルの論文を発表
1974IBMがSEQUELを開発し、のちにSQLへ改名
1979Oracleが最初の商用SQLデータベースをリリース
1986SQLがANSI標準になる
1992SQL-92が標準JOINや式の主要機能を追加
1999SQL:1999がトリガー、CTE、再帰クエリを追加
2016-2023現代のSQL標準がJSONやグラフクエリ機能を追加

リレーショナルデータベースの解説

リレーショナルデータベースは、データをテーブルに整理します。各テーブルには通常、次の要素があります:

  • : name、email、price、created_atなどのフィールドを定義します。
  • : 1行が1件のレコードです。
  • 主キー: 行を一意に識別します。
  • 外部キー: テーブル間の行を関連付けます。
users(id, name, email)
orders(id, user_id, total, order_date)

orders.user_id -> users.id

この構造により重複を減らせます。たとえば顧客情報はusersテーブルに一度だけ保存し、ordersテーブルはその顧客をidで参照できます。

SQL構文の基本

SQL文は、よく次のカテゴリに分類されます:

カテゴリコマンド目的
DQLSELECTデータを取得する
DMLINSERT, UPDATE, DELETEデータを変更する
DDLCREATE, ALTER, DROPスキーマやテーブルを定義する
DCLGRANT, REVOKE権限を制御する
TCLBEGIN, COMMIT, ROLLBACKトランザクションを管理する
SELECT users.name, orders.total
FROM users
JOIN orders ON orders.user_id = users.id
WHERE orders.total > 100
ORDER BY orders.total DESC;

CRUD操作

CRUDはcreate、read、update、deleteの略です。保存されたデータに対して多くのアプリが行う基本操作です。

-- Create
INSERT INTO products (name, price) VALUES ('Keyboard', 49.99);

-- Read
SELECT id, name, price FROM products WHERE price > 20;

-- Update
UPDATE products SET price = 44.99 WHERE id = 1;

-- Delete
DELETE FROM products WHERE id = 1;

フィルタリング、並べ替え、集計

実際のクエリでは、行を絞り込み、結果を並べ替え、データをグループ化し、件数、合計、平均、最小値、最大値などの集計を行います。

  • WHEREは行を絞り込みます。
  • ORDER BYは結果を並べ替えます。
  • GROUP BYは集計のために行をグループ化します。
  • HAVINGはグループ化後の結果を絞り込みます。

JOIN: テーブルを結合する

JOINは複数テーブルの行を結合します。リレーショナルデータベースがデータをあちこちにコピーせず、現実世界の関係を表現できる理由になる重要な機能です。

  • INNER JOIN: 両方のテーブルで一致する行だけを返します。
  • LEFT JOIN: 左側テーブルの全行と、右側テーブルで一致する行を返します。
  • RIGHT JOIN: 右側テーブルの全行と、左側テーブルで一致する行を返します。
  • FULL OUTER JOIN: 可能なところは一致させつつ、両側の行を返します。
SELECT users.name, orders.order_date, orders.total
FROM users
INNER JOIN orders ON orders.user_id = users.id;

サブクエリとCTE

サブクエリは、別のクエリの中に書くクエリです。CTEはWITHで一時的な結果セットに名前を付ける仕組みで、複雑なSQLを読みやすく再利用しやすくします。

インデックスとパフォーマンス

インデックスは、多くの場合B-treeのようなデータ構造で、データベースが行をより速く見つける助けになります。読み取りは速くなりますが、追加の保存領域が必要で、INSERT、UPDATE、DELETEのたびにインデックス更新も発生するため書き込みが遅くなることがあります。

CREATE INDEX idx_products_category ON products(category);
EXPLAIN SELECT * FROM products WHERE category = 'Electronics';

インデックスのトレードオフ

すべての列にインデックスを付けるべきではありません。WHERE、JOIN、ORDER BY、一意性チェックでよく使う列に集中し、EXPLAINで性能を確認します。

トランザクションとACID

性質意味
Atomicityすべての操作が成功するか、すべてロールバックされる
Consistencyデータベースが有効な状態から別の有効な状態へ移る
Isolation同時実行されるトランザクションが互いに壊し合わない
Durabilityコミット済みの変更がクラッシュ後も残る
BEGIN TRANSACTION;

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;
-- ROLLBACK;

SQL方言の比較

SQLは標準化されていますが、各データベースは独自機能や細かな構文差を追加しています。

機能MySQLPostgreSQLSQLiteSQL Server
自動採番AUTO_INCREMENTSERIAL / GENERATEDAUTOINCREMENTIDENTITY
行数制限LIMITLIMITLIMITTOP / OFFSET-FETCH
文字列結合CONCAT()||||+
UpsertON DUPLICATE KEYON CONFLICTON CONFLICTMERGE
JSON対応JSON型JSONBJSON関数JSON関数

SQLインジェクションとセキュリティ

SQLインジェクションは、ユーザー入力をSQL文字列へ直接連結したときに起こります。攻撃者はクエリの意味を変え、データの読み取り、変更、削除を行える可能性があります。

-- Vulnerable: string concatenation
query = "SELECT * FROM users WHERE name = '" + userInput + "'";

-- Safe: parameterized query
query = "SELECT * FROM users WHERE name = ?";
db.execute(query, [userInput]);

必ずパラメータ化クエリを使う

ユーザー入力をSQL文字列に連結してはいけません。プリペアドステートメントやパラメータ化クエリを使うと、入力は実行可能なSQLではなくデータとして扱われます。

ベストプラクティス

  • キーワードの大文字化と明確なインデントでSQLを一貫して整形します。SQLフォーマッターが役立ちます。
  • 意味の分かりやすいテーブル名と列名を使います。
  • 本番クエリではSELECT *を避け、必要な列だけを取得します。
  • インデックスは戦略的に追加し、EXPLAINで検証します。
  • 一緒に成功または失敗すべき関連変更にはトランザクションを使います。
  • ユーザーが入力した値には必ずパラメータ化クエリを使います。
  • 定期的にバックアップし、復元手順もテストします。

SQLとNoSQLの違い

MongoDB、Redis、Cassandra、DynamoDBなどのNoSQLデータベースは、リレーショナルモデルが最適でないワークロードで役立ちます。

観点SQLNoSQL
データモデル行と列を持つテーブルドキュメント、キー・バリュー、グラフ、ワイドカラム
スキーマ定義済みスキーマ柔軟なスキーマ
スケーリング垂直方向が先になることが多い水平方向が先になることが多い
一貫性強いACIDサポート結果整合性または調整可能な一貫性が多い
向いている用途構造化データとトランザクション柔軟なデータと高スループットのワークロード

現代の多くのシステムでは両方を使います。ユーザーや注文のようなトランザクション記録にはSQL、キャッシュ、検索、イベント、ドキュメント保存にはNoSQLを使う、といった構成です。

SQLをすぐに整形

無料のSQL Formatterで、SQLクエリを整形、インデント、標準化できます。一般的な方言に対応し、ブラウザ内で動作します。

SQL Formatterを試す ->

参考資料

  1. Codd, E. F. A Relational Model of Data for Large Shared Data Banks. https://dl.acm.org/doi/10.1145/362384.362685
  2. ISO/IEC 9075:2023. Information technology - Database languages - SQL.
  3. OWASP Foundation. SQL Injection. https://owasp.org/www-community/attacks/SQL_Injection
  4. PostgreSQL Global Development Group. PostgreSQL Documentation. https://www.postgresql.org/docs/
  5. MySQL. MySQL Reference Manual. https://dev.mysql.com/doc/