外部キーの使用法
外部キーを定義して、テーブル間の参照整合性を強制できます。外部キー制約を持つテーブルを変更する際に、外部キー制約が確認されます。
外部キーの定義
Caché SQL で外部キーを定義するには、以下のような方法があります。
-
2 つのクラスの間にリレーションシップを定義できます。リレーションシップを定義すると、自動的に SQL に外部キー制約が投影されます。リレーションシップの詳細は、"Caché オブジェクトの使用法" を参照してください。
-
クラス定義に、明示的に外部キー定義を追加できます (リレーションシップによって定義できない場合)。詳細は、"Caché クラス定義リファレンス" の “外部キー定義” を参照してください。
-
外部キーを追加するには、CREATE TABLE コマンドまたは ALTER TABLE コマンドを使用します。また、外部キーを削除するには、ALTER TABLE コマンドを使用します。これらのコマンドについては、"Caché SQL リファレンス" を参照してください。
1 つのテーブル (クラス) のための外部キーの最大数は 400 です。
外部キーの参照整合性チェック
既定では、Caché は INSERT、UPDATE、DELETE の各操作に対して、外部キーの参照整合性チェックを実行します。操作が参照整合性に違反する場合、その操作は行われず、その操作によって SQLCODE -121、-122、-123、-124 のいずれかのエラーが発行されます。参照整合性チェックに失敗すると、以下のようなエラーが生成されます。
ERROR #5540: SQLCODE: -124 Message: At least 1 Row exists in table 'HealthLanguage.FKey2' which references key NewIndex1 - Foreign Key Constraint 'NewForeignKey1' (Field 'Pointer1') failed on referential action of NO ACTION [Execute+5^CacheSql16:USER]
このチェックは、以下のいずれかを使用してシステム全体で抑制できます。
-
管理ポータルに移動します。[システム管理] から、[構成]、[SQL およびオブジェクトの設定]、[一般SQL設定] (システム, 構成, 一般SQL設定) を選択します。この画面で、[INSERT、UPDATE、DALETE の外部キーについて参照整合性チェックを実行する] の現在の設定を表示できます。既定は “はい” です。
-
$SYSTEM.SQL.SetFilerRefIntegrity()Opens in a new tab メソッドを呼び出します。
永続クラス定義を使用してテーブルを定義する場合、NoCheck キーワードを指定して外部キーを定義すると、その外部キーの今後のチェックを抑制できます。CREATE TABLE にはこのキーワード・オプションはありません。
特定の操作のチェックを抑制するには、%NOCHECK キーワード・オプションを使用します。
既定では、Caché は次の各操作に対して、外部キーの参照整合性チェックを実行します。指定されたアクションが参照整合性に違反する場合、このコマンドは実行されません。
-
ALTER TABLE DROP COLUMN。
-
ALTER TABLE DROP CONSTRAINT。SQLCODE -317 を発行します。外部キーの整合性チェックは、SET OPTION COMPILEMODE=NOCHECK を使用して抑制できます。
-
DROP TABLE。SQLCODE -320 を発行します。外部キーの整合性チェックは、SET OPTION COMPILEMODE=NOCHECK を使用して抑制できます。
-
TRUNCATE TABLE (DELETE と同様の考慮事項が適用されます)。
-
トリガ・イベント (BEFORE イベントなど)。例えば、DELETE 操作が外部キーの参照整合性に違反するために実行されない場合、BEFORE DELETE トリガは実行されません。
親テーブルと子テーブルの識別
埋め込み SQL では、ホスト変数配列を使用して、親テーブルと子テーブルを識別できます。子テーブルの場合、ホスト変数配列の添え字 0 は parentref または parentref||childref の形式で親参照に設定されています。親テーブル場合、添え字 0 は未定義です。詳細は、以下の例を参照してください。
&sql(SELECT *,%TABLENAME INTO :tflds(),:tname
FROM Aviation.Event )
IF SQLCODE=0 {
IF $DATA(tflds(0)) {
WRITE tname," is a child table",!,"parent ref: ",tflds(0),! }
ELSE {WRITE tname," is a parent table",! }
}
ELSE {WRITE "SQLCODE error=",SQLCODE,! }
&sql(SELECT *,%TABLENAME INTO :tflds(),:tname
FROM Aviation.Aircraft )
IF SQLCODE=0 {
IF $DATA(tflds(0)) {
WRITE tname," is a child table",!,"parent ref: ",tflds(0),! }
ELSE {WRITE tname," is a parent table",! }
}
ELSE {WRITE "SQLCODE error=",SQLCODE,! }
&sql(SELECT *,%TABLENAME INTO :tflds(),:tname
FROM Aviation.Crew )
IF SQLCODE=0 {
IF $DATA(tflds(0)) {
WRITE tname," is a child table",!,"parent ref: ",tflds(0),! }
ELSE {WRITE tname," is a parent table",! }
}
ELSE {WRITE "SQLCODE error=",SQLCODE,! }