【Mac向け】SQLite入門:インストールから基本操作まで


【Mac向け】SQLite入門:インストールから基本操作まで

データベースの世界へようこそ!この記事では、Macユーザーの皆さんに向けて、軽量ながら強力なデータベースシステム「SQLite」の基本的な使い方をゼロから丁寧に解説します。データベースの概念に初めて触れる方でも理解できるよう、インストール(Macには標準で入っています!)から、データベースの作成、テーブルの設計、データの操作、そしてGUIツールの利用までを網羅的にカバーします。

この記事で学べること:

  • SQLiteとは何か、その特徴とMacで使うメリット
  • MacにプリインストールされているSQLiteの確認方法
  • SQLiteコマンドラインツール(sqlite3)の基本的な使い方
  • データベースファイルとテーブルの作成・管理方法
  • データの挿入、参照、更新、削除といった基本的なSQL操作
  • より高度なSQL操作(結合、集計など)の基礎
  • GUIツールを使ったデータベース操作の紹介
  • よくある疑問や問題の解決方法

さあ、一緒にSQLiteの世界を探検しましょう!

1. SQLiteとは何か? その特徴とMacで使うメリット

まずは、SQLiteがどのようなデータベースシステムなのか、その特徴を見ていきましょう。

1.1 SQLiteの概要

SQLiteは、C言語で書かれた軽量なリレーショナルデータベース管理システム(RDBMS)です。最大の特徴は、サーバーを必要としないことです。一般的なRDBMS(MySQL, PostgreSQL, SQL Serverなど)は、データベースサーバーを起動し、クライアントアプリケーションがネットワーク経由でサーバーに接続してデータを操作します。しかし、SQLiteはデータベース全体が単一のファイルとして保存されます。このファイルに対して、アプリケーションが直接アクセスしてデータを読み書きします。

「サーバーレス」であること、そして「ファイルベース」であることが、SQLiteの最大のアイデンセティティです。

1.2 SQLiteの主な特徴

SQLiteは、その設計思想から来るユニークな特徴をいくつか持っています。

  • 軽量かつ高速: コードベースが小さく、オーバーヘッドが少ないため、組み込みシステムや小規模なアプリケーションに適しています。
  • 設定不要: データベースファイルを開くだけで利用開始できます。特別な設定や管理作業はほとんど必要ありません。
  • トランザクション対応: ACID特性(原子性、一貫性、独立性、永続性)を満たすトランザクションをサポートしており、データの整合性が保証されます。
  • 標準SQL準拠: 多くの標準SQL92構文をサポートしています。基本的なSQL文法(SELECT, INSERT, UPDATE, DELETE, CREATE TABLEなど)は他のRDBMSと共通しています。
  • クロスプラットフォーム: Windows, macOS, Linux, iOS, Androidなど、様々なOSや環境で動作します。
  • パブリックドメイン: 商用・非商用を問わず、完全に無料で自由に利用・配布できます。

1.3 なぜMacでSQLiteを使うのか?

Macユーザーにとって、SQLiteは非常に便利なツールです。その理由はいくつかあります。

  • macOSにプリインストール: 最も大きな理由の一つです。macOSには標準でSQLiteが搭載されています。追加のインストール作業なしに、ターミナルを開いてすぐに使い始めることができます。これは学習コストや導入の手間を大幅に削減します。
  • 開発やプロトタイピングに最適: 大規模なデータベースシステムを立てる必要がないため、ちょっとしたツールの開発、データ分析、プロトタイピングなど、手軽にデータベースを使いたい場合に非常に便利です。Python, Swift, Objective-Cなど、様々なプログラミング言語から容易に利用できます。
  • 学習用: データベースの概念やSQLを学ぶ上で、SQLiteは最適な入門ツールです。サーバー管理の複雑さを気にすることなく、純粋にデータベースの操作に集中できます。
  • ローカルデータ管理: アプリケーションの設定情報、キャッシュデータ、オフラインで使用するデータなど、ローカル環境でデータを管理する用途に広く使われています。iTunes、Skype、Firefox、Chromeといった多くのソフトウェアが内部でSQLiteを使用しています。

このように、MacユーザーにとってSQLiteは、手軽に始められる、学習に適している、そして様々な用途に活用できる非常に魅力的なデータベースシステムです。

2. SQLiteのインストール(Mac)

良いニュースです!macOSには、ほとんどの場合、SQLiteが標準でプリインストールされています。そのため、特別なインストール作業は不要です。

2.1 SQLiteのバージョン確認

まずは、お使いのMacにSQLiteがインストールされているか、そしてそのバージョンを確認してみましょう。

  1. ターミナルを開く: Applications -> Utilities -> Terminal を開くか、Spotlight検索(Cmd + Space)で「Terminal」と入力して開きます。
  2. コマンド入力: ターミナルが表示されたら、以下のコマンドを入力してEnterキーを押します。

    bash
    sqlite3 --version

    または

    bash
    sqlite3 -version

    実行例:

    % sqlite3 --version
    3.39.5 2022-10-14 20:58:05 c4c16322b466f5445f21e7b1459a846539f79f18a27afefc0c572a8a9d50d410

    このようにバージョン情報が表示されれば、SQLiteは正しくインストールされています。表示されるバージョン番号は、macOSのバージョンによって異なります。

2.2 Homebrewを使ったインストール/アップグレード(任意)

macOSにプリインストールされているSQLiteは、最新バージョンではない場合があります。もし最新機能を使いたい場合や、特定のバージョンが必要な場合は、パッケージマネージャーのHomebrewを使ってSQLiteをインストールまたはアップグレードすることができます。

