<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cloudflare D1 on M1KE BL0G</title><link>https://www.m1ke.org/tags/cloudflare-d1/</link><description>Recent content in Cloudflare D1 on M1KE BL0G</description><generator>Hugo -- gohugo.io</generator><language>ja-jp</language><copyright>mike</copyright><lastBuildDate>Sun, 08 Nov 2026 01:52:00 +0900</lastBuildDate><atom:link href="https://www.m1ke.org/tags/cloudflare-d1/index.xml" rel="self" type="application/rss+xml"/><item><title>SQLite3のデータ型</title><link>https://www.m1ke.org/p/sqlite3%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B/</link><pubDate>Sun, 08 Nov 2026 01:52:00 +0900</pubDate><guid>https://www.m1ke.org/p/sqlite3%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B/</guid><description>&lt;img src="https://www.m1ke.org/p/sqlite3%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%9E%8B/s.webp" alt="Featured image of post SQLite3のデータ型" /&gt;&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare D1（SQLite3互換）を最近使っていて、&lt;code&gt;DATE&lt;/code&gt;型が存在しないことに気づいた。SQLiteの型システムは他のRDBMSと考え方が異なるので、ここで整理した&lt;/li&gt;
&lt;li&gt;D1はSQLite互換のため、同じ型システムが適用される。アプリ側で日付を扱いたい場合は、TEXT（ISO8601）かINTEGER（UNIX時間）のどちらかに統一して保存するのが実用的だった&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="データ型"&gt;データ型&lt;/h2&gt;
&lt;h3 id="ストレージクラスは5種類"&gt;ストレージクラスは5種類&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ストレージクラス&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;空値&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INTEGER&lt;/td&gt;
&lt;td&gt;整数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REAL&lt;/td&gt;
&lt;td&gt;小数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TEXT&lt;/td&gt;
&lt;td&gt;文字列&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BLOB&lt;/td&gt;
&lt;td&gt;バイト列&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;SQLiteが値を格納する際の実体はこの5種類のみ&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DATE&lt;/code&gt;や&lt;code&gt;BOOLEAN&lt;/code&gt;のようなストレージクラスは存在しない&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="型アフィニティという仕組み"&gt;型アフィニティという仕組み&lt;/h3&gt;
&lt;p&gt;列定義には&lt;code&gt;DATE&lt;/code&gt;や&lt;code&gt;VARCHAR(255)&lt;/code&gt;のような任意の型名を書けるが、これは「型アフィニティ」というヒントとして扱われるだけで、宣言した型名の文字列に応じて次のルールでいずれかのアフィニティに変換される。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;アフィニティ&lt;/th&gt;
&lt;th&gt;判定ルール（型名に含まれる文字列）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;INTEGER&lt;/td&gt;
&lt;td&gt;&lt;code&gt;INT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TEXT&lt;/td&gt;
&lt;td&gt;&lt;code&gt;CHAR&lt;/code&gt; / &lt;code&gt;CLOB&lt;/code&gt; / &lt;code&gt;TEXT&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BLOB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;BLOB&lt;/code&gt; または型名未指定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;REAL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;REAL&lt;/code&gt; / &lt;code&gt;FLOA&lt;/code&gt; / &lt;code&gt;DOUB&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NUMERIC&lt;/td&gt;
&lt;td&gt;上記のいずれにも該当しない場合&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DATE&lt;/code&gt;はどのルールにも一致しないため、NUMERICアフィニティになる&lt;/li&gt;
&lt;li&gt;NUMERICアフィニティの列は、可能ならINTEGERまたはREALに変換され、不可能ならTEXTのまま格納される&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="日付真偽値はどう表現するか"&gt;日付・真偽値はどう表現するか&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;BOOLEANはINTEGERの0/1として格納&lt;/li&gt;
&lt;li&gt;DATE/DATETIMEは次のいずれかで表現するのが一般的
&lt;ul&gt;
&lt;li&gt;TEXT: ISO8601形式の文字列（&lt;code&gt;YYYY-MM-DD HH:MM:SS.SSS&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;REAL: ユリウス日&lt;/li&gt;
&lt;li&gt;INTEGER: UNIXタイムスタンプ（エポック秒）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;組み込みの日付関数（&lt;code&gt;date()&lt;/code&gt;、&lt;code&gt;datetime()&lt;/code&gt;、&lt;code&gt;strftime()&lt;/code&gt;など）はこれらの表現を前提に動作する&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="制約"&gt;制約&lt;/h3&gt;
&lt;h2 id="制約とキー"&gt;制約とキー&lt;/h2&gt;
&lt;p&gt;型システムに加えて、CHECK制約・FK制約・PK・UUIDの扱いもSQLite特有のクセがあるので合わせて整理する。&lt;/p&gt;
&lt;h3 id="check制約"&gt;CHECK制約&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;列レベル・テーブルレベルのどちらでも&lt;code&gt;CHECK (条件)&lt;/code&gt;として定義できる&lt;/li&gt;
&lt;li&gt;デフォルトで常に有効、無効化する仕組みはない&lt;/li&gt;
&lt;li&gt;D1でも同様にデフォルトで有効&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fk外部キー制約"&gt;FK（外部キー）制約&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;制約&lt;/th&gt;
&lt;th&gt;SQLite&lt;/th&gt;
&lt;th&gt;D1&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FK&lt;/td&gt;
&lt;td&gt;デフォルトで無効（&lt;code&gt;PRAGMA foreign_keys = ON&lt;/code&gt;が必要）&lt;/td&gt;
&lt;td&gt;デフォルトで有効（全クエリ・マイグレーションに適用）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;D1はクエリ単位でFK制約を無効化できない&lt;/li&gt;
&lt;li&gt;トランザクション内で一時的にチェックを遅延させたい場合は&lt;code&gt;PRAGMA defer_foreign_keys = on&lt;/code&gt;を使う（&lt;code&gt;RESTRICT&lt;/code&gt;指定の関係は即時エラーになり対象外）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="primary-keypk"&gt;PRIMARY KEY（PK）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;INTEGER PRIMARY KEY&lt;/code&gt;は特別扱いで、内部的なrowidのエイリアスになる（自動採番）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AUTOINCREMENT&lt;/code&gt;を付けると、削除された最大IDの再利用を防げる（代わりにオーバーヘッドが増える）&lt;/li&gt;
&lt;li&gt;PKの型がINTEGER以外（TEXTなど）の場合はrowidのエイリアスにならず、通常の列として暗黙のUNIQUEインデックスで一意性が保たれる&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PRIMARY KEY (col1, col2)&lt;/code&gt;のようにテーブルレベルで複合PKも定義できる&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WITHOUT ROWID&lt;/code&gt;を指定すると、PKそのものをテーブルの実体キーとして扱い、rowidを持たないテーブルにできる&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="uuidの扱い"&gt;UUIDの扱い&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;SQLiteにネイティブなUUID型はなく、TEXT（36文字の文字列）かBLOB（16バイト）で格納するのが一般的&lt;/li&gt;
&lt;li&gt;D1（Cloudflare Workers）では、アプリ側で&lt;code&gt;crypto.randomUUID()&lt;/code&gt;を使ってUUIDv4を生成し、TEXT列に挿入する構成がよく使われる&lt;/li&gt;
&lt;li&gt;UUIDv4はランダムな値のため、&lt;code&gt;INTEGER PRIMARY KEY&lt;/code&gt;のような連番PKと比べて挿入順序が不規則になり、B-treeのページ分割が増えやすい&lt;/li&gt;
&lt;li&gt;挿入局所性を保ちたい場合は、時刻順にソート可能なUUIDv7のような方式を検討するとよい&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="まとめ"&gt;まとめ&lt;/h2&gt;
&lt;p&gt;SQLiteのストレージクラスはNULL/INTEGER/REAL/TEXT/BLOBの5つのみで、DATE型は存在しない。列に&lt;code&gt;DATE&lt;/code&gt;と宣言してもNUMERICアフィニティとして扱われるだけで、実体はINTEGER・REAL・TEXTのいずれかに格納される。D1でも同様の仕組みなので、日付はTEXT（ISO8601）かINTEGER（UNIX時間）で統一して保存するのが実用的。&lt;/p&gt;
&lt;p&gt;制約面では、CHECKはSQLite・D1共にデフォルト有効だが、FKはSQLiteがデフォルト無効・D1がデフォルト有効という違いがある。PKは&lt;code&gt;INTEGER PRIMARY KEY&lt;/code&gt;だとrowidのエイリアスになる点に注意が必要で、UUIDを使う場合はTEXT/BLOBで保存しつつ挿入局所性にも気を配るとよい。&lt;/p&gt;</description></item></channel></rss>