1. ホーム
  2. sql

[解決済み] Foreign Key Mismatchエラーの原因は何ですか?

2022-02-16 17:54:50

質問

次のような構造のsqliteデータベースがあります。

CREATE TABLE IF NOT EXISTS Patient 
( PatientId INTEGER PRIMARY KEY AUTOINCREMENT );

CREATE TABLE IF NOT EXISTS Event 
( 
PatientId INTEGER REFERENCES Patient( PatientId ),
DateTime TEXT,
EventTypeCode TEXT,
PRIMARY KEY( PatientId, DateTime, EventTypeCode )
);

CREATE TABLE IF NOT EXISTS Reading 
( 
PatientId INTEGER REFERENCES Patient( PatientId ),
DateTime TEXT REFERENCES Event (DateTime),
EventTypeCode TEXT REFERENCES Event (EventTypeCode),
Value REAL,
PRIMARY KEY( PatientId, DateTime, EventTypeCode )
);

ID #1 の患者を挿入します。

を実行します。

INSERT INTO Event (PatientId, DateTime, EventTypeCode) VALUES (1, '2011-01-23 19:26:59', 'R')

どの作品

を実行します。

INSERT INTO Reading (PatientId, DateTime, EventTypeCode, Value) VALUES (1, '2011-01-23 19:26:59', 'R', 7.9)

で、外部キーの不一致が発生します。 患者IDはすべて「1」で、2番目と3番目のクエリではdatetimeとtypecodeが一致しています。私は何がミスマッチなのか理解できませんが、実際に外部キーを定義するのは少し初めてなので、何が間違っているのか分かりません。

どのように解決するのですか?

SQLiteには詳しくないのですが、ちょっとググってみると こんなのが出てきました。 . ドキュメントによると

データベーススキーマに が必要な外部キーエラー 複数のテーブルを見る を識別するために、そのような は検出されません。 テーブルが作成されます。その代わり、そのような エラーは、アプリケーションが を変更するSQLステートメントを準備する。 子または親のコンテンツが テーブルを使用する方法で、外部 キーになります。コンテンツがある場合に報告されるエラー はDMLエラーとなります。 スキーマが変更されたときに報告される は"DDLエラー"です。つまり、言い換えれば 外部キー制約の設定ミス 子プロセスの両方を参照する必要があります。 と親はDMLエラーです。 英語版 のエラーメッセージは、外部キー DMLエラーは通常、"外部キー を使用します。 となることもありますが、"no such 親テーブルが存在しない場合は、そのテーブルを使用します。 が存在します。外部キーDMLエラーは である が報告されている場合。

  • 親テーブルが存在しない、または
  • 外部キー制約で指定された親キーカラムが存在しない。 または
  • 外部キー制約で指定された親キーカラムが 親テーブルの主キーと 一意性制約の対象外である で指定された照合順序を使用して を実行するか、または、CREATE TABLE
  • 子テーブルが親の主キーを参照し、その主キーは 主キーカラムの指定と の主キーカラムの数が の数と一致しない。 子キーカラムを使用します。

その中で3番に当たる可能性があるのでは?

また、他のDBでは一意でないインデックスを外部キー参照として使用することをサポートしている場合がありますが、( 回答はこちら )ですが、私の意見では、これは悪い設計上の選択です。私なら、以下のどちらかを行うように再構築します。

  1. Reading.PatientId 参考文献 Event.PatientId から完全なコンポジットキーが得られるように Event が参照するのは Reading または
  2. を追加します。 EventId に自動インクリメントの主キーを設定します。 Event テーブルの外部キーとして使用します。 Reading テーブルを作成します(そうすれば EventIdValueReading を取得することができます。 PatientId, DateTime, EventTypeCode のうち Event ).

の冗長性を避けるために、2をお勧めします。 PatientId, DateTimeEventTypeCode の両方で EventReading .