Homebrewがインストールされていない場合は、先にHomebrewの公式サイト(https://brew.sh/index_ja)を参照してインストールしてください。

  1. Homebrewを使ってSQLiteをインストール(またはアップグレード): ターミナルで以下のコマンドを実行します。

    bash
    brew install sqlite

    または、既にインストールされている場合はアップグレードします。

    bash
    brew upgrade sqlite

    Homebrewでインストールした場合、Homebrewが管理するSQLiteの実行ファイル(通常 /usr/local/bin/sqlite3/opt/homebrew/bin/sqlite3 など)が、システムのSQLite(/usr/bin/sqlite3)よりも優先して使用されるように、環境変数のPATHが設定されているはずです。念のため、インストール後に再度 sqlite3 --version を実行して、Homebrewでインストールしたバージョンが表示されることを確認してください。

    注意: 通常の学習や基本的な使用には、macOSにプリインストールされているバージョンで十分です。Homebrewを使ったインストールは、特定の理由がある場合のみ検討すれば良いでしょう。この記事では、特にHomebrew版と区別せず、sqlite3 コマンドとして説明を進めます。

これで、MacでSQLiteを使う準備が整いました。次は、実際にコマンドラインツールを使ってデータベースを操作してみましょう。

3. SQLiteコマンドラインツールの起動と終了

SQLiteのコマンドラインツールは sqlite3 という名前です。ターミナルからこのコマンドを実行して、SQLiteのインタラクティブシェルに入り、SQLコマンドやSQLite独自のコマンド(ドットコマンド)を実行します。

3.1 ターミナルを開く

先ほどバージョン確認のために開いたターミナルを使用します。閉じている場合は、再度開いてください。

3.2 sqlite3 コマンドの使い方

sqlite3 コマンドの基本的な使い方は以下の通りです。

bash
sqlite3 [データベースファイル名]

  • データベースファイル名なしで起動:

    bash
    sqlite3

    このコマンドを実行すると、新しいデータベースファイルは作成されず、メモリ上に一時的なデータベースが作成されます。.databases コマンドを実行すると、データベース名が main と表示されますが、ファイル名は表示されません。このモードで操作した内容は、.quit または Ctrl+Dsqlite3 を終了すると失われます。簡単な試用やSQLの練習に使えます。

  • データベースファイル名を指定して起動:

    bash
    sqlite3 mydatabase.db

    このコマンドを実行すると、以下の動作をします。
    * 指定した名前(例: mydatabase.db)のファイルがカレントディレクトリに存在する場合、そのデータベースを開きます。
    * 指定した名前のファイルがカレントディレクトリに存在しない場合、新しいデータベースファイルを作成し、それを開きます。

    データベースファイル名は .db.sqlite といった拡張子を付けるのが一般的ですが、必須ではありません。好きな名前を付けられます。

    ファイルパスを指定することも可能です。

    bash
    sqlite3 /Users/yourusername/Documents/mydatabase.db

    存在しないディレクトリを指定した場合、エラーになります。事前にディレクトリは作成しておく必要があります。

3.3 SQLiteシェルの起動

例として、test.db という名前のデータベースファイルを作成(または開く)してみましょう。ターミナルで以下のコマンドを実行します。

bash
sqlite3 test.db

実行すると、以下のようなプロンプトが表示され、SQLiteのインタラクティブシェルに入ります。

SQLite version 3.39.5 2022-10-14 20:58:05
Enter ".help" for usage hints.
sqlite>

これで、sqlite> プロンプトが表示され、SQLiteのコマンドやSQL文を入力できるようになりました。

3.4 SQLiteシェルの基本コマンド(ドットコマンド)

sqlite> プロンプトでは、SQL文の他に、. (ドット) から始まるSQLite独自のコマンドを実行できます。これらは「ドットコマンド」と呼ばれ、データベースの管理やシェルの設定などに使われます。

いくつか重要なドットコマンドを紹介します。

  • .help: 利用可能なドットコマンドの一覧と簡単な説明を表示します。困ったときはまずこれを実行しましょう。

    sqlite
    sqlite> .help

    実行例(一部):
    .auth ON|OFF Show authorizer callbacks
    .backup ?DB? FILE Backup DB (default "main") to FILE
    ... (省略) ...
    .databases List names and files of attached databases
    ... (省略) ...
    .quit Exit sqlite3 program
    ... (省略) ...
    .schema ?PATTERN? Show the CREATE statements for tables matching PATTERN
    .tables ?PATTERN? List names of tables matching PATTERN
    ... (省略) ...
    .mode MODE ?TABLE? Set output mode where MODE is one of:
    csv Comma-separated values
    columns Left-aligned columns. (See .width)
    ... (省略) ...
    list Separator is "|"
    ... (省略) ...
    .headers ON|OFF Turn display of headers on or off
    ... (省略) ...

  • .quit: SQLiteシェルを終了し、ターミナルのプロンプトに戻ります。Ctrl+D でも終了できます。

    sqlite
    sqlite> .quit

  • .databases: 現在開いているデータベース(アタッチされているデータベース)の一覧と、それに対応するファイルパスを表示します。main は通常、起動時に指定したファイルまたはメモリ上のデータベースです。

    sqlite
    sqlite> .databases

    実行例 (test.db で起動した場合):
    main: /Users/yourusername/test.db

    実行例 (ファイル名を指定せず起動した場合):
    main:

  • .tables: 現在のデータベースに含まれるテーブルの一覧を表示します。まだテーブルを作成していない場合は何も表示されません。

    sqlite
    sqlite> .tables

  • .schema [テーブル名]: 指定したテーブルの作成に使われた CREATE TABLE 文を表示します。テーブル名を省略すると、全てのテーブルの CREATE 文を表示します。これはテーブル構造を確認するのに非常に便利です。

    sqlite> .schema users

  • .mode MODE: SQLクエリの結果表示形式を設定します。よく使うモードには list (デフォルト、区切り文字はパイプ |)、column (カラム幅を調整して整形表示)、csv (CSV形式) などがあります。

    sqlite
    sqlite> .mode column

  • .headers ON|OFF: クエリ結果のカラム名(ヘッダー)を表示するかどうかを設定します。column モードと併用すると見やすい整形済みテーブル表示になります。

    sqlite
    sqlite> .headers on

    今後の説明では、.mode column および .headers on を設定している前提で、クエリ結果例を示します。操作を開始する前に、これらの設定を行っておくと良いでしょう。

    sqlite
    sqlite> .mode column
    sqlite> .headers on

3.5 SQL文の実行

SQLiteシェルでは、SQL文はセミコロン(;)で終わる必要があります。複数行にまたがるSQL文も、セミコロンが現れるまで入力が続行されます。

例:

sqlite
sqlite> SELECT 1 + 1;

Enter キーを押してもセミコロンがない場合は、プロンプトが ...> に変わります。

sqlite
sqlite> SELECT
...> 1 + 1;

セミコロンを入力して Enter キーを押すと、SQL文が実行されます。

sqlite
sqlite> SELECT 1 + 1;
1+1
--
2

SQL文はセミコロンで終わることを忘れないようにしましょう。ドットコマンドはセミコロンを必要としません。

これで、SQLiteシェルの起動、終了、そして基本的な操作環境の設定ができるようになりました。次は、実際にデータベースの中にテーブルを作成し、データを操作していきます。

4. データベースとテーブルの操作

データベースはデータを整理・管理するための「箱」のようなものです。そして、その箱の中にデータを格納するための構造が「テーブル」です。テーブルは、スプレッドシートのように、行(レコード)と列(カラム/フィールド)で構成されます。

4.1 データベースファイルの作成

前述の通り、sqlite3 [ファイル名] で起動すると、ファイルが存在しない場合は新規作成されます。

bash
sqlite3 mydatabase.db

これで mydatabase.db という空のデータベースファイルが作成(または開かれ)ました。

4.2 テーブルの作成 (CREATE TABLE)

データベースの中にデータを格納するためには、まずテーブルを定義する必要があります。テーブルの定義には、カラム名、そのデータ型、そして制約を指定します。

テーブルを作成するためのSQL文は CREATE TABLE です。

sql
CREATE TABLE テーブル名 (
カラム名1 データ型1 [制約1],
カラム名2 データ型2 [制約2],
...
);

4.2.1 SQLiteの主要なデータ型

SQLiteは動的型付けを採用しており、他のRDBMSほど厳密ではありませんが、内部的には以下の5つの主要なストレージクラスを持ちます。

  • NULL: 値がNULL(欠損値)である。
  • INTEGER: 符号付き整数。大きさによって1, 2, 3, 4, 6, または8バイトで格納されます。
  • REAL: 浮動小数点数。8バイトのIEEE浮動小数点数として格納されます。
  • TEXT: テキスト文字列。データベースのエンコーディング(UTF-8, UTF-16BE, UTF-16LE)を使用して格納されます。
  • BLOB: バイナリデータ。入力されたそのままの形で格納されます(Binary Large Object)。

CREATE TABLE 文では、これらのストレージクラスに対応する型名(INTEGER, TEXT, REAL, BLOB)や、他のRDBMSで一般的な型名(VARCHAR, INT, FLOAT, BOOLEAN など)を指定できます。SQLiteは、指定された型名を上記の5つのストレージクラスのいずれかにマッピングします。例えば、VARCHARTEXTTEXT に、INTINTEGERINTEGER にマッピングされます。

4.2.2 制約 (Constraints)

カラムには、データの整合性を保つための制約を設定できます。

  • PRIMARY KEY: 主キー。そのカラムの値によって行を一意に識別するための制約です。NOT NULLかつUNIQUEになります。通常、INTEGER型の主キーは特別な挙動(ROWIDエイリアス、AUTOINCREMENTなど)を持ちます。
  • NOT NULL: そのカラムにNULL値を挿入することを禁止します。
  • UNIQUE: そのカラムの値がテーブル内で一意であることを保証します。
  • DEFAULT デフォルト値: 値が指定されなかった場合に自動的に挿入されるデフォルト値を設定します。
  • CHECK 条件式: 指定した条件式を満たす値のみ挿入できるようにします。
  • FOREIGN KEY: 外部キー。他のテーブルのカラムを参照し、テーブル間の関係を定義します。
4.2.3 AUTOINCREMENT

INTEGER型のPRIMARY KEYカラムに対して AUTOINCREMENT キーワードを指定すると、新しいレコードが挿入されるたびに、そのカラムに自動的に一意の連番が割り当てられます。これは、各レコードに固有の識別子を付与したい場合によく使われます。

注意: AUTOINCREMENT は、前に使用されたROWIDを再利用しないことを保証するものであり、単に自動連番を使いたいだけであれば INTEGER PRIMARY KEY と指定するだけで十分な場合がほとんどです。INTEGER PRIMARY KEY だけでも、特別な事情がない限り連番が生成されます。AUTOINCREMENT は、削除されたレコードのIDが将来的に再利用されないようにしたい、といった特定の要件がある場合にのみ必要になります。

4.2.4 テーブル作成例

ユーザー情報を管理する users テーブルと、商品情報を管理する products テーブルを作成してみましょう。

users テーブル:
* id: ユーザーID (整数、主キー、自動採番)
* name: ユーザー名 (テキスト、必須)
* email: メールアドレス (テキスト、必須、一意)
* age: 年齢 (整数、NULL可)

products テーブル:
* id: 商品ID (整数、主キー、自動採番)
* name: 商品名 (テキスト、必須)
* price: 価格 (実数、必須、0より大きいこと)

SQLiteシェルを開き(例: sqlite3 shop.db)、以下のSQL文を入力して実行します。

sqlite
sqlite> CREATE TABLE users (
...> id INTEGER PRIMARY KEY AUTOINCREMENT,
...> name TEXT NOT NULL,
...> email TEXT NOT NULL UNIQUE,
...> age INTEGER
...> );

成功しても特にメッセージは表示されません。

次に products テーブルを作成します。

sqlite
sqlite> CREATE TABLE products (
...> id INTEGER PRIMARY KEY AUTOINCREMENT,
...> name TEXT NOT NULL,
...> price REAL NOT NULL CHECK (price > 0)
...> );

これで2つのテーブルが作成されました。

4.3 テーブル一覧の表示 (.tables)

作成したテーブルを確認するには、.tables ドットコマンドを使います。

sqlite
sqlite> .tables

実行例:
products users

作成した usersproducts テーブルが表示されました。

4.4 テーブル構造の確認 (.schema)

テーブルがどのようなカラムを持ち、どのような制約が設定されているかを確認するには、.schema ドットコマンドを使います。

sqlite
sqlite> .schema users

実行例:
sql
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
age INTEGER
);

