2026年6月26日
2026年6月26日
SQLiteの基本操作とコマンド一覧(sqlite3のドットコマンド・SQL・バックアップまで)
SQLite は、データベース全体を 1 つのファイルに保存する軽量なデータベースで、サーバーを立てずに sqlite3 コマンドだけで操作できます。この記事では、sqlite3 の起動から、よく使うドットコマンドの一覧、テーブル作成・検索・更新の SQL、CSV の入出力、バックアップまでを、実際にサーバー上で作業する順に説明します。読み終えるころには、手元の .db ファイルの中身を確認し、安全に書き換えてバックアップを取れるようになります。
SQLite の特徴と向いている用途
MySQL や PostgreSQL がサーバープロセスとして動き、ネットワーク越しに接続するのに対し、SQLite はアプリケーションがファイルを直接読み書きします。
- 向いている用途: 設定やキャッシュの保存、小〜中規模のツールのデータ、ログの一時集計、開発・検証用のデータベース
- 向いていない用途: 多数のプロセスが同時に書き込むサービス、複数サーバーから同じデータを使う構成
書き込みはデータベース全体で一度に 1 つずつ処理されます。読み取りは同時に行えますが、書き込みが多いサイトのデータベースには MySQL などを選びます。
WordPress は公式には MySQL / MariaDB を前提としていますが、SQLite で動かすための「SQLite Database Integration」プラグインがあり、WordPress Playground などの検証環境でも SQLite が使われています。本番サイトでの利用は、対応状況やプラグインとの相性を確認したうえで慎重に判断してください。
インストールと起動
Ubuntu / Debian では次のように入れます。
sudo apt install sqlite3
sqlite3 --version
データベースファイルを指定して起動します。ファイルが存在しなければ、最初に書き込んだ時点で作られます。
sqlite3 site.db
sqlite> というプロンプトが出たら、SQL かドットコマンドを入力します。SQL の文は ; で終わるまで実行されません。入力の途中で ...> という表示が続くときは、; の付け忘れです。終了は .quit です。
使える機能は版によって違います(2026年10月現在、3.4x 系が配布されています)。OS のパッケージは古い版のことがあるため、後述の新しい機能を使う前に sqlite3 --version で確かめます。
ドットコマンド一覧
. で始まるのは SQL ではなく、sqlite3 コマンド自体の操作です。行末に ; は付けません。
| コマンド | 用途 |
|---|---|
.help |
ドットコマンドの一覧と説明を表示 |
.open ファイル名 |
別のデータベースファイルを開く |
.databases |
開いているデータベースとファイルの場所を表示 |
.tables |
テーブルの一覧 |
.schema テーブル名 |
テーブルの定義(CREATE 文)を表示 |
.indexes テーブル名 |
インデックスの一覧 |
.headers on |
結果に列名を表示 |
.mode 形式 |
出力形式を変更(column・box・csv・json・markdown など) |
.import ファイル テーブル |
CSV などをテーブルに取り込む |
.output ファイル / .once ファイル |
結果をファイルへ出力(.once は次の 1 回だけ) |
.read ファイル |
SQL を書いたファイルを実行 |
.dump |
データベース全体を SQL 文として出力 |
.backup ファイル |
データベースを別ファイルへバックアップ |
.timer on |
各 SQL の実行時間を表示 |
.quit |
終了 |
見やすさのため、作業の最初に次の 2 つを入れておくと便利です。box 形式は比較的新しい版で追加されたもので、古い版では column を使います。
.headers on
.mode box
テーブルを作る
SQLite の型は柔軟で、列に宣言した型と違う種類の値も、変換できなければそのまま保存されます(型アフィニティ)。意図しない値が混ざるのを防ぎたい場合は、3.37.0 以降で使える STRICT テーブルにします。
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'draft',
views INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
) STRICT;
CREATE INDEX idx_posts_status ON posts(status);
押さえておきたい点は次のとおりです。
INTEGER PRIMARY KEYの列は内部の行番号(rowid)と同じものになり、値を省略すると自動で採番されます。AUTOINCREMENTは、削除した番号を再利用させたくない場合にだけ付けます。- SQLite には日付型がありません。ISO 8601 形式の文字列(
2026-10-18 09:00:00)か、UNIX 時間の整数で保存します。datetime('now')は UTC を返すため、日本時間が欲しいときはdatetime('now', 'localtime')を使います。 - 外部キー制約(
REFERENCES)は、既定では無効です。接続のたびにPRAGMA foreign_keys = ON;を実行しないと、制約が効きません。
データの追加・検索・更新・削除
基本の 4 操作です。
INSERT INTO posts (title, status) VALUES ('SQLite入門', 'publish');
INSERT INTO posts (title) VALUES ('下書きの記事');
SELECT id, title, status, created_at
FROM posts
WHERE status = 'publish'
ORDER BY created_at DESC
LIMIT 10;
UPDATE posts SET views = views + 1 WHERE id = 1;
DELETE FROM posts WHERE status = 'draft';
UPDATE と DELETE で WHERE を書き忘れると、全行が対象になります。大事なデータを書き換えるときは、トランザクションの中で実行し、結果を確かめてから確定します。
BEGIN;
DELETE FROM posts WHERE status = 'draft';
SELECT count(*) FROM posts; -- 残った件数を確認
COMMIT; -- 問題があれば ROLLBACK;
トランザクションは、大量の INSERT を速くする効果もあります。1 件ずつ確定させるより、BEGIN と COMMIT でまとめたほうがずっと短時間で終わります。
「あれば更新、なければ追加」は、ON CONFLICT(UPSERT、3.24.0 以降)で書けます。対象の列に UNIQUE 制約か主キーが必要です。
CREATE TABLE page_views (path TEXT PRIMARY KEY, views INTEGER NOT NULL);
INSERT INTO page_views (path, views) VALUES ('/about/', 1)
ON CONFLICT(path) DO UPDATE SET views = views + 1;
列の追加は ALTER TABLE posts ADD COLUMN excerpt TEXT; でできます。列の削除(DROP COLUMN)は 3.35.0 以降で使えますが、インデックスや制約に使われている列は削除できません。
CSV の取り込みと書き出し
CSV を取り込むときは、.import に --csv を付けます。テーブルが存在しない場合は 1 行目が列名として使われ、既存のテーブルに入れる場合は --skip 1 で見出し行を飛ばします。これらのオプションは古い版にはないため、使えない場合は .mode csv に切り替えてから .import を実行します。
.import --csv --skip 1 posts.csv posts
結果を CSV に書き出すには、出力形式と出力先を指定してから SELECT を実行します。
.headers on
.mode csv
.once export.csv
SELECT id, title, views FROM posts ORDER BY views DESC;
シェルスクリプトから使う場合は、SQL を引数で渡せます。読むだけの処理なら -readonly を付けておくと、誤って書き換える心配がありません。
sqlite3 -readonly -header -csv site.db "SELECT id, title FROM posts;" > posts.csv
バックアップと復元
アプリケーションが書き込んでいる最中に cp でファイルをコピーすると、壊れたコピーができることがあります。また、WAL モードでは site.db-wal などの付随ファイルにも未反映のデータがあります。バックアップは SQLite の機能で取ります。
# 稼働中でも一貫したコピーを作る
sqlite3 site.db ".backup 'backup/site-20261018.db'"
# 空き領域を詰めたコピーを作る(3.27.0 以降)
sqlite3 site.db "VACUUM INTO 'backup/site-compact.db'"
# SQL 文として書き出し、別ファイルに復元する
sqlite3 site.db .dump > site.sql
sqlite3 restored.db < site.sql
バックアップを取ったら、PRAGMA integrity_check; で中身が壊れていないかを確かめます。問題がなければ ok と表示されます。
よく使う PRAGMA と、つまずきやすいエラー
PRAGMA は SQLite の動作設定や情報取得のための命令です。
PRAGMA table_info(posts); -- 列の定義を一覧
PRAGMA journal_mode = WAL; -- 読み書きの同時実行に強いモードへ(設定はファイルに残る)
PRAGMA busy_timeout = 5000; -- ロック中は最大5秒待つ(接続ごとの設定)
PRAGMA foreign_keys = ON; -- 外部キー制約を有効化(接続ごとの設定)
database is locked: 別のプロセスが書き込み中のときに出ます。アプリケーション側で busy_timeout を設定する、WAL モードにする、長いトランザクションを開いたままにしない、の順に見直します。
attempt to write a readonly database: ファイルだけでなく、ファイルを置いたディレクトリにも書き込み権限が必要です。SQLite は同じディレクトリに一時ファイルを作るためです。Web サーバーのユーザー(www-data など)から書き込む場合は、ディレクトリの所有者と権限を確認します。
検索が遅い: EXPLAIN QUERY PLAN SELECT ...; を実行し、SCAN posts(全件走査)と出ていれば、条件に使っている列にインデックスを作ります。
Web サーバー上で使うときの注意
データベースファイルを公開ディレクトリに置くと、URL を知られただけでファイルごとダウンロードされるおそれがあります。ファイルはドキュメントルートの外に置くのが原則です。やむを得ず公開ディレクトリの下に置く場合は、Web サーバーの設定でそのファイルやディレクトリへのアクセスを拒否します。Apache の既定設定では .ht で始まるファイルへのアクセスが拒否されることが多い一方、Nginx では明示的に deny を書かない限り配信されてしまう点に注意します。PHP から使う場合は PDO の SQLite ドライバーを使い、利用者から受け取った値は SQL 文に直接埋め込まず、プリペアドステートメントで渡します。
まとめ
- SQLite はファイル 1 つのデータベース。
sqlite3 ファイル名で開き、.quitで終わる .tables・.schema・.headers on・.modeで中身を確認し、.import/.onceで CSV を入出力する- 型を厳密にしたいなら
STRICTテーブル。日付は文字列か整数で保存し、外部キーはPRAGMA foreign_keys = ONで有効化する - 書き換えは
BEGIN〜COMMITの中で確認してから確定する - バックアップは
cpではなく.backupかVACUUM INTOで取り、integrity_checkで確かめる - データベースファイルは公開ディレクトリの外に置く