Menu

SQLiteのデータ型入門:5つのストレージクラスと動的型付け

SQLiteは値をどう保存しているのか。5つのストレージクラスと動的型付けの仕組み、そしてPostgresやMySQLから来た人がハマりやすいポイントをまとめます。

このページのコードはエディタで実行できます — 編集してすぐに結果を確認できます。

型はたくさんあるように見えて、実はストレージクラスは5つだけ

SQLite では、すべての値が次の5つの ストレージクラス のいずれかとして保存されます。

  • NULL — 値がないことを表します。
  • INTEGER — 符号付きの整数。サイズに応じて1〜8バイトで格納されます。
  • REAL — 8バイトのIEEE浮動小数点数。
  • TEXT — 文字列。データベースのエンコーディング(通常はUTF-8)で保存されます。
  • BLOB — バイト列。渡したバイトがそのまま格納されます。

これだけです。BOOLEANDATETIMEVARCHARDECIMAL も、独立した型としては存在しません。他のデータベースには何十もの型が用意されていますが、SQLite は5つだけ。それ以外はすべて、この5つの上に組み立てられているのです。

typeof() を使うと、その値が実際にどのストレージクラスで保存されているのかが分かります。返ってくるのは integerrealtextblob のいずれか。これに null を加えた5つが、SQLite が認識するすべての型です。

SQLite は動的型付け

ここが Postgres や MySQL から来た人がいちばん面食らうポイントです。SQLite では(STRICT を付けない限り)、カラムに宣言した型はあくまで 目安 にすぎず、契約にはなりません。型は値ごとに保持されているのです:

どちらの行も問題なく挿入されました。id カラムには片方に整数、もう片方にテキストが入っており、body にもテキストと整数が混在しています。SQLite はどんなストレージクラスの値でも、どのカラムにも平気で格納してしまうのです。

これがいわゆる 動的型付け(dynamic typing) で、SQLite が意図的に採用している設計です。プロトタイプづくりや使い捨てスクリプトでは、この緩さがありがたい場面も多いでしょう。一方で、アプリ側のちょっとしたタイポが原因で、想定と違う型のデータが何年も静かに保存され続ける、なんて事故も起こりえます。このトレードオフが気になる場合 ――本番運用のスキーマならたいてい気になるはずです―― STRICT テーブルを使えば解決できます。後ほど詳しく取り上げます。

型親和性(Type Affinity)をひとことで

カラムに宣言した型は無視されているわけではなく、そのカラムに 親和性(affinity) を与えています。値を挿入すると、SQLite はロスなく変換できる場合に限って、カラムの親和性に寄せようとします。たとえば TEXT カラムに数値 42 を入れるとテキスト '42' として保存され、INTEGER カラムに文字列 '42' を入れると整数 42 として格納されます。変換によって情報が失われてしまう場合は、元の型のまま保持されます。

1行目を見てみましょう。整数の 42 はテキストの '42' に変換され、文字列の '100' は整数の 100 に変換されています。2行目では、'3.5' は情報を失わずに INTEGER に変換できないため、テキストのまま保存されています。型親和性(affinity)については別ページで詳しく扱いますが、ここではひとまず「カラムの型は強制力こそないものの、保存形式には影響を与える」ということを押さえておけばOKです。

boolean 型の扱い

SQLite には BOOLEAN というストレージクラスは存在しません。真偽値は整数として保存され、0 が false、1 が true を表します。

TRUEFALSE は SQLite 3.23 以降でキーワードとして認識され、それぞれ 10 に変換されます。BOOLEAN で宣言するとそのカラムは数値親和性(numeric affinity)を持ちますが、値が 0 か 1 に制限されるわけではありません。STRICT を付けていなければ 'maybe' のような文字列を入れても SQLite は文句を言いません。

SQLite の日付・datetime 型の扱い方

DATETIME 型もありません。代わりに次の 3 つのエンコード方式から好きなものを選びます。SQLite の日付関数はどの形式でもそのまま動きます。

  • TEXT で ISO-8601 形式: '2026-04-23 14:30:00'
  • REAL でユリウス通日(Julian day)
  • INTEGER で Unix エポック秒

ISO-8601 形式の文字列がいちばん無難です。文字列としても正しい順序でソートできて、人間が読んでもわかりやすいですし、組み込み関数(date()time()datetime()strftime()julianday())もすべてこの形式を受け付けてくれます。1つのカラムにつき形式は1つに決めて、ぶれないように運用しましょう。同じカラム内で複数のフォーマットが混在していると、半年後に痛い目を見るパターンの典型です。

VARCHAR、CHAR など、見慣れた型名について