products テーブルの構造も確認してみましょう。

sqlite
sqlite> .schema products

実行例:
sql
CREATE TABLE products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL CHECK (price > 0)
);

.schema コマンドは、テーブル作成時に実行した CREATE TABLE 文を再構成して表示してくれます。

4.5 テーブルの削除 (DROP TABLE)

不要になったテーブルは DROP TABLE 文で削除できます。テーブル内のデータも全て失われますので注意してください。

sql
DROP TABLE テーブル名;

例として、誤って作成した架空の temp_table というテーブルを削除する場合:

sqlite
sqlite> DROP TABLE temp_table;

もし存在しないテーブル名を指定するとエラーになります。存在チェックをしてから削除したい場合は、IF EXISTS を使用します。

sql
DROP TABLE IF EXISTS temp_table;

これで、データベースファイルの作成、テーブルの作成、構造確認、削除といった基本的な操作ができるようになりました。次は、作成したテーブルにデータを挿入し、参照、更新、削除する方法を学びます。

5. データの操作

テーブルを作成したら、いよいよデータの登録、表示、変更、削除といった操作を行います。これらの操作には、SQLの INSERT, SELECT, UPDATE, DELETE 文を使用します。これらはまとめてCRUD操作(Create, Read, Update, Delete)と呼ばれることもあります。

5.1 データの挿入 (INSERT INTO)

テーブルに新しい行(レコード)を追加するには INSERT INTO 文を使用します。

基本的な構文は以下の通りです。

sql
INSERT INTO テーブル名 (カラム1, カラム2, ...) VALUES (値1, 値2, ...);

または、全てのカラムに値を挿入する場合で、VALUES句の順序がテーブル定義のカラム順と一致する場合は、カラム名のリストを省略できます。

sql
INSERT INTO テーブル名 VALUES (値1, 値2, ...); -- 全てのカラムに値を挿入する場合のみ

