Welcome

SQL Guide初心者向けSQL文・キーワード集

SQLは「データベースへお願いを伝える言葉」です

SQL(Structured Query Language)は、データベースに対して「見せて」「追加して」「直して」「削除して」と依頼するための言語です。サーバー構築・運用では、アプリの接続確認、監視データの調査、障害時の切り分け、バックアップ後の確認でも使います。

最初の覚え方:読む SELECT → 絞る WHERE → 並べる ORDER BY → 集計する GROUP BY → つなぐ JOIN → 変更する INSERT / UPDATE / DELETE の順で練習します。

DQL(Data Query Language/データを問い合わせる命令):読む

SELECT で必要な行と列を取得します。調査は原則ここから始めます。

DML(Data Manipulation Language/データを操作する命令):データを変える

INSERT / UPDATE / DELETE で行を追加・更新・削除します。

DDL(Data Definition Language/データの入れ物を定義する命令):器を作る

CREATE / ALTER / DROP でテーブルなどの構造を管理します。ここでいう「器」とは、データを入れる表そのもののことです。

DCL(Data Control Language/権限を制御する命令):権限を守る

GRANT / REVOKE で「誰が何をできるか」を制御します。

TCL(Transaction Control Language/変更のまとまりを制御する命令):変更をまとめる

COMMIT / ROLLBACK で変更の確定・取り消しを行います。

運用:速さと安全を確かめる

EXPLAIN、インデックス、ログ、バックアップを組み合わせて確認します。

SQL方言(データベース製品ごとの書き方の違い)に注意:MySQL、PostgreSQL、SQLite、SQL Serverでは、日付関数、自動採番、文字列結合、件数制限などの書き方が異なります。このページは共通的な書き方を中心にし、実行時は利用製品の公式資料で確認します。
方言差異の代表例(各1行)
分類MySQLPostgreSQLSQLiteSQL Server
現在日時を取る日付関数NOW()NOW() / CURRENT_TIMESTAMPCURRENT_TIMESTAMPGETDATE()
自動採番AUTO_INCREMENTGENERATED ... AS IDENTITY / SERIALINTEGER PRIMARY KEY(自動的に採番)IDENTITY(1,1)
文字列結合CONCAT(a, b)a || ba || ba + b
件数制限LIMIT nLIMIT nLIMIT nTOP n

練習用テーブル:servers

以降は、サーバー台帳を想定した次の列を使います。1行が1台のサーバー、列がその属性です。owner_id は担当者を表す番号で、結合(JOIN)で使う owners テーブルの主キー(その表の中で1行を見分けるための、重複しない列)に対応します。

