Menu

SQLite INSERT文の使い方 | 一括挿入とOR IGNORE

SQLiteのINSERT文を実例で解説。1行挿入から複数行の一括挿入、INSERT...SELECT、デフォルト値の挿入、OR IGNORE / OR REPLACEによる重複制御まで一気に押さえます。

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

INSERT でテーブルに行を追加する

新しい行をテーブルに追加するときに使うのが INSERT 文です。sqlite insert into の書き方はとてもシンプルで、覚えやすい形になっています。

注目すべきポイントは3つあります。

  • INSERT INTO books — 挿入先のテーブル名。
  • (title, author, year) — 値を入れるカラムの一覧。
  • VALUES (...) — 実際の値。カラム一覧と同じ順序で並べます。

id はカラム一覧に含まれていないので、SQLite が自動で値を割り当ててくれます(INTEGER PRIMARY KEY なので rowid が入ります)。指定しなかったカラムにはデフォルト値が、デフォルトがなければ NULL が入ります。

カラム名は必ず明示しよう

カラム一覧を省略して、宣言順にすべてのカラムへ値を渡すこと自体は できます

-- 動作はするが、壊れやすい:
INSERT INTO books VALUES (NULL, 'Dune', 'Frank Herbert', 1965);

やめておきましょう。books に誰かがカラムを 1 つ追加した瞬間、こういう書き方の INSERT 文はエラーになるか、最悪の場合は別のカラムに値が入ってしまいます。カラム名はきちんと明示しましょう:

カラム名を明示的に書いておくと、それ自体がドキュメントの役割を果たします。テーブル定義をいちいち見に行かなくても、何をしているSQLなのか一目で分かるようになります。

SQLiteで複数行をまとめてINSERTする

SQLiteでは、値のタプルをカンマで並べることで、1つのINSERT文で複数行を一気に挿入できます。

これは別々の INSERT 文を3つ書くよりスッキリしますし、SQLite はこれ全体をひとつの文として扱います。ただし、大量データを投入するときに本当に効いてくるのは、INSERT をトランザクションで囲むことです。次はその話をします。

sqlite 一括 insert はトランザクションでまとめる

デフォルトでは、INSERT 文はそれぞれが独立したトランザクションになります。SQLite は1件ごとに fsync を実行するので、素朴なループが遅くなる原因はじつは INSERT 自体ではなく、この同期処理なんです。

まとめて流しましょう。

5回の fsync が1回で済みます。数千行規模になると、その差は2〜3桁になることもあります。途中で何か失敗しても ROLLBACK でバッチ全体を巻き戻せるので安心です。

これがsqliteの一括 insertの定番パターンです。Python、Node、Rust など、どの言語からSQLiteを呼び出す場合でも同じで、ループ全体を BEGIN / COMMIT で囲んでおきましょう。

INSERT ... SELECT:別テーブルからのコピー

リテラルの値ではなく、クエリの結果からテーブルにデータを流し込むこともできます。

SELECT の各列は名前ではなく並び順INSERT の列リストに対応付けられます。名前は一致しなくてOKで、順序さえ合っていれば問題ありません。これは行のアーカイブ、集計用テーブルの作成、マイグレーション時に一部のデータをコピーする、といった場面で定番のやり方です。

DEFAULT VALUES と省略した列の扱い

列に DEFAULT 句が指定されていれば、その列を列リストから外しておくだけでSQLiteが既定値を補ってくれます。

created_at には値を渡していないので、自動的に現在のタイムスタンプが入ります。すべての列をデフォルト値で埋めた行を作りたいときは(プレースホルダ的な行を入れたい場面で便利です)、DEFAULT VALUES 構文を使いましょう:

新しい行が2つ追加され、どちらも value = 0 で id は自動採番されます。

INSERT OR IGNORE:重複をスキップする

UNIQUE 制約や PRIMARY KEY 制約に違反する行を挿入しようとすると、デフォルトではエラーが発生して文全体が中断されます。

エラー: UNIQUE制約に違反しました: users.email

INSERT OR IGNORE を使えば、競合した行は「黙ってスキップ」する動きに切り替えられます:

残った行は3件。重複した行はエラーを出さずに静かに弾かれます。シンプルなシードデータに対して「存在しなければ挿入する」を表現する、SQLite らしいイディオムです。事前に SELECT でチェックしたり、例外処理を書いたりする必要はありません。

INSERT OR REPLACE: 重複行を上書きする

INSERT OR REPLACE は、競合した行を削除してから新しい行をその位置に挿入します。

ひとつだけ注意点があります。REPLACEUPDATE ではなく DELETE + INSERT です。削除される行に対して ON DELETE CASCADE 付きの外部キーが張られていれば、子レコードも一緒に消えます。さらに、新しい INSERT で指定しなかったカラムは元の値を保持せず、デフォルト値にリセットされます。

「あればUPDATE、なければINSERT」をやりたいケースのほとんどは、本来の upsert である ON CONFLICT ... DO UPDATE を使うのが正解です。これについては別ページで詳しく解説します。

ここまでのおさらい

  • INSERT INTO table (cols) VALUES (...) が基本形。カラム名は必ず明示する。
  • sqlite で複数行 insert するときは、VALUES のあとにタプルをカンマ区切りで並べる。
  • 本格的な一括 insert では、BEGIN / COMMIT でまとめてトランザクションにする。
  • INSERT INTO ... SELECT ... でクエリ結果をそのまま流し込める。
  • DEFAULT VALUES を使えばデフォルト値だけで1行作れる。省略したカラムも同じくデフォルトが入る。
  • INSERT OR IGNORE は競合した行をスキップ、INSERT OR REPLACE は削除→挿入で上書きする。

次は UPDATE

行を追加する話はこれで一区切り。残りのもう半分は、すでに存在する行を書き換える話です。カウンタを増やしたり、タイプミスを直したり、注文を発送済みにしたり——そこで登場するのが UPDATE です。特に WHERE 句まわりに、押さえておきたいクセがいくつかあります。続きは次のページで。

よくある質問

SQLiteで1行だけ挿入するには?

INSERT INTO テーブル名 (col1, col2) VALUES (val1, val2); の形で書きます。カラム名のリストは省略できますが、明示しておくのがおすすめ。あとからカラムが追加されてもこの文はそのまま動き続けます。省略する場合は、テーブル定義の順番どおりに全カラム分の値を渡す必要があります。

SQLiteで複数行をまとめてINSERTするには?

VALUES のあとにカッコで囲んだタプルをカンマ区切りで並べればOKです。例: INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);。ただし、数千行レベルの本格的な一括ロードでは BEGINCOMMIT でトランザクションにまとめるのがポイント。実は速くなる理由は複数行構文ではなく、こちらのトランザクション化のほうです。

INSERT OR IGNORE はどんな動きをする?

INSERT OR IGNORE は、UNIQUEPRIMARY KEYNOT NULL 制約に引っかかる行をエラーにせず黙ってスキップします。衝突した行だけが捨てられて、残りの行はそのまま挿入されます。「すでに存在しなければ追加」という動きを、わざわざ存在チェックを書かずに実現したいときに便利です。

INSERT時に『UNIQUE constraint failed』が出るのはなぜ?

UNIQUE または PRIMARY KEY カラムに、すでに同じ値の行が存在することをSQLiteが検知したからです。本当に値が重複しているか、シードスクリプトを再実行しているケースが大半。重複を黙って飛ばしたいなら INSERT OR IGNORE、上書きしたいなら INSERT OR REPLACE、もっと細かく制御したいなら ON CONFLICT ... DO UPDATE(いわゆるupsert)を使い分けましょう。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める