注意点:
* テキスト値はシングルクォート (') で囲む必要があります。
* 数値(整数、実数)はクォートは不要です。
* NULL値を挿入する場合は NULL と記述します。
* AUTOINCREMENTDEFAULT が設定されているカラムで、自動的に値を生成させたい場合は、INSERT 文でそのカラム名を省略するか、VALUES 句で NULL または DEFAULT と指定します。

挿入例

先ほど作成した users テーブルと products テーブルにデータを挿入してみましょう。

users テーブルに3人のユーザー情報を追加します。idAUTOINCREMENT なので、INSERT 文では指定しません。

sqlite
sqlite> INSERT INTO users (name, email, age) VALUES ('Alice', '[email protected]', 30);
sqlite> INSERT INTO users (name, email, age) VALUES ('Bob', '[email protected]', 25);
sqlite> INSERT INTO users (name, email) VALUES ('Charlie', '[email protected]'); -- ageはNULLを挿入

products テーブルに商品を2つ追加します。

sqlite
sqlite> INSERT INTO products (name, price) VALUES ('Laptop', 1200.00);
sqlite> INSERT INTO products (name, price) VALUES ('Keyboard', 75.50);

複数の行を一度に挿入することも可能です(SQLite 3.7.11 以降)。

sql
INSERT INTO テーブル名 (カラム1, ...) VALUES
(値1a, 値1b, ...),
(値2a, 値2b, ...),
...
;

例: users テーブルにさらに2人のユーザーを追加

sqlite
sqlite> INSERT INTO users (name, email, age) VALUES
...> ('David', '[email protected]', 22),
...> ('Eve', '[email protected]', 29);

5.2 データの表示 (SELECT)

テーブルからデータを取得するには SELECT 文を使用します。これが最も頻繁に使うSQL文です。

基本的な構文は以下の通りです。

sql
SELECT カラム1, カラム2, ... FROM テーブル名 [WHERE 条件] [ORDER BY カラム [ASC|DESC]] [LIMIT 数 OFFSET 数];

  • SELECT カラム1, カラム2, ...: 取得したいカラムを指定します。
  • SELECT *: テーブルの全てのカラムを取得する場合に使用します。
  • FROM テーブル名: データを取得するテーブルを指定します。
  • WHERE 条件: 取得する行を絞り込むための条件を指定します(省略可)。
  • ORDER BY カラム [ASC|DESC]: 結果を指定したカラムでソートします。ASCは昇順(デフォルト)、DESCは降順です(省略可)。
  • LIMIT 数 [OFFSET 数]: 取得する行の最大数を指定します。OFFSETを付けると、指定した数だけ行をスキップして取得します(省略可)。
データの全件取得

users テーブルの全てのデータを取得してみましょう。

sqlite
sqlite> SELECT * FROM users;

column モードと headers on に設定している場合、実行例は以下のようになります。

“`
id name email age


1 Alice [email protected] 30
2 Bob [email protected] 25
3 Charlie [email protected]
4 David [email protected] 22
5 Eve [email protected] 29
“`

age が指定されなかったCharlieのレコードは NULL と表示されています。

特定のカラムのみ取得する場合:

sqlite
sqlite> SELECT name, email FROM users;

実行例:
“`
name email


Alice [email protected]
Bob [email protected]
Charlie [email protected]
David [email protected]
Eve [email protected]
“`

条件を指定して取得 (WHERE)

WHERE 句を使って、特定の条件を満たす行だけを取得できます。比較演算子 (=, !=, <, >, <=, >=) や論理演算子 (AND, OR, NOT)、LIKE (パターンマッチング)、IN (リストに含まれるか) などが使えます。

  • 年齢が30歳以上のユーザーを取得:

    sqlite
    sqlite> SELECT * FROM users WHERE age >= 30;

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    “`

  • 名前に ‘o’ が含まれるユーザーを取得:

    sqlite
    sqlite> SELECT * FROM users WHERE name LIKE '%o%';

    LIKE 句では、% は任意の文字列、_ は任意の一文字を表します。

    実行例:
    “`
    id name email age


    2 Bob [email protected] 25
    “`

  • 年齢が25歳から30歳の間(25歳と30歳を含む)のユーザーを取得:

    sqlite> SELECT * FROM users WHERE age BETWEEN 25 AND 30;

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    2 Bob [email protected] 25
    5 Eve [email protected] 29
    ``BETWEENカラム >= 最小値 AND カラム <= 最大値` と同じ意味です。

  • 年齢がNULLのユーザーを取得:

    sqlite
    sqlite> SELECT * FROM users WHERE age IS NULL;

    注意: NULL値の比較は =!= ではなく、IS NULL または IS NOT NULL を使います。

    実行例:
    “`
    id name email age


    3 Charlie [email protected]
    “`

  • 複数の条件を組み合わせる(AND, OR):

    sqlite
    sqlite> SELECT * FROM users WHERE age >= 25 AND name LIKE 'A%'; -- 年齢が25歳以上 AND 名前がAで始まる

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    “`

結果をソートする (ORDER BY)

ORDER BY 句を使って、結果を特定のカラムの値で並べ替えることができます。デフォルトは昇順 (ASC) ですが、DESC を指定すると降順になります。

結果の件数を制限する (LIMIT, OFFSET)

LIMIT 句を使って、取得する行数を制限できます。OFFSET を使って、先頭から数行をスキップすることも可能です。これはページネーション(結果を分割して表示すること)などに利用されます。

  • 最初の3人のユーザーを取得:

    sqlite
    sqlite> SELECT * FROM users LIMIT 3;

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    2 Bob [email protected] 25
    3 Charlie [email protected]
    “`

  • 4番目以降のユーザーを全て取得(最初の3件をスキップ):

    sqlite
    sqlite> SELECT * FROM users LIMIT -1 OFFSET 3; -- LIMIT -1 は「最後まで」という意味

    実行例:
    “`
    id name email age


    4 David [email protected] 22
    5 Eve [email protected] 29
    “`

  • 年齢でソートした結果の、2件目から2件を取得(例:年齢が若い順に並べたときの、2番目と3番目を取得):

    sqlite
    sqlite> SELECT * FROM users ORDER BY age ASC LIMIT 2 OFFSET 1;

    実行例:
    “`
    id name email age


    2 Bob [email protected] 25
    5 Eve [email protected] 29
    “`

重複行を除外する (DISTINCT)

SELECT DISTINCT を使うと、結果から重複する行を排除できます。

  • ユーザーの年齢のユニークなリストを取得:

    sqlite
    sqlite> SELECT DISTINCT age FROM users;

    実行例:
    “`
    age


    30
    25
    22
    29
    “`
    NULL値も重複とみなされず、1つだけ表示されます。

集計関数とGROUP BY

SQLでは、データの集計を行うための関数が用意されています。よく使う関数には COUNT (行数/非NULL値の数)、SUM (合計)、AVG (平均)、MIN (最小値)、MAX (最大値) などがあります。

これらの集計関数は、テーブル全体に対して、または GROUP BY 句で指定したカラムの値ごとに適用できます。

  • users テーブルの全レコード数を取得:

    sqlite
    sqlite> SELECT COUNT(*) FROM users;

    実行例:
    “`
    COUNT(*)


    5
    “`

  • 年齢が登録されているユーザーの数を取得:

    sqlite
    sqlite> SELECT COUNT(age) FROM users; -- NULL値はカウントされない

    実行例:
    “`
    COUNT(age)


    4
    “`

  • ユーザーの平均年齢を取得:

    sqlite
    sqlite> SELECT AVG(age) FROM users;

    実行例:
    “`
    AVG(age)


    26.5
    “`

  • 年齢層ごとの人数を集計:

    GROUP BY 句を使うと、指定したカラムでグループ分けし、グループごとに集計関数を適用できます。ここでは、年齢ごとに何人いるか(ただし、年齢がNULLでない人)を集計します。

    sqlite
    sqlite> SELECT age, COUNT(*) FROM users WHERE age IS NOT NULL GROUP BY age;

    実行例:
    “`
    age COUNT(*)


    22 1
    25 1
    29 1
    30 1
    “`

    GROUP BY で集計した結果に対してさらに条件を絞り込みたい場合は WHERE ではなく HAVING 句を使います。例えば、人数が2人以上の年齢層だけを表示したい場合:

    sqlite
    sqlite> SELECT age, COUNT(*) FROM users WHERE age IS NOT NULL GROUP BY age HAVING COUNT(*) >= 2;

    現在のデータでは、この条件を満たす年齢層はないため、何も表示されません。

5.3 データの更新 (UPDATE)

既存のレコードの内容を変更するには UPDATE 文を使用します。

構文は以下の通りです。

sql
UPDATE テーブル名 SET カラム1 = 新しい値1, カラム2 = 新しい値2, ... [WHERE 条件];

注意点: WHERE 句を省略すると、テーブルの全てのレコードが更新されてしまうため、非常に危険です。通常は WHERE 句を使って、更新したい特定のレコードを指定します。

更新例
  • IDが3のユーザー(Charlie)の年齢を28歳に設定する:

    sqlite
    sqlite> UPDATE users SET age = 28 WHERE id = 3;

    更新後、確認してみましょう。

    sqlite
    sqlite> SELECT * FROM users WHERE id = 3;

    実行例:
    “`
    id name email age


    3 Charlie [email protected] 28
    “`

  • 全ての商品の価格を10%値上げする(WHERE句なしの例、実務では慎重に!):

    sqlite
    sqlite> UPDATE products SET price = price * 1.10;

    更新後、確認してみましょう。

    sqlite
    sqlite> SELECT * FROM products;

    実行例:
    “`
    id name price


    1 Laptop 1320.0
    2 Keyboard 83.05
    “`

5.4 データの削除 (DELETE FROM)

テーブルからレコードを削除するには DELETE FROM 文を使用します。

構文は以下の通りです。

sql
DELETE FROM テーブル名 [WHERE 条件];

注意点: WHERE 句を省略すると、テーブルの全てのレコードが削除されてしまうため、非常に危険です。通常は WHERE 句を使って、削除したい特定のレコードを指定します。

削除例
  • IDが4のユーザー(David)を削除する:

    sqlite
    sqlite> DELETE FROM users WHERE id = 4;

    削除後、確認してみましょう。

    sqlite
    sqlite> SELECT * FROM users;

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    2 Bob [email protected] 25
    3 Charlie [email protected] 28
    5 Eve [email protected] 29
    “`
    Davidのレコード(ID=4)が削除されていることがわかります。AUTOINCREMENTの連番は、削除された番号は通常再利用されません(厳密にはROWIDが再利用されない)。

  • 年齢が25歳以下のユーザーを全て削除:

    sqlite
    sqlite> DELETE FROM users WHERE age <= 25;

    この例では、Bob (ID=2, age=25) が削除されます。David (ID=4) は既に削除されています。

    sqlite
    sqlite> SELECT * FROM users;

    実行例:
    “`
    id name email age


    1 Alice [email protected] 30
    3 Charlie [email protected] 28
    5 Eve [email protected] 29
    “`

  • DELETE FROM テーブル名; は、WHERE 句がないため、テーブル内の全てのデータを削除しますが、テーブル構造自体は残ります。これは TRUNCATE TABLE と呼ばれる操作に似ています(SQLiteには TRUNCATE TABLE コマンドは標準でありませんが、実質的に同じ結果になります)。

これで、SQLiteデータベースにおける基本的なデータ操作、つまりCRUDの全ての操作ができるようになりました。次は、複数のテーブルを扱う際に役立つテクニックをいくつか紹介します。

6. もう少し進んだ操作

データベースシステムの真価は、単にデータを格納するだけでなく、異なる情報を関連付けて活用できることにあります。ここでは、リレーショナルデータベースの重要な概念である「結合(JOIN)」、データの取得を効率化する「インデックス」、よく使うクエリを保存しておける「ビュー」、そしてデータの安全性を保つ「トランザクション」について学びます。

これらの操作を行うために、簡単なサンプルデータとして、ユーザーと注文に関するテーブルを作成し、データを入れてみましょう。

データベースを一度終了し、新しいデータベースファイルで始めるか、既存のデータベースにテーブルを追加しても構いません。ここでは shop.db を引き続き使うと仮定します。

まず、注文を記録する orders テーブルを作成します。
* id: 注文ID (整数、主キー、自動採番)
* user_id: 注文したユーザーのID (整数、必須、users テーブルの id を参照する外部キー)
* order_date: 注文日 (テキスト)
* total_amount: 合計金額 (実数、必須、0以上であること)

sqlite
sqlite> CREATE TABLE orders (
...> id INTEGER PRIMARY KEY AUTOINCREMENT,
...> user_id INTEGER NOT NULL,
...> order_date TEXT,
...> total_amount REAL NOT NULL CHECK (total_amount >= 0),
...> FOREIGN KEY (user_id) REFERENCES users(id)
...> );

ここで FOREIGN KEY (user_id) REFERENCES users(id) は、orders テーブルの user_id カラムが、users テーブルの id カラムを参照する外部キーであることを示しています。これにより、存在しないユーザーのIDで注文が登録されることを防ぐなど、データの整合性を保つことができます。ただし、SQLiteではデフォルトでは外部キー制約が無効になっています。有効にするには、セッションごとに以下のコマンドを実行する必要があります。

sqlite
sqlite> PRAGMA foreign_keys = ON;

外部キー制約を有効にした状態で、いくつか注文データを挿入してみましょう。存在するユーザーID(現在のusersテーブルにはIDが1, 3, 5のユーザーがいます)を使ってデータを挿入します。

sqlite
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (1, '2023-10-26', 5000.00);
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (3, '2023-10-26', 150.00);
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (1, '2023-10-27', 7500.00);
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (5, '2023-10-27', 300.50);
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (1, '2023-10-28', 2200.00);

もし存在しないユーザーIDで挿入しようとするとエラーになります(PRAGMA foreign_keys = ON; が有効な場合)。

sqlite
sqlite> INSERT INTO orders (user_id, order_date, total_amount) VALUES (999, '2023-10-28', 1000.00);

実行例:
Error: FOREIGN KEY constraint failed

これで、users テーブルと orders テーブルにデータが入った状態になりました。

6.1 結合 (JOIN)

リレーショナルデータベースの重要な機能の一つに、複数のテーブルを結合して関連するデータを一度に取得する「JOIN」があります。例えば、「どのユーザーがどの注文をしたか」を知りたい場合、users テーブルのユーザー情報と orders テーブルの注文情報を、ユーザーIDをキーとして結合する必要があります。

JOINにはいくつかの種類がありますが、最も一般的でよく使うものを紹介します。

  • INNER JOIN: 結合条件に一致する両方のテーブルの行のみを返します。
  • LEFT JOIN (or LEFT OUTER JOIN): 左側のテーブルの全ての行と、結合条件に一致する右側のテーブルの行を返します。右側のテーブルに一致する行がない場合は、右側のカラムにはNULLが入ります。

構文:

sql
SELECT カラムリスト
FROM 左テーブル
JOIN種類 右テーブル ON 結合条件
[WHERE 条件];

結合条件は通常、両方のテーブルの関連するカラムが等しい (テーブル1.カラム = テーブル2.カラム) と指定します。

JOIN例
  • 各注文とその注文をしたユーザーの名前を取得する(INNER JOIN):

    users テーブルの idorders テーブルの user_id が一致する行を結合します。

    sqlite
    sqlite> SELECT orders.id, users.name, orders.order_date, orders.total_amount
    ...> FROM orders
    ...> INNER JOIN users ON orders.user_id = users.id;

    カラム名の衝突を避けるため、テーブル名.カラム名 の形式で指定することが一般的です。

    実行例:
    “`
    id name order_date total_amount


    1 Alice 2023-10-26 5000.0
    2 Charlie 2023-10-26 150.0
    3 Alice 2023-10-27 7500.0
    4 Eve 2023-10-27 300.5
    5 Alice 2023-10-28 2200.0
    “`
    これにより、注文データにユーザー名が付加された形で取得できました。結合条件に一致しない注文(user_id が users テーブルに存在しない場合)や、注文をしていないユーザーは結果に含まれません。

  • 全てのユーザーと、もしあればそのユーザーの注文情報を取得する(LEFT JOIN):

    users テーブルを左側、orders テーブルを右側として結合します。

    sqlite
    sqlite> SELECT users.name, orders.order_date, orders.total_amount
    ...> FROM users
    ...> LEFT JOIN orders ON users.id = orders.user_id;

    実行例:
    “`
    name order_date total_amount


    Alice 2023-10-26 5000.0
    Alice 2023-10-27 7500.0
    Alice 2023-10-28 2200.0
    Bob
    Charlie 2023-10-26 150.0
    David
    Eve 2023-10-27 300.5
    “`
    BobとDavidは注文データがないため、ordersテーブルからのカラム(order_date, total_amount)がNULLになっています。LEFT JOINを使うことで、「左側のテーブルの全ての行」を基準に関連データを取得できます。

6.2 インデックスの作成 (CREATE INDEX)

テーブルに大量のデータがある場合、SELECT 文で特定の条件を指定してデータを検索したり、ORDER BY 句でソートしたりする処理に時間がかかることがあります。これは、データベースが対象の行を見つけるためにテーブル全体をスキャン(全件検索)する必要があるためです。

「インデックス」は、特定カラムの値と、その値を持つ行がどこにあるかの情報を持つデータ構造です。書籍の索引のように、これを使うことでテーブル全体をスキャンすることなく、効率的に目的の行を見つけ出すことができます。

検索条件(WHERE句)やソート条件(ORDER BY句)で頻繁に使うカラムにインデックスを作成すると、これらの操作のパフォーマンスが向上します。

インデックスを作成する構文:

sql
CREATE INDEX インデックス名 ON テーブル名 (カラム1 [ASC|DESC], カラム2 [ASC|DESC], ...);

インデックス作成例
  • users テーブルの email カラムにインデックスを作成する(メールアドレスでユーザーを検索することが多いと想定):

    sqlite
    sqlite> CREATE INDEX idx_users_email ON users (email);

  • orders テーブルの user_id カラムと order_date カラムの組み合わせにインデックスを作成する(特定のユーザーの特定の期間の注文を検索することが多いと想定):

    sqlite
    sqlite> CREATE INDEX idx_orders_user_date ON orders (user_id, order_date DESC); -- 日付は新しい順でソートすることも多いと想定

インデックスは検索やソートを高速化しますが、データの挿入、更新、削除の際にはインデックスも更新する必要があるため、これらの操作のパフォーマンスはわずかに低下する可能性があります。また、インデックス自体もディスク容量を消費します。どのカラムにインデックスを作成するかは、アプリケーションの利用パターン(読み込みが多いか、書き込みが多いかなど)を考慮して判断する必要があります。

6.3 ビューの作成 (CREATE VIEW)

「ビュー」は、1つ以上のテーブルに対する SELECT クエリの結果を、あたかも1つの仮想的なテーブルであるかのように扱えるようにするものです。ビュー自体はデータを物理的に保持しません。ビューにアクセスするたびに、定義されたクエリが実行され、その結果が表示されます。

ビューを使うことで、複雑なJOINを含むクエリに簡単な名前を付けたり、特定のカラムだけを見せることでセキュリティを確保したりすることができます。

ビューを作成する構文:

sql
CREATE VIEW ビュー名 AS
SELECT ... FROM ... WHERE ... ; -- ビューの定義となるSELECT文

ビュー作成例
  • ユーザーの名前と各ユーザーの注文数、合計金額を表示するビューを作成する:

    複雑なクエリ(LEFT JOINとGROUP BY、集計関数を含む)に user_order_summary という名前を付けます。

    sqlite
    sqlite> CREATE VIEW user_order_summary AS
    ...> SELECT
    ...> users.name,
    ...> COUNT(orders.id) AS order_count, -- 注文IDの数を数える
    ...> SUM(orders.total_amount) AS total_spent -- 合計金額を計算する
    ...> FROM users
    ...> LEFT JOIN orders ON users.id = orders.user_id
    ...> GROUP BY users.id; -- ユーザーごとにグループ化して集計

    ビューが作成されたら、通常のテーブルのように SELECT 文でアクセスできます。

    sqlite
    sqlite> SELECT * FROM user_order_summary;

    実行例:
    “`
    name order_count total_spent


    Alice 3 14700.0
    Bob 0
    Charlie 1 150.0
    David 0
    Eve 1 300.5
    “`
    このビューを使うことで、ユーザーごとの注文サマリーを簡単に取得できるようになりました。

6.4 トランザクション

「トランザクション」は、一連のデータベース操作(SQL文)を1つの論理的な単位として扱うための仕組みです。トランザクション内の全ての操作が成功した場合にのみ、その変更がデータベースに永続的に反映されます(コミット)。もし途中で何らかのエラーが発生したり、ユーザーがキャンセルしたりした場合は、トランザクション内の全ての変更が取り消され、データベースはトランザクション開始前の状態に戻ります(ロールバック)。

これにより、複数の操作が組み合わさった処理(例えば、「商品の在庫を減らして、売上レコードを追加する」といった一連の操作)において、一部の操作だけが成功してデータの不整合が発生することを防ぎ、データの整合性を保つことができます。

SQLiteはデフォルトで「オートコミットモード」で動作します。これは、個々のSQL文が実行されるたびに、自動的にトランザクションとしてコミットされるということです。複数のSQL文を1つのトランザクションとしてまとめたい場合は、明示的にトランザクションを開始する必要があります。

トランザクションを制御するコマンド:

  • BEGIN TRANSACTION; または BEGIN;: トランザクションを開始します。
  • COMMIT;: 現在のトランザクション内の全ての変更をデータベースに永続的に反映します。
  • ROLLBACK;: 現在のトランザクション内の全ての変更を取り消し、トランザクション開始前の状態に戻します。
トランザクション例

ある商品の在庫を1減らし、同時に売上ログを記録するという操作を考えます。この2つの操作は同時に成功するか、同時に失敗するべきです。

架空の products テーブルに stock カラムを追加し、データを更新しておきます。

“`sqlite
— products テーブルに stock カラムを追加 (ALTER TABLE)
sqlite> ALTER TABLE products ADD COLUMN stock INTEGER DEFAULT 0;

— 既存の商品に在庫数を設定
sqlite> UPDATE products SET stock = 10 WHERE id = 1; — Laptop
sqlite> UPDATE products SET stock = 50 WHERE id = 2; — Keyboard

— 売上ログテーブルも作成 (仮)
sqlite> CREATE TABLE sales_log (
…> id INTEGER PRIMARY KEY AUTOINCREMENT,
…> product_id INTEGER,
…> quantity INTEGER,
…> sale_time TEXT
…> );
“`

トランザクションを使って、在庫更新とログ記録を行います。

“`sqlite
sqlite> BEGIN TRANSACTION; — トランザクション開始

— Laptop (id=1) の在庫を1減らす
sqlite> UPDATE products SET stock = stock – 1 WHERE id = 1;

— 売上ログを記録する (Laptop 1個)
sqlite> INSERT INTO sales_log (product_id, quantity, sale_time) VALUES (1, 1, ‘now’); — SQLiteの’now’は現在時刻を表す関数

— ここで、もし何らかの問題が発生した場合… (例: エラーをシミュレーション)
— 例えば、別のテーブルへの挿入に失敗した場合など

— 問題なく全て成功した場合、コミットする
sqlite> COMMIT; — 変更を確定

— もし途中で問題が発生した場合、ロールバックする(COMMITの代わりにこちらを実行)
— sqlite> ROLLBACK; — 変更を取り消し
“`

上記の例では、COMMIT が実行されれば、products テーブルの stock は9になり、sales_log テーブルに新しい行が追加されます。もし ROLLBACK が実行されれば、これらの変更はどちらもデータベースに反映されず、トランザクション開始前の状態(stock=10, sales_logは変更なし)に戻ります。

トランザクションは、複数の関連するデータベース操作の整合性を保つ上で非常に重要な概念です。

これで、SQLiteの基本的な操作だけでなく、JOIN、インデックス、ビュー、トランザクションといった、より実践的なデータベース操作の基礎を学ぶことができました。

7. SQLiteのGUIツール

これまでコマンドラインツール(sqlite3)を使ってSQLiteを操作してきましたが、データの閲覧や簡単な編集、テーブル構造の確認など、視覚的なインターフェースがあると便利な場面が多くあります。SQLiteには、多くのサードパーティ製のGUIツールが存在します。Macで利用できる代表的なツールをいくつか紹介します。

GUIツールを使うことで、SQLコマンドを覚える負担を減らし、データベースの状態をより直感的に把握することができます。

7.1 代表的なGUIツール

  • DB Browser for SQLite: (旧名: SQLite Database Browser)

    • 最も有名で広く使われている無料・オープンソースのGUIツールの一つです。
    • テーブルの作成、編集、削除。データの閲覧、編集、検索、ソート。SQLクエリの実行。インデックスやビューの管理。データベースのエクスポート/インポート(CSV, SQLなど)といった基本的な機能が揃っています。
    • シンプルで分かりやすいインターフェースが特徴です。
    • Macを含む様々なOSで利用可能です。公式サイトからダウンロードしてインストールできます。
  • TablePlus:

    • Macユーザーに人気のある、洗練されたモダンなインターフェースを持つデータベースクライアントです。SQLiteを含む、MySQL, PostgreSQL, SQL Serverなど多くのデータベースに対応しています。
    • データのインライン編集、複数タブでの作業、強力なフィルタリング・ソート機能、SQLエディタ(シンタックスハイライト、オートコンプリート)、データベース構造の視覚化など、高機能です。
    • 無料版と有料版があります。無料版でも基本的な機能は十分に利用できます。App Storeからも入手可能です。
  • DBeaver:

    • Eclipseプラットフォームをベースにした、非常に高機能なユニバーサルデータベースツールです。SQLiteを含む膨大な種類のデータベースに対応しています。
    • 高機能なSQLエディタ、ER図表示、データ移行ツール、様々なプラグインなど、エンタープライズレベルの機能も備えています。
    • 無料のCommunity Editionと有料のEnterprise Editionがあります。機能が豊富なので、最初は慣れが必要かもしれません。公式サイトからダウンロードしてインストールできます。

7.2 GUIツールの利用イメージ

GUIツールを使うと、以下のような操作がマウスやキーボードショートカットで行えます。

  1. データベースファイルの開く/作成: ファイルメニューから既存の .db ファイルを開いたり、新しいデータベースファイルを作成したりします。
  2. テーブル一覧の表示: サイドバーなどに表示されるツリー構造で、データベース内のテーブル、ビュー、インデックスなどを一覧できます。
  3. テーブル構造の確認: テーブル名を選択すると、そのカラム、データ型、制約などが一覧表示されます。
  4. データ閲覧・編集: テーブル名を選択すると、そのテーブルのデータがスプレッドシートのような形式で表示されます。セルをダブルクリックして直接データを編集したり、新しい行を追加・削除したりできます。
  5. SQLクエリの実行: SQLエディタウィンドウでSQL文を入力し、実行ボタンを押すと、結果が下部のペインに表示されます。シンタックスハイライトやオートコンプリート機能が入力の手助けをしてくれます。
  6. データのインポート/エクスポート: CSVファイルやSQLファイルからデータをインポートしたり、データベースの内容をファイルにエクスポートしたりできます。

例えばDB Browser for SQLiteの画面は、以下のような構成になっています(バージョンや設定によって異なります)。

  • 上部にツールバー(新規DB作成、開く、保存、SQL実行などのボタン)
  • 左側にデータベースのツリー構造(テーブル、ビュー、インデックスなどのリスト)
  • 中央にタブ形式の作業エリア(データベース構造表示タブ、データ表示タブ、SQL実行タブなど)
  • SQL実行タブの場合、上部にSQLエディタ、下部にクエリ結果表示エリア

コマンドラインツールでの学習はデータベースの仕組みやSQLそのものへの理解を深める上で非常に重要ですが、日常的な開発やメンテナンスにおいてはGUIツールを併用することで効率が格段に向上します。いくつか試してみて、ご自身に合ったツールを見つけると良いでしょう。

8. SQLiteの利点と欠点

ここまでSQLiteの使い方を見てきましたが、ここで改めてその特徴を踏まえ、どのような場合に適しているのか、あるいは適していないのかを整理しておきましょう。

8.1 SQLiteの利点

  • 軽量・組み込み: サーバー不要でファイルベースのため、アプリケーションに簡単に組み込むことができます。サイズが小さく、リソース消費も少ないです。
  • 設定・管理が不要: インストールや複雑な設定、デーモンプロセスの起動や停止、ユーザー権限管理などが不要です。データベースファイルを開くだけで使えます。
  • 移植性: データベースは単一のファイルなので、コピーするだけで簡単に別の場所に移動したり、異なるOS間で共有したりできます(バイトオーダーの問題などはありますが、基本的には容易です)。
  • トランザクションのサポート: ファイルベースでありながら、ACID特性を満たす堅牢なトランザクションをサポートしており、データの安全性が高いです。
  • 標準SQL準拠: 多くの標準的なSQL構文をサポートしているため、他のRDBMSの経験がある方なら容易に習得できます。また、SQLiteで学んだSQLの知識は他のデータベースシステムでも活かせます。
  • ライセンス: パブリックドメインであり、商用利用を含め完全に無料で制約なく利用できます。

8.2 SQLiteの欠点

  • 並行処理の制限: 複数のプロセスやスレッドからの書き込み要求に対して、SQLiteは基本的に一度に一つの書き込みしか処理できません。ファイルロックによって書き込みの競合を制御しているためです。読み込みについては同時に実行できますが、多数のクライアントからの書き込みが同時に発生するような、高い並行性が求められるWebアプリケーションのバックエンドなどには向いていません。
  • ネットワーク経由のアクセス: SQLiteはファイルベースなので、データベースファイルはクライアントと同じファイルシステム上にある必要があります。ネットワーク越しにデータベースファイルに直接アクセスすることは可能ですが、推奨されていませんし、パフォーマンスや信頼性の問題が発生しやすいです。複数のユーザーがネットワーク経由で同時にアクセスするような用途には適していません。
  • ユーザー管理・セキュリティ: データベースレベルでのユーザー認証や権限管理機能は限定的です。アクセス制御はファイルシステムレベルで行うのが基本となります。高いセキュリティ要件を持つマルチユーザー環境には向きません。
  • スケーラビリティ: 非常に大規模なデータセット(数テラバイト以上など)や、非常に高い読み書きスループットが求められる用途には、専用のデータベースサーバーを持つRDBMS(MySQL, PostgreSQLなど)の方が適しています。SQLiteは通常、数百GB程度までが実用的な範囲と言われます。

8.3 どのような用途に向いているか?

これらの利点と欠点を踏まえると、SQLiteは以下のような用途に非常に適しています。

  • デスクトップアプリケーションのローカルデータストレージ
  • モバイルアプリケーションのデータストレージ
  • 組み込みシステム(IoTデバイスなど)
  • ウェブサイトのプロトタイピングや小規模サイト(アクセスが集中しない場合)
  • 学習用途
  • 単一ユーザーまたは少数のユーザーが同時にアクセスするツールやスクリプト
  • ファイル形式としての利用(設定ファイルやログファイルなど)

逆に、以下のような用途にはあまり向きません。

  • 大規模なWebアプリケーションのバックエンド(同時書き込みが多い場合)
  • 複数のサーバーからネットワーク越しにアクセスされる集中型データベース
  • 厳格なユーザー権限管理が必要な基幹システム

ご自身の用途に照らし合わせて、SQLiteが適切な選択肢であるか検討してみてください。Macでの個人的な開発や学習、ローカルツールの作成などには、SQLiteは間違いなく強力な味方となるでしょう。

9. 実践的な例:簡単なTODOリストデータベース

これまでに学んだことを活かして、簡単なTODOリストを管理するデータベースを作成・操作してみましょう。

TODOリストに必要な要素:
* タスクの内容 (テキスト)
* 完了したかどうか (真偽値)
* 作成日 (テキスト)

これらの情報を格納する todos テーブルを作成します。

  1. SQLiteシェルの起動

    ターミナルを開き、todo.db という新しいデータベースファイルを作成(または開く)します。

    bash
    sqlite3 todo.db

  2. テーブルの作成

    todos テーブルを作成します。id を主キー(自動採番)とし、task は必須、completed はデフォルトで未完了(0)とします。created_at はテキスト型で日付を保存することにします。

    sqlite
    sqlite> CREATE TABLE todos (
    ...> id INTEGER PRIMARY KEY AUTOINCREMENT,
    ...> task TEXT NOT NULL,
    ...> completed INTEGER DEFAULT 0, -- 0: 未完了, 1: 完了
    ...> created_at TEXT
    ...> );

  3. データの挿入

    いくつかタスクを追加します。created_at には現在の日付をテキストで入力します。

    sqlite
    sqlite> INSERT INTO todos (task, created_at) VALUES ('Groceries shopping', '2023-10-28');
    sqlite> INSERT INTO todos (task, created_at) VALUES ('Write SQLite article', '2023-10-28');
    sqlite> INSERT INTO todos (task, created_at) VALUES ('Plan weekend trip', '2023-10-29');

    completed はデフォルト値の0が自動的に入ります。

  4. データの表示

    現在のTODOリストを表示してみましょう。タスクと完了状態、作成日を表示します。

    sqlite
    sqlite> SELECT task, completed, created_at FROM todos;

    実行例:
    “`
    task completed created_at


    Groceries shopping 0 2023-10-28
    Write SQLite article 0 2023-10-28
    Plan weekend trip 0 2023-10-29
    “`

    未完了のタスクのみを表示したい場合:

    sqlite
    sqlite> SELECT task, created_at FROM todos WHERE completed = 0;

  5. データの更新(完了状態の変更)

    最初のタスク(ID=1)が完了したとマークします。

    sqlite
    sqlite> UPDATE todos SET completed = 1 WHERE id = 1;

    更新後、全てのタスクを表示して確認します。

    sqlite
    sqlite> SELECT task, completed, created_at FROM todos;

    実行例:
    “`
    task completed created_at


    Groceries shopping 1 2023-10-28
    Write SQLite article 0 2023-10-28
    Plan weekend trip 0 2023-10-29
    ``
    "Groceries shopping" の
    completed` が1に変わりました。

  6. データの削除

    完了したタスク(completed = 1 のタスク)を削除します。

    sqlite
    sqlite> DELETE FROM todos WHERE completed = 1;

    削除後、全てのタスクを表示して確認します。

    sqlite
    sqlite> SELECT task, completed, created_at FROM todos;

    実行例:
    “`
    task completed created_at


    Write SQLite article 0 2023-10-28
    Plan weekend trip 0 2023-10-29
    “`
    完了したタスクが削除されました。

このように、SQLiteを使えば、簡単なアプリケーションのデータ管理をコマンドラインから手軽に行うことができます。さらに複雑な機能(優先度、期日、カテゴリーなど)を追加したい場合は、テーブル構造を設計し直して、対応するSQL操作を記述すれば良いだけです。

10. トラブルシューティング

SQLiteの操作中に発生しやすい問題と、その解決策をいくつか紹介します。

  • sqlite3 コマンドが見つかりません:

    • MacにSQLiteがプリインストールされているはずですが、環境によってはPATHが通っていない、あるいはHomebrewなどでインストールしたSQLiteのパスが優先されていない可能性があります。
    • ターミナルで echo $PATH を実行し、SQLiteがインストールされているディレクトリ(通常 /usr/bin/usr/local/bin など)が含まれているか確認してください。
    • Homebrewでインストールした場合は、Homebrewのインストール指示に従って、HomebrewのbinディレクトリがPATHの先頭に来るように設定されているか確認してください(例: シェルの設定ファイル ~/.bash_profile, ~/.zshrc などに eval "$(/opt/homebrew/bin/brew shellenv)" のような行があるか確認)。設定を反映させるためにターミナルを再起動するか、source ~/.zshrc のように設定ファイルを再読み込みしてください。
  • SQL文がエラーになる (e.g., Error: near "..." syntax error):

    • 最も一般的なエラーです。SQL文の構文が間違っています。
    • キーワードのスペルミス、カラム名やテーブル名の間違い、カッコやクォートの対応、末尾のセミコロン(;)の抜けなどを確認してください。
    • エラーメッセージに表示される near "..." は、エラーが発生した箇所の近くを示しています。その周辺の構文を重点的に確認してください。
    • SQLiteのデータ型や制約に違反している可能性もあります(例: NOT NULL カラムにNULLを挿入しようとした、UNIQUE カラムに重複する値を挿入しようとした)。
  • ドットコマンドがエラーになる (e.g., Error: unknown command: .table):

    • ドットコマンドは .tables のように、必ずドット (.) から始める必要があります。
    • SQL文を入力する箇所でドットコマンドを入力している可能性があります。ドットコマンドは sqlite> プロンプトで直接入力します。SQL文の途中で入力することはできません。
  • データベースファイルが開けない、または書き込みできない:

    • 指定したデータベースファイルのパスが間違っている可能性があります。絶対パスで指定してみるか、ファイルが実際に存在し、かつ読み書き権限があるかを確認してください。ls -l ファイル名 コマンドなどでパーミッションを確認できます。
    • データベースファイルが他のプロセスによってロックされている可能性があります。SQLiteは書き込み時にファイルロックを使用するため、別のアプリケーションや別の sqlite3 プロセスが同じデータベースファイルを開いて書き込み中の場合、書き込み操作がブロックされることがあります。可能な場合は、他のプロセスを終了してみてください。
    • ファイルシステムが読み取り専用になっている可能性も考えられます。
  • PRAGMA foreign_keys = ON; を実行しても外部キー制約が機能しない:

    • PRAGMA foreign_keys = ON; は、接続ごとに実行する必要があります。新しい sqlite3 シェルを開き直した場合や、アプリケーションから接続し直した場合は、再度このコマンドを実行する必要があります。
    • テーブル作成時に FOREIGN KEY 制約を正しく定義できているか確認してください。.schema テーブル名 で確認できます。
  • .mode column.headers on の設定が次回起動時に引き継がれない:

    • これらの設定は現在のセッションにのみ適用されます。起動時に自動的に設定したい場合は、SQLiteの起動コマンドのオプションを使用するか、.sqliterc という設定ファイルを作成してその中にコマンドを記述することで可能です(詳細はSQLiteの公式ドキュメントを参照してください)。

これらのトラブルシューティングのヒントは、一般的な問題に対処するためのものです。より複雑な問題に直面した場合は、SQLiteの公式ドキュメントや、オンラインコミュニティでの質問が役立つでしょう。

11. まとめ

この記事では、Macユーザー向けにSQLiteの入門として、その特徴から始まり、ターミナルを使った基本的な操作、SQL文によるデータの管理、そしてGUIツールの活用までを網羅的に解説しました。

学んだことの要点:

  • SQLiteはMacにプリインストールされている、軽量でサーバー不要のファイルベースデータベースです。
  • ターミナルから sqlite3 コマンドで対話的に操作できます。. から始まるドットコマンドはシェル固有の設定や管理に、; で終わるSQL文はデータ操作に使用します。
  • CREATE TABLE でテーブル構造を定義し、INSERT, SELECT, UPDATE, DELETE でデータを操作します。
  • WHERE 句で条件を指定、ORDER BY で並べ替え、LIMIT で件数制限ができます。
  • JOIN で複数のテーブルを関連付けてデータを取得できます。
  • CREATE INDEX でデータ検索・ソートを高速化できます。
  • CREATE VIEW で複雑なクエリを再利用可能な仮想テーブルとして定義できます。
  • BEGIN TRANSACTION, COMMIT, ROLLBACK で一連の操作の整合性を保てます。
  • DB Browser for SQLiteのようなGUIツールを使うと、より視覚的にデータベースを操作できます。
  • SQLiteは手軽で多用途ですが、高い並行性やネットワークアクセスには制限があります。

SQLiteは、その手軽さから様々なMacアプリケーションの内部データ管理に使われており、また個人の開発や学習、スクリプトからのデータ処理にも非常に適しています。この記事を通して、SQLiteの基本的な使い方を習得し、ご自身のプロジェクトや学習に活かせるようになったことを願っています。

次のステップ:

この記事で学んだ基礎を元に、さらにSQLiteやデータベースの世界を深く探求することができます。

  • より高度なSQL: ウィンドウ関数、サブクエリ、共通テーブル式 (CTE) など、さらに強力なSQL構文を学ぶ。
  • プログラムからの利用: Python (sqlite3モジュール), Swift, Objective-C, Rubyなど、お好みのプログラミング言語からSQLiteデータベースにアクセスし、アプリケーションに組み込む方法を学ぶ。
  • データベース設計: 正規化など、効率的で矛盾のないデータベース構造を設計するための理論や手法を学ぶ。
  • パフォーマンスチューニング: EXPLAINクエリプランを使ってSQL文の実行計画を確認し、インデックスの設計やクエリの書き方を見直すことでパフォーマンスを改善する方法を学ぶ。

SQLiteは奥が深く、学ぶほどにその便利さを実感できるはずです。この記事が、あなたのMacでのSQLiteジャーニーの良いスタートとなることを願っています!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール