sqlite3 コマンド入門 - ターミナルで SQL を試す最短手順

sqlite3 コマンド入門 - ターミナルで SQL を試す最短手順

この記事でできるようになること

  • `sqlite3 gym.db` でデータベースを開き、表を作ってデータを入れられる
  • `SELECT` / `WHERE` / `ORDER BY` / `LIMIT` / `COUNT(*)` で必要な行だけを取り出せる
  • SQL の結果を `sort` / `uniq` などのパイプにつなぎ、`.dump` でテキストに戻せる

前提知識(先に読むと理解しやすい記事)

この記事でわかること

  • sqlite3 で データベースを 1 個のファイルとして作る 方法がわかります
  • 表を作り、データを入れ、SELECT で 取り出す 最小の SQL が書けます
  • COUNT(*) と wc -l の数が ずれる理由 がわかります
  • SQL の結果を パイプで sort / uniq につなぐ 方法と、.dump でテキストに戻す方法がわかります

言葉の整理(先に取りちがえを防ぎます)

  • データベース:データをためて、あとから探したり数えたりできるしくみです。「DB」とも書きます。
  • 表:データを行と列で並べたものです。「テーブル」とも呼びます。Excel のシートに近いものです。
  • 行と列:表の横 1 本が行、縦 1 本が列です。「レコード」「カラム」とも呼びます。
  • SQL:データベースに命令する言葉です。「エスキューエル」と読みます。SQL で書いた 1 つの命令は「クエリ」とも呼びます。
  • SQLite と sqlite3:SQLite はソフトの名前、sqlite3 はそれを操作するコマンドの名前です。
  • CSV:値をカンマ(,)で区切って並べたテキストファイルです。
  • プロンプトコマンドの入力を待っている状態を示す記号(例 $ や #)。:「ここに打てます」という合図として行の先頭に出る記号です。ふだんは user@PC名:~$ のように行の最後が $ になります。記事の $ は打ちません。

前提(対象環境)

1. なぜ sqlite3 なのか?

結論: SQLite はサーバーがいらない。データベース全体が 1 個のファイルになるので、ls で見えるただのファイルとして扱える。

リナ: ライニー先輩、SQL を試してみたいです。でもデータベースって、サーバーを立てる準備が大変なんですよね。
ライニー先輩: 多くのデータベースはそうだね。でも SQLite はサーバーがいらない。データベース全体が 1 個のファイルになるんだ。
リナ: ファイル 1 個ですか。ls で見えるんですか。
ライニー先輩: 見えるよ。このあと作る gym.db は、ls -l でこう表示される。
$ ls -l gym.db
-rw-r--r-- 1 user user 8192 Oct 24 02:18 gym.db

まだ gym.db は無いので、この ls -l は 4 章のあとで試せます。所有者の名前と日時は環境ごとに変わります。

2. sqlite3 はどうやって入れる?

結論: Ubuntu と WSL は apt で入れる。Mac は最初から入っている。どちらも sqlite3 --version で確かめる。

Ubuntu / Debian 系の場合

$ sudo apt update
$ sudo apt install sqlite3
$ sqlite3 --version
3.45.1 2024-01-30 16:01:20 e876e51a0ed5c5b3126f52e532044363a014bc594cfefa87ffb5b82257ccalt1 (64-bit)

sudo は、管理者の権限でコマンドを実行するための言葉です。パスワードを聞かれたら、自分のログイン用のパスワードを打ちます。打っている文字は、画面に * も出ません。そのまま最後まで打って Enter を押します。最後の sqlite3 --version で出る最初の数字が版(バージョン)です。この例では 3.45.1 です。

Windows の場合:WSL(Windows の中で Linux を動かすしくみ)の Ubuntu を開きます。そのあとは上と同じ apt の手順です。WSL がまだ無い人は、WSL2 入門から始めてください。

Mac の場合:macOS には最初から sqlite3 が入っています。sqlite3 --version で確かめてください。macOS 付属の sqlite3 のままで、この記事はすべて試せます。

練習用のディレクトリファイルをまとめて整理する入れ物。Windows や macOS の「フォルダ」と同じもの。(フォルダのこと)を作ってから始めると安心です。

$ mkdir ~/sqlite-practice
$ cd ~/sqlite-practice

この記事のファイルは、すべてこの中に作ります。

3. sqlite3 を起動すると何が変わる?

結論: sqlite3 gym.db で起動すると、プロンプトが sqlite> に変わる。点で始まる命令は sqlite3 自身への指示になる。

ライニー先輩: さっそく起動しよう。sqlite3 のうしろに、データベースのファイル名を書く。
リナ: まだ gym.db は作っていません。大丈夫ですか。
ライニー先輩: 大丈夫。公式ドキュメントには「ファイルが無ければ自動で作る」と書いてある。正確には、表を作ったときにファイルができるよ。
$ sqlite3 gym.db
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite>
リナ: 最後の行が $ から sqlite> に変わりました。
ライニー先輩: 「今は sqlite3 の中にいる」という合図だよ。ここでは SQL と、. で始まる「ドットコマンド」を打つ。ドットコマンドは sqlite3 自身への指示なんだ。

まず使うのは次の 5 つです。

ドットコマンド すること
.tables 表の一覧を出す
.schema members members 表の作りを出す
.headers on 結果の 1 行目に列の名前を出す
.mode column 結果を列ごとにそろえて出す
.quit sqlite3 を終わり、$ に戻る

ドットコマンドの最後にはセミコロン(;)を付けません。SQL の最後には必ず ; を付けます。

3.54.0 以降の版では、プロンプトの見た目が変わります(変更履歴の 3.54.0 の項)。公式ドキュメントの例では SQLite-3.54 ex1.db-> です。打つ中身は同じです。

この記事のコード例では、先頭の $ や sqlite> は打ちません。そのうしろだけを打ちます。コピーボタンを使ったときは、貼り付けたあとで先頭の sqlite> (または $ )を消してから Enter を押します。

このあとの 4 章と 5 章は、sqlite> のまま続けて打ちます。途中でやめたときは .quit で終わり、もう一度 sqlite3 gym.db で入り直します。表とデータはファイルに残っています。4 章の CREATE TABLE と INSERT は打ち直しません(打ち直すと同じ行が増えます)。.headers on と .mode column は消えるので、5 章から再開するときはこの 2 つをもう一度打ちます。

4. 表を作ってデータを入れるには?

結論: CREATE TABLE で表の形を決めて、INSERT で 1 行ずつデータを入れる。SQL の最後には必ず ; を付ける。

ライニー先輩: ジムの会員表を作ろう。列は id(番号)、name(名前)、city(住んでいる街)、age(年齢)の 4 つだ。
リナ: Excel で 1 行目に見出しを書くのと同じ感じですね。
sqlite> CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER);
sqlite> INSERT INTO members (name, city, age) VALUES ('Pip', 'Tokyo', 24);
sqlite> INSERT INTO members (name, city, age) VALUES ('Momo', 'Osaka', 31);
sqlite> INSERT INTO members (name, city, age) VALUES ('Kai', 'Tokyo', 19);