練習用serversテーブルの列
列名意味
server_id重複しない識別番号101
hostnameサーバー名web-01
role役割web / db
environment環境dev / prod
owner_id担当者ID(ownersテーブルへの外部キー、未設定はNULL1 / NULL
cpu_usageCPU使用率(%)42.5
last_checked_at最終確認日時2026-08-28 10:00:00

この列に、以下のような架空のサンプルデータが入っているものとして、このページの例と演習を進めます。

serversテーブルのサンプルデータ(架空)
server_idhostnameroleenvironmentowner_idcpu_usagelast_checked_at
101web-01webprod182.32026-08-28 09:50:00
102web-02webprod245.12026-08-28 09:55:00
103db-01dbprod191.72026-08-28 10:00:00
104db-02dbdevNULL15.22026-08-20 08:00:00
105app-01appstg266.42026-08-27 22:10:00
106app-02appprodNULL88.92026-08-28 09:40:00
107batch-01batchdev312.02026-08-15 07:30:00
108cache-01cacheprod377.52026-08-28 09:45:00
注記:このサンプルデータは学習用に作成した架空の値です。実際の機器で実行して得た結果ではありません(NOT RUN=未実行)。このページの「11. 手を動かす演習」にある手順を使って、自分の手元の環境で同じデータを作り、実際に実行して確かめてください。

1. データを読む・絞る・並べる

取得

SELECT

表示したい列を指定します。* と書くと、すべての列を取り出せます。ただし実務では、必要な列だけを書き並べます。何を見たいのかが他の人に伝わり、無駄なデータのやり取りも減らせるからです。

対象

FROM

どのテーブルから読むかを指定します。SELECT hostname FROM servers のように使います。

条件

WHERE

条件に合う行だけに絞り込みます。文字のデータは、通常シングルクォート(')で囲みます。

並び替え

ORDER BY

ASC は昇順、DESC は降順です。省略時は通常 ASC です。

重複除外

DISTINCT

重複する結果を1つにまとめます。環境名の一覧取得などに使います。

件数制限

LIMIT

返す行数を制限します。MySQL・PostgreSQL・SQLiteで利用できます。SQL Serverは TOP などを使います。

SELECT hostname, role, cpu_usage
FROM servers
WHERE environment = 'prod' AND cpu_usage >= 80
ORDER BY cpu_usage DESC
LIMIT 10;

このデータに対する実行結果(#sampleのサンプルデータで再現した例。架空のデータであり、実機で実行した記録ではありません):

実行結果例
hostnamerolecpu_usage
db-01db91.7
app-02app88.9
web-01web82.3

読み解き方:上のSQLを「本番環境(prod)でCPU使用率が80%以上のサーバーを、使用率が高い順に最大10台表示する」と日本語へ戻せれば理解できています。面接では「条件で絞り、並べ替え、件数を制限する流れを説明できる」と言えます。

よく使う条件:=<>(等しくない)、ANDORNOTIN (...)(かっこ内のどれかに一致)、BETWEEN A AND B(AからBまでの範囲に入る)、LIKE 'web-%'%は任意の文字列を表すので「web-」で始まる名前に一致)、IS NULL(値が入っていない)。NULL は値がない状態なので = NULL ではなく IS NULL を使います。

2. 数える・まとめる

かんたんに言うとここでは、1行ずつ見るのをやめて「同じ仲間ごとにまとめて数える」方法を学びます。まとめる単位を決めるのが GROUP BY、まとめたあとの結果を絞り込むのが HAVING です。

集計関数

COUNT / SUM

COUNT(*) は行数、SUM(column) は合計を求めます。

集計関数

AVG / MIN / MAX

平均・最小・最大を求めます。監視値の傾向確認に便利です。

グループ

GROUP BY

同じ値ごとに行をまとめます。環境別・役割別の台数集計に使います。

集計後の条件

HAVING

WHERE は、まとめる前の行を1行ずつ絞り込みます。HAVING は、GROUP BY でまとめたあとのグループを絞り込みます。

別名

AS

列やテーブルへ分かりやすい別名を付けます。AS server_count のように使います。

条件分岐

CASE

値に応じて表示を変えます。CPU使用率を「正常・警告・異常」に分類できます。CASE WHEN cpu_usage >= 90 THEN '異常' WHEN cpu_usage >= 70 THEN '警告' ELSE '正常' END のように使います。

SELECT environment, COUNT(*) AS server_count, AVG(cpu_usage) AS avg_cpu
FROM servers
GROUP BY environment
HAVING AVG(cpu_usage) >= 60
ORDER BY avg_cpu DESC;

このデータに対する実行結果(#sampleのサンプルデータで再現した架空の例):

実行結果例
environmentserver_countavg_cpu
prod577.10
stg166.40

devは平均CPU使用率が13.6と60未満のため、HAVINGで除外されて結果に含まれません。

3. 複数のテーブルをつなぐ

servers.owner_idowners.owner_id のように、両方の表に共通する列をキー(つなぎ合わせるための目印)として使います。こうして、別々の表に分けて保存したデータを1つの結果にまとめます。担当者を管理する owners テーブルは、次の列を持つものとします。

練習用ownersテーブルの列とサンプルデータ(架空)
owner_idowner_name
1インフラ担当
2アプリ担当
3監視担当
一致行

INNER JOIN

両方のテーブルに一致する行だけを返します。

左側を全件

LEFT JOIN

左側をすべて返し、右側に一致がなければ右側の列は NULL になります。担当未設定の発見に便利です。

結合条件

ON

どの列同士を一致させるかを書きます。この条件が足りないと、結果の行数が想定外に増えてしまいます。

SELECT s.hostname, s.environment, o.owner_name
FROM servers AS s
LEFT JOIN owners AS o ON s.owner_id = o.owner_id
WHERE s.environment = 'prod';

このデータに対する実行結果(#sample・上記ownersのサンプルデータで再現した架空の例):

実行結果例
hostnameenvironmentowner_name
web-01prodインフラ担当
web-02prodアプリ担当
db-01prodインフラ担当
app-02prodNULL
cache-01prod監視担当

app-02はowner_idNULLのため、LEFT JOINにより行は残りつつowner_nameNULLになります。これが演習3で探す「担当者未設定」の状態です。

確認点:結合する前と後で、行の件数を比べます。結合の失敗で件数が水増しされていないかを確かめるためです。想定より増えた場合は、結合に使ったキーの値が重複していないか、ON の条件が足りていないかを疑います。

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

追加

INSERT INTO

新しい行を追加します。列名と値の対応を明示します。

更新

UPDATE / SET

既存行の値を変更します。WHERE がないと全行更新になるため要注意です。

削除

DELETE FROM

行を削除します。WHERE がないと全行削除になります。

INSERT INTO servers (server_id, hostname, role, environment, cpu_usage)
VALUES (104, 'web-02', 'web', 'dev', 15.2);

UPDATE servers
SET last_checked_at = CURRENT_TIMESTAMP
WHERE server_id = 104;

DELETE FROM servers
WHERE server_id = 104 AND environment = 'dev';
安全手順:変更する前に、同じ WHERE を付けた SELECT を実行します。どの行が何件変わるのかを、先に自分の目で確認するためです。可能ならトランザクション(複数の変更をひとまとめにして、失敗したら取り消せる仕組み)の中で実行します。本番環境では、これに加えて作業の承認、バックアップの取得、切り戻し手順(元の状態へ戻す手順)の用意、作業ログの記録もそろえる必要があります。

5. テーブルと制約を定義する

かんたんに言うとデータを入れる前に、表の形と「入れてよい値の決まり」を先に決めます。この決まりを制約と呼びます。制約を付けておけば、間違ったデータがそもそも入らなくなります。

作成

CREATE TABLE

テーブル名、列名、データ型(その列に入る値の種類)、制約(値が満たすべき決まり)を決めて、新しい表を作ります。

変更

ALTER TABLE

列や制約を追加・変更します。製品によって対応範囲が異なります。ALTER TABLE servers ADD COLUMN memo VARCHAR(200); のように使います。

構造削除

DROP TABLE

テーブル構造とデータを削除します。復旧が難しい破壊的操作です。DROP TABLE servers; のように使います。

主キー

PRIMARY KEY

各行を一意に識別します。重複と NULL を許しません。

外部キー

FOREIGN KEY

別テーブルのキーを参照し、存在しない担当者IDなどを防ぎます。

値の規則

NOT NULL / UNIQUE / CHECK / DEFAULT

NOT NULLは必須入力、UNIQUEは重複禁止、CHECKは値が満たすべき条件、DEFAULTは初期値を表します。アプリ側だけでなく、データベース側でもこれらの決まりを守らせます。

CREATE TABLE owners (
    owner_id INTEGER PRIMARY KEY,
    owner_name VARCHAR(50) NOT NULL
);

CREATE TABLE servers (
    server_id INTEGER PRIMARY KEY,
    hostname VARCHAR(100) NOT NULL UNIQUE,
    role VARCHAR(30) NOT NULL,
    environment VARCHAR(10) NOT NULL CHECK (environment IN ('dev', 'stg', 'prod')),
    owner_id INTEGER,
    cpu_usage DECIMAL(5,2) DEFAULT 0,
    last_checked_at TIMESTAMP,
    FOREIGN KEY (owner_id) REFERENCES owners (owner_id)
);
主なデータ型の早見表
意味
INTEGER整数
VARCHAR(n)最大n文字までの可変長文字列(例:VARCHAR(100)は最大100文字)
DECIMAL(p,s)合計p桁のうち小数点以下s桁を持つ数値(例:DECIMAL(5,2)は999.99まで表現可能)
TIMESTAMP日付と時刻

6. トランザクションで変更をひとまとまりにする

複数の変更を「すべて成功」または「すべて取り消し」にする仕組みです。途中だけ反映される不整合を防ぎます。

BEGIN;

UPDATE servers SET environment = 'prod' WHERE server_id = 104;
SELECT server_id, hostname, environment FROM servers WHERE server_id = 104;

-- 問題なければ確定
COMMIT;
-- 問題があれば COMMIT の代わりに ROLLBACK;
ACIDの短い覚え方:トランザクションが備えるべき4つの性質のことです。すべて反映されるか、まったく反映されないかのどちらかになる(原子性)。決めたルールを壊さない(一貫性)。同時に動く作業どうしが干渉しない(独立性)。確定した変更は消えずに残る(永続性)。なお、CREATE TABLE などのDDLを実行すると、その時点で変更が自動的に確定されてしまう製品もあります。使う製品ごとに確認します。

7. 権限と安全なSQL

まず、SQLインジェクション(利用者が入力した文字を悪用して、想定外のSQLを実行させる攻撃)という典型的な事故の悪い例を見ます。利用者が入力した文字を、そのままSQL文へつなぎ合わせてはいけません。入力の内容しだいで、作った人が想定していないSQLが実行されてしまいます。

-- 悪い例:入力値をそのまま文字列連結している(アプリ側の疑似コード、実行しないでください)
sql = "SELECT * FROM servers WHERE hostname = '" + input + "'";

-- 利用者が hostname 欄に  ' OR '1'='1  と入力すると、
-- 実際に実行される文は次のようになってしまう
SELECT * FROM servers WHERE hostname = '' OR '1'='1';
-- WHERE条件が常に真になり、絞り込みたかった一部の行ではなく全行が返る
危険性:件数の想定外の増加だけでなく、連結の仕方によっては条件を偽装した更新・削除にもつながります。これを防ぐのが次のプレースホルダーです。
付与

GRANT

読み取りなど必要な権限だけを付与します。最小権限の原則を守ります。

取り消し

REVOKE

不要になった権限を取り消します。退職・異動・役割変更時も見直します。

安全な入力

プレースホルダー

利用者が入力した値を、SQLの文字列へ直接つなぎません。値を入れる場所だけを空けておいたSQLを先に用意する、プリペアドステートメント(準備済みのSQL)という仕組みを使います。空けておいた場所がプレースホルダーです。これでSQLインジェクションを防げます。

GRANT SELECT ON servers TO monitoring_user;
REVOKE UPDATE, DELETE ON servers FROM monitoring_user;

-- アプリ側の考え方(記法はライブラリで異なる)
SELECT hostname FROM servers WHERE server_id = ?;
秘密情報:パスワードや接続文字列(接続先やユーザー名をまとめた設定用の文字列)を、SQLファイル、ソースコード、Gitのリポジトリへ直接書きません。代わりに環境変数(実行時に外から渡す設定値)や、秘密情報管理の機能を使います。万一漏れたときは、認証情報をローテーション(新しいものへ入れ替えること)します。

8. インデックス・ビュー・実行計画

かんたんに言うと「なぜ遅いのか」を調べて速くする章です。インデックスは本の索引にあたる検索の近道、ビューはよく使うSQLに付けた名前、実行計画はデータベースがどう処理するつもりかを見せてくれる説明書です。

検索補助

CREATE INDEX

本の索引のように検索を速くします。ただし容量を使い、追加・更新・削除が遅くなることがあります。

仮想表

CREATE VIEW

よく使う問い合わせに名前を付けます。複雑さを隠せますが、必ず高速になるわけではありません。CREATE VIEW prod_servers AS SELECT hostname, cpu_usage FROM servers WHERE environment = 'prod'; のように使います。

計画確認

EXPLAIN

データベースがそのSQLをどう処理するつもりかを表示します。全件走査(表を先頭から最後まで全部読む方法)になっていないか、どのインデックスを使うか、どの順でテーブルをつなぐかを確認できます。なお、実際にSQLを実行して計測する形式もあり、その場合はサーバーへの負荷に注意します。

CREATE INDEX idx_servers_environment_role
ON servers (environment, role);

EXPLAIN
SELECT hostname FROM servers
WHERE environment = 'prod' AND role = 'web';

実行計画の出力例(製品によって列名や表示は異なります。架空の例であり、実機で実行した記録ではありません):

EXPLAIN出力例
idselect_typetabletypekeyrows
1SIMPLEserversrefidx_servers_environment_role12

typerefkeyには、実際に使われたインデックスの名前が入ります。ここに作成したインデックス名が表示され、推定行数(rows)が表全体の行数より少なければ、インデックスが使われたと判断できます。面接では「実行計画を見て、インデックスが使われたことを確認した」と説明できます。typeALLkeyが空の場合は全件走査(フルスキャン)です。

  1. 遅いSQL、実行時間、頻度、対象時間帯をログで特定する。
  2. EXPLAIN で実行計画と推定件数を確認する。
  3. 不要な列・行、関数、並び替え、結合条件を見直す。
  4. 必要なら候補インデックスを検証環境で比較する。
  5. 変更前後の時間、CPU、I/O、ロック、書き込み性能を記録する。

9. SQLキーワード早見表

SQLの目的別キーワード早見表
したいこと主なキーワード覚え方・注意
読むSELECT ... FROM列を選び、表から読む
絞るWHERE変更系では対象漏れに注意
並べるORDER BY ... ASC/DESC昇順/降順
重複を除くDISTINCT結果の重複を1つにする
まとめるGROUP BY / HAVING集計後の条件はHAVING
つなぐJOIN ... ONキーと件数を確認
追加INSERT INTO ... VALUES列と値の順番を合わせる
更新UPDATE ... SET ... WHERE先に同条件でSELECT
削除DELETE FROM ... WHEREバックアップと切り戻し
構造を作るCREATE TABLE型と制約を設計
確定/取消COMMIT / ROLLBACK変更を一まとまりにする
権限GRANT / REVOKE最小権限
計画を見るEXPLAIN製品ごとの出力を読む

10. サーバー運用でSQLエラーが起きたとき

  1. 影響を確認:誰が、いつから、どの画面・処理で失敗しているかを記録する。
  2. 接続を確認:データベースのサービスが動いているか、待受ポート(接続を受け付ける番号)、DNS(ホスト名からIPアドレスを調べる仕組み)、ファイアウォール(決めた条件で通信を許可・拒否する関所)、接続先の設定、TLS(通信の暗号化)、認証の順に確認する。
  3. エラーを保存:画面の表示だけで判断しない。発生時刻、SQLSTATE(SQLの標準エラーコード)、データベースのログ、アプリのログを採取する。パスワードなどの秘密情報は伏せる。
  4. 切り分け:構文、権限、ロック、容量、接続数、タイムアウト、実行計画、直前変更を順に確認する。
  5. 変更を管理:本番で思いつきのSQLを実行せず、承認、対象確認、バックアップ、切り戻し、作業記録をそろえる。
  6. 復旧後を確認:エラーが消えたことだけでなく、件数、整合性、監視、再発有無を確認し、手順へ反映する。
「接続できない」ときの代表例

DBサービス停止、ホスト名・ポート間違い、Firewall遮断、接続元制限、証明書期限、ユーザー停止、パスワード変更、接続数上限を確認します。

「遅い」ときの代表例

全件走査、インデックス不足、統計情報、ロック待ち、同時実行数、CPU・メモリ・ディスクI/O、ネットワーク、データ急増を確認します。

「更新できない」ときの代表例

権限、読み取り専用、制約違反、データ型、トランザクション、デッドロック、ディスク満杯、レプリカ接続を確認します。

11. 手を動かす演習

最初は本番データではなく、SQLiteなどの使い捨て学習環境で実行してください。各演習では「実行したSQL・予想した結果・実際に出た結果・気づいたこと」を記録します。記録が残っていれば、面接や報告のときに「何を試して、何が分かったのか」を自分の言葉で説明できます。

学習環境の用意の仕方は、主に次の2通りです。

  1. ブラウザで動くオンライン実行環境を使う:検索エンジンで「SQLite オンライン実行」などと調べると、インストール不要でSQLiteを試せる学習用サービスが見つかります。そこに下記のSQL文を貼り付けて実行します。
  2. 自分のPCに手元の環境を作る:PCにSQLite(sqlite3コマンドなど)を用意し、同じSQL文をローカルで実行してテーブルを作ります。

いずれの方法でも、まず次のSQL文をそのまま実行してください。#defineで説明したテーブル定義(ownersservers)と、#sampleのサンプルデータを再現できます。

CREATE TABLE owners (
    owner_id INTEGER PRIMARY KEY,
    owner_name VARCHAR(50) NOT NULL
);

INSERT INTO owners (owner_id, owner_name) VALUES
    (1, 'インフラ担当'),
    (2, 'アプリ担当'),
    (3, '監視担当');

CREATE TABLE servers (
    server_id INTEGER PRIMARY KEY,
    hostname VARCHAR(100) NOT NULL UNIQUE,
    role VARCHAR(30) NOT NULL,
    environment VARCHAR(10) NOT NULL CHECK (environment IN ('dev', 'stg', 'prod')),
    owner_id INTEGER,
    cpu_usage DECIMAL(5,2) DEFAULT 0,
    last_checked_at TIMESTAMP,
    FOREIGN KEY (owner_id) REFERENCES owners (owner_id)
);

INSERT INTO servers (server_id, hostname, role, environment, owner_id, cpu_usage, last_checked_at) VALUES
    (101, 'web-01', 'web', 'prod', 1, 82.3, '2026-08-28 09:50:00'),
    (102, 'web-02', 'web', 'prod', 2, 45.1, '2026-08-28 09:55:00'),
    (103, 'db-01', 'db', 'prod', 1, 91.7, '2026-08-28 10:00:00'),
    (104, 'db-02', 'db', 'dev', NULL, 15.2, '2026-08-20 08:00:00'),
    (105, 'app-01', 'app', 'stg', 2, 66.4, '2026-08-27 22:10:00'),
    (106, 'app-02', 'app', 'prod', NULL, 88.9, '2026-08-28 09:40:00'),
    (107, 'batch-01', 'batch', 'dev', 3, 12.0, '2026-08-15 07:30:00'),
    (108, 'cache-01', 'cache', 'prod', 3, 77.5, '2026-08-28 09:45:00');
注記:上記のINSERT文は#sampleの架空データを再現するためのものです。実際にこの内容で実行して動作確認した記録ではありません(NOT RUN)。まず自分の手元で実行し、このページの実行結果例と一致するかを確かめてください。

演習1:安全に読む

本番環境のサーバー名と役割を、サーバー名順で最大20件取得してください。

解答例
SELECT hostname, role
FROM servers
WHERE environment = 'prod'
ORDER BY hostname ASC
LIMIT 20;

演習2:集計する

環境ごとのサーバー台数と平均CPU使用率を求めてください。

解答例
SELECT environment, COUNT(*) AS server_count,
       AVG(cpu_usage) AS avg_cpu
FROM servers
GROUP BY environment;

演習3:未設定を探す

LEFT JOIN を使い、担当者が設定されていないサーバーを探してください。

解答例
SELECT s.hostname
FROM servers AS s
LEFT JOIN owners AS o ON s.owner_id = o.owner_id
WHERE o.owner_id IS NULL;

演習4:更新前確認

server_id 104の環境を変更する前に、対象を確認するSQLを書いてください。

解答例
SELECT server_id, hostname, environment
FROM servers
WHERE server_id = 104;

演習5:失敗を調べる

「アプリからDBへ接続できない」場合の確認順を、接続先、ネットワーク、認証、ログの観点で説明してください。

確認観点の例
  • 接続先:ホスト名・ポート番号・DB名・接続文字列に誤りがないかを確認する。
  • ネットワーク:DNS解決、Firewall・セキュリティグループ、経路上の到達性を確認する。
  • 認証:ユーザー名・パスワード、権限、証明書の期限、アカウントの有効期限を確認する。
  • ログ:アプリ側のエラーメッセージ、DBサーバー側の接続ログ、直前の設定変更履歴を確認する。

演習6:説明する

WHEREHAVINGDELETEDROP の違いを、初学者へ1文ずつ説明してください。

模範解答例
  • WHERE と HAVING:WHEREは集計前の行を1行ずつ絞り込む条件で、HAVINGGROUP BYでまとめた後のグループを絞り込む条件です。
  • DELETE と DROP:DELETEはテーブル構造を残したまま行(データ)だけを削除する操作で、DROP TABLEはテーブルの構造自体をデータごと削除する操作です。
完了条件:SQLが動くだけでなく、対象件数を予測し、結果を確認し、危険な操作と製品差を説明できたら合格です。

関連する学習内容

SQLはデータベースだけでなく、監視・障害調査・権限管理・バックアップ確認にもつながります。

スキル一覧へ戻る サーバー構築の学習を見る