MENU

SQLiteの外部キーで存在しない取引先を止める

当ページのリンクには広告(PR)が含まれていることがあります。
SQLiteの外部キーで存在しない取引先を止める。取引先ID、マスターを参照、不明なIDを拒否の処理例。

明細の取引先IDが取引先マスターに存在しないまま保存されると、後から照合できなくなります。画面の選択リスト以外にも登録経路があるなら、保存先でも関連を確認する方法を持たせられます。

SQLiteの外部キーは、子テーブルの値が親テーブルのキーを参照する関係を定義します。定義に加えて、接続ごとの検査の有効化も確認します。以前の別の接続で有効だったことを、そのまま現在の接続の根拠にはしません。

目次

接続直後に設定して読み戻す

次は取引先C1と、それを参照する明細を持つ架空DBです。トランザクション開始前の設定を分かりやすくするため、Python 3.12以降のautocommit=Trueを指定します。複数変更をまとめる処理の例ではありません。

import sqlite3

db = sqlite3.connect(":memory:", autocommit=True)
try:
    db.execute("PRAGMA foreign_keys=ON")
    if db.execute("PRAGMA foreign_keys").fetchone() != (1,):
        raise RuntimeError("外部キーを有効にできません")
    db.execute("CREATE TABLE clients(id TEXT PRIMARY KEY NOT NULL)")
    db.execute(
        "CREATE TABLE tickets(id TEXT PRIMARY KEY NOT NULL,"
        "client_id TEXT NOT NULL REFERENCES clients(id))"
    )
    db.execute("INSERT INTO clients VALUES (?)", ("C1",))
    try:
        db.execute("INSERT INTO tickets VALUES (?,?)", ("T0", "C404"))
    except sqlite3.IntegrityError:
        print("存在しない取引先を拒否")
    else:
        raise AssertionError("不正な参照を通過しました")
    db.execute("INSERT INTO tickets VALUES (?,?)", ("T1", "C1"))
    rows = db.execute("SELECT id,client_id FROM tickets").fetchall()
    violations = db.execute("PRAGMA foreign_key_check").fetchall()
    print("保存した明細:", rows)
    print("参照違反:", violations)
    assert rows == [("T1", "C1")] and violations == []
finally:
    db.close()

C404を参照する明細は拒否され、T1とC1の組だけが残ります。参照違反の一覧は空です。Windows・Python 3.12.10・SQLite 3.49.1で、この結果を確認しました。実台帳へ制約を追加した例ではありません。

トランザクション中に切り替えない

外部キーの切替は、トランザクションの途中では効果がありません。すでにトランザクションが始まる設定を使う場合は、接続時の管理方法と有効化する順序を合わせて確認してください。

ONを実行したつもりでも、現在値を読み戻して1になっているかを確認する形にします。ツール内で新しく接続を作る箇所が複数あるなら、そのたびに同じ方針を適用する必要があります。

NULLと削除の条件も決める

外部キーだけでは参照する列のNULLを必ず拒否するわけではありません。この例は取引先が必須なのでclient_idにNOT NULLも付けています。未割当を許す業務なら、別の定義になります。

親を削除したときに子を残すのか、削除を止めるのか、連動して消すのかも決めます。ON DELETE CASCADEを便利な既定値として付けると、想定より広くデータが消える場合があります。実際の関連と残す必要のある記録から選んでください。

既存の台帳を見直すときは、現在の定義と参照違反を読み取るところから始めます。親がないからといって、明細を勝手に削除したり、適当な取引先へ付け替えたりする処理にはしません。

接続と基本検索はSQLite入門、台帳の入力や状態の整理は在庫・台帳の自動化設計で補えます。

参考資料

SQLite外部キーとPython sqlite3の公式資料を2026年11月1日に確認しました。

この記事を書いた人

Watanabeのアバター Watanabe サイト運営者

2020年よりブログ開始。
SEOが思いのほか性にあっていたようで現在に至る。
モットーは「勝率の高い選択をする」
AIは活用するが吉、最後は人間が息を吹き込む。
アートと科学を追求し、日々精進。
―――
収益:6~7桁をウゴウゴ。
サイト:ペラサイト~中規模サイトまで運営中。
案件:1000円以上の案件をメインに取組中。
打ち手:ブラックSEO~ホワイトSEOまで
―――

目次