うまくいくと、何も表示されずに次の sqlite> が出ます。

  • INTEGER は整数、TEXT は文字(文字列)という意味です
  • id INTEGER PRIMARY KEY にしたので、id には 1、2、3 と番号が自動で入ります
  • 文字は 'Tokyo' のようにシングルクォート(')で囲みます

できたかどうかは、ドットコマンドで確かめます。

sqlite> .tables
members
sqlite> .schema members
CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER);
リナ: .tables が ls、.schema が cat みたいですね。
ライニー先輩: いい見方だね。.tables で表の名前を見て、.schema で表の作りを読むんだ。

; を忘れて Enter を押すと、プロンプトが ...> に変わります。「続きを待っている」という合図です。; だけ打って Enter を押せば実行されます。

5. 必要な行だけ取り出すには?

結論: WHERE でしぼり、ORDER BY で並べ、LIMIT で切る。grep・sort・head と同じ役わりだ。

まず、表の中身を全部出してみます。* は「すべての列」という意味です。

sqlite> SELECT * FROM members;
1|Pip|Tokyo|24
2|Momo|Osaka|31
3|Kai|Tokyo|19
リナ: 出ましたけど、| で区切られていて読みにくいです。どれが何の列かもわかりません。
ライニー先輩: そこで .headers on と .mode column を使う。列の名前が出て、縦がそろうよ。
sqlite> .headers on
sqlite> .mode column
sqlite> SELECT * FROM members;
id  name  city   age
--  ----  -----  ---
1   Pip   Tokyo  24
2   Momo  Osaka  31
3   Kai   Tokyo  19