SQLite では、他のデータベースでおなじみの型名 — VARCHAR(255)CHAR(10)NVARCHARDECIMAL(10,2)DOUBLEFLOATINTBIGINTMEDIUMINT — もそのまま書けます。パース自体は問題なく通ります。ただし内部的には、型親和性(type affinity)のルールに従って、先ほどの5つのストレージクラスのどれかにマッピングされるだけです。

VARCHAR(255) と書いても、255 文字の制限は 効きません。SQLite は長さ指定を無視します。DECIMAL(10, 2) も同様で、固定精度の小数として保存される わけではなく、数値アフィニティが付与されて INTEGERREAL として格納されます。これらの型名が用意されているのは、他のデータベースからコピーしてきたスキーマがそのまま動くようにするためで、本来その名前が持つ制約までは引き継がれません。

金額計算のように厳密な小数演算が必要なら、セント単位(最小通貨単位)で INTEGER として保存するのが鉄則です。REAL のような浮動小数点を使うと、遅かれ早かれ小数第 3 位あたりで丸め誤差が顔を出します。

NULL もストレージクラスのひとつ

SQLite における NULL は、単なる「値がない状態」ではありません。れっきとした独自のストレージクラスを持つ値で、typeof() で確認できます。

bnull として返ってきます。ここで重要なのは、NULL は何とも等しくならないという点です。別の NULL 同士でも等しくありません。b = NULL は決して真にならないので、b IS NULL と書く必要があります。この話は後ほど「演算子と NULL」のページで詳しく扱いますが、その出発点はここ、ストレージクラスにあります。

BLOB でバイト列をそのまま格納する

BLOB はバイト列を一切加工せずそのまま保存します。小さな画像、ハッシュ値、エンコード済みデータなど、テキストでも数値でもないものを扱うときに便利です。

x'...' リテラルを使うと、SQL 内で BLOB を 16 進数で書けます。アプリケーション側のコードからは、通常はパラメータ経由でバイト配列を渡す形になります。なお、BLOB に対する length() はバイト数を返すもので、文字数ではありません。

実用上の注意点として、SQLite は大きな BLOB も問題なく格納できますが、その行に触れるクエリのたびに 50MB の BLOB を引きずり回すのは遅くなります。大きなファイルはディスク上に置き、データベースにはパスだけを保存するのがおすすめです。

ここまでのまとめ

  • ストレージクラスは NULLINTEGERREALTEXTBLOB の 5 つで、これだけで全部カバーできます。
  • boolean 型は整数として、日付は TEXT・REAL・INTEGER のいずれか好きな形で扱います。
  • カラムに宣言した型はあくまでヒントであって、強制ではありません(STRICT を使った場合を除く)。
  • VARCHAR(255) のような書き方は構文として通りますが、他の DB のように長さや精度を強制してくれるわけではありません。
  • 中身が実際にどの型で入っているか怪しいときは、typeof(value) が頼りになります。

次回:型親和性(Type Affinity)について

ここでサラッと流した「ヒントとしての型」の挙動には、実はきちんとしたルールがあります。宣言した型名から導かれる 5 つの親和性クラスがあり、INSERT のたびに適用されるしくみです。次のページではそこを掘り下げます。SQLite が渡した値を実際にどう扱うのか予測する上で、これが鍵になります。

よくある質問

SQLiteで使えるデータ型は?

SQLiteのストレージクラスは NULLINTEGERREALTEXTBLOB の5つだけです。データベース内のすべての値は、このいずれかとして格納されます。VARCHAR(255)DATETIMEBOOLEAN といった見慣れた型名も CREATE TABLE で書けますが、これは互換性のためで、保存時には結局この5つのどれかにマッピングされます。

SQLiteにboolean型やdatetime型はある?

専用のストレージクラスとしては存在しません。boolean は INTEGER(0と1)として保存されますが、TRUEFALSE というキーワード自体は認識されます。日付や時刻は TEXT(ISO-8601形式の文字列)、REAL(ユリウス日)、INTEGER(Unixエポック秒)のいずれかで保存します。エンコード方法は自分で選べばよく、日付関数はどれにも対応しています。

なぜSQLiteの型付けは「動的」と呼ばれるの?

他のDBでは INTEGER と宣言したカラムに文字列を入れると弾かれますが、SQLiteではデフォルトで宣言した型は単なる「ヒント」として扱われ、実際の型は値そのものに紐づきます。なので TEXT カラムに整数を突っ込むこともできてしまう。便利な場面もあれば落とし穴になる場面もある仕様です。これを止めたいときは STRICT テーブルを使います。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める