3.53.0 以降の版をターミナルで使うと、最初から枠線つきの表で表示されます(公式ドキュメントの https://sqlite.org/climode.html と、変更履歴の 3.53.0 の項より)。新しい版でも、この記事では .headers on と .mode column を打ってください。

5-1. WHERE で行をしぼる(grep に近い)

sqlite> SELECT name, age FROM members WHERE city = 'Tokyo';
name  age
----  ---
Pip   24
Kai   19

grep Tokyo と同じように、条件に合う行だけが出ます。

5-2. ORDER BY で並べる(sort に近い)

sqlite> SELECT name, age FROM members ORDER BY age DESC;
name  age
----  ---
Momo  31
Pip   24
Kai   19

DESC は大きい順です。sort -rn と同じ向きです。DESC を付けなければ小さい順になります。

5-3. LIMIT で件数を切る(head に近い)

sqlite> SELECT name, age FROM members ORDER BY age DESC LIMIT 2;
name  age
----  ---
Momo  31
Pip   24

head -n 2 と同じように、先頭の 2 行だけが出ます。

6. 数を数えると何が起きる?

結論: COUNT(*) は表の行を数える。CSV に書き出して wc -l で数えると、列の名前の行が 1 行ぶん多く数えられる。

sqlite> SELECT COUNT(*) FROM members;
COUNT(*)
--------
3
リナ: 3 人ですね。CSV にして、wc -l でも数を確かめたいです。
ライニー先輩: .mode csv で CSV の形にして、.once で「次の 1 回の結果だけ」をファイルに書き出そう。
sqlite> .mode csv
sqlite> .once members.csv
sqlite> SELECT * FROM members;
sqlite> .quit
$ wc -l members.csv
4 members.csv

.quit でプロンプトが $ に戻ったので、最後の wc -l はふだんの Linux のコマンドとして動いています。

リナ: えっ、4 行です。会員は 3 人なのに、1 人増えています。エラーも出ていないのに、数が合いません。
ライニー先輩: 中身を見てみよう。
$ cat members.csv
id,name,city,age
1,Pip,Tokyo,24
2,Momo,Osaka,31
3,Kai,Tokyo,19
リナ: あ、1 行目が id,name,city,age です。さっき .headers on にしたから、列の名前も書き出されたんですね。
ライニー先輩: そのとおり。wc -l はファイルの行を、COUNT(*) は表の行を数える。数えているものがちがうんだ。
リナ: コマンドが通っても、数が正しいとは限らないんですね。ちがう方法で数えて、くらべるのが大事だとわかりました。

列の名前の行を除いて数えるには、tail -n +2(2 行目から最後まで出す)を使います。

$ tail -n +2 members.csv | wc -l
3

これで COUNT(*) の 3 と一致しました。なお、.headers on などの設定は sqlite3 を終わると元に戻ります。

7. SQL の結果をパイプにつなぐには?

結論: sqlite3 ファイル名 "SQL" と書くと、1 回だけ実行してすぐ終わる。結果は普通の文字なので、sort や uniq にそのままつなげる。

リナ: 毎回 sqlite3 に入って .quit で出るのは、少し手間です。
ライニー先輩: ファイル名のうしろに SQL を 1 つ書けば、その場で実行して終わる(公式ドキュメントより)。結果はただの文字だから、パイプにつなげるよ。
$ sqlite3 gym.db "SELECT city FROM members" | sort | uniq -c
      1 Osaka
      2 Tokyo
  • sqlite3 gym.db "SELECT city FROM members" が街の名前を 1 行ずつ出します
  • sort が同じ街を隣どうしに集めます
  • uniq -c が同じ行の数を数えます

この書き方では .headers on を打っていないので、列の名前の行は出ません。公式ドキュメントによると、結果は「list モード」(| 区切りの形)で出ます。

7-1. 仮想ターミナルの対話モードで試す

3 章の sqlite> が出ている状態を「対話モード」と呼びます。1 行ずつ打って、その場で結果を見る使い方です。

本サイトの仮想ターミナルでも、対話モードを試せます。課題「会員の数を数える」を開き、次の順に打ちます。先頭の $ や sqlite> は打ちません。

$ sqlite3 gym.db
sqlite> SELECT COUNT(*) FROM members;
(課題用の gym.db に入っている会員の数が 1 行出る)
sqlite> .quit

仮想ターミナルの gym.db は課題用に用意したものです。出る数は、この記事の 3 人とはちがいます。正しく数えられると、課題の完了が表示されます。7 章の 1 回だけ実行する書き方(sqlite3 gym.db "SELECT COUNT(*) FROM members;")でも、同じように完了します。仮想ターミナルのプロンプトは、版によらず sqlite> です。

8. データベースをテキストに戻すには?

結論: .dump はデータベース全体を SQL のテキストにする。そのテキストを sqlite3 に読ませると、同じデータベースを作り直せる。

> は確認なしで上書きする

> は、同じ名前のファイルがすでにあると、中身を消して書き直します。GUI のように「上書きしますか?」とは聞いてくれません。6 章の .once も同じように上書きします。打つ前に ls で同じ名前のファイルが無いか確かめ、練習用のディレクトリの中で試してください。

$ sqlite3 gym.db .dump > backup.sql
$ cat backup.sql
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE members (id INTEGER PRIMARY KEY, name TEXT, city TEXT, age INTEGER);
INSERT INTO members VALUES(1,'Pip','Tokyo',24);
INSERT INTO members VALUES(2,'Momo','Osaka',31);
INSERT INTO members VALUES(3,'Kai','Tokyo',19);
COMMIT;
リナ: さっき打った CREATE TABLE と INSERT が並んでいます。
ライニー先輩: データベースの中身を、作り直すための SQL として書き出したんだ。これを新しいファイルに読ませてみよう。

BEGIN TRANSACTION と COMMIT は、あいだの SQL をひとまとまりとして実行するための行です。PRAGMA の行も、sqlite3 が自動で付けた設定の行です。今は読み飛ばしてかまいません。

$ sqlite3 new.db < backup.sql
$ sqlite3 new.db "SELECT * FROM members"
1|Pip|Tokyo|24
2|Momo|Osaka|31
3|Kai|Tokyo|19

< は、ファイルの中身をコマンドに読ませる記号です。backup.sql の SQL が上から順に実行され、new.db に同じ表ができました。

9. よくあるミスと対処

結論: つまずきはセミコロン・クォート・大文字小文字・ファイル名で多い。エラーは文を読む。出ないのに結果が変なら SELECT * で中身を見る。

症状 原因 確認・対処
Parse error: near "sqlite": syntax error 先頭の sqlite> までコピーした sqlite> を消して打ち直す
プロンプトが ...> のまま SQL の最後の ; が無い ; だけ打って Enter を押す
Parse error: no such column: Tokyo 文字を ' で囲んでいない WHERE city = 'Tokyo' のように囲む
WHERE city = 'tokyo' で何も出ない 文字の比べ方は大文字と小文字を区別する 表に入っている書き方(Tokyo)に合わせる
起動してすぐ .quit したら gym.db が無い 3.45.1 では何もしないとファイルが作られない 表を作ってから .quit し、ls -l で確かめる
table members already exists のあと人数が増えた INSERT を 2 回実行した DELETE FROM members WHERE id > 3; で消す。または gym.db を作り直す
new.db < backup.sql で table members already exists new.db にもう同じ表がある 別の名前のファイル(例: new2.db)に読ませる

'tokyo' の例は、エラーにならずに 0 件が返ります。結果が空のときは、まず SELECT * FROM members; で表に入っている書き方を見てください。

10. ミニ課題:実際にやってみよう

結論: 並べる・数える・パイプでつなぐ、の 3 つを自分の手で試す。答えは折りたたみの中にある。

課題1:若い順に並べよう

やること:sqlite3 gym.db で入り、.headers on と .mode column を打とう。そのあと、名前と年齢を年齢の小さい順に全員分出してみよう。

ヒント1(方向づけ)を見る

「並べる」ための言葉を SELECT のうしろに足します。大きい順のときに付けた言葉は、今回は付けません。

ヒント2(コマンド名)を見る

ORDER BY age を使います。DESC は付けません。

答えを見る
sqlite> SELECT name, age FROM members ORDER BY age;
name  age
----  ---
Kai   19
Pip   24
Momo  31

課題2:Osaka の会員を数えよう

やること:city が Osaka の会員が何人いるかを、SQL だけで数えてみよう。

ヒント1(方向づけ)を見る

「数える」と「条件でしぼる」の 2 つを組み合わせます。

ヒント2(コマンド名)を見る

SELECT COUNT(*) に WHERE city = 'Osaka' を足します。

答えを見る
sqlite> SELECT COUNT(*) FROM members WHERE city = 'Osaka';
COUNT(*)
--------
1

課題3:パイプで Tokyo の人数を数えよう

やること:まず .quit で $ に戻ろう。そのあと sqlite3 の中に入らずに、Tokyo の会員の名前を出し、その行数を Linux のコマンドで数えてみよう。

ヒント1(方向づけ)を見る

プロンプトが $ になっているか確かめます。sqlite3 を 1 回だけ実行して終わる書き方を使います。その結果を、行を数えるコマンドに渡します。

ヒント2(コマンド名)を見る

sqlite3 gym.db "SELECT ..." のうしろに | wc -l をつなぎます。

答えを見る
$ sqlite3 gym.db "SELECT name FROM members WHERE city = 'Tokyo'" | wc -l
2

この書き方では列の名前の行が出ないので、wc -l の数がそのまま人数になります。

11. 振り返り

リナ: 整理します。SQLite はサーバーがいらなくて、データベースは gym.db という 1 個のファイルでした。
ライニー先輩: そうだね。表は CREATE TABLE で作って、INSERT で入れた。
リナ: WHERE は grep、ORDER BY は sort、LIMIT は head に近いです。wc -l が 1 多かったのは、列の名前の行のせいでした。
ライニー先輩: そこがいちばん大事だよ。ちがう方法で数をくらべると、ずれに気づける。.dump でテキストに戻せることも覚えておこう。

今日の 3 行まとめ

  1. SQLite はサーバー不要で、データベースは ls で見える 1 個のファイルになる
  2. SELECT / WHERE / ORDER BY / LIMIT は grep / sort / head と対応している
  3. COUNT(*) と wc -l は数えるものがちがう。CSV の 1 行目(列の名前)に気をつける

まとめ:次に読む

この記事を共有

次の一手