Skip to main content

This documentation is for an older version of this product. See the latest version of this content.Opens in a new tab

テーブル間のリレーションシップ

外部キーを定義して、テーブル間の参照整合性を強制できます。外部キー制約を持つテーブルを変更する際に、外部キー制約が確認されます。

外部キーの定義

InterSystems SQL で外部キーを定義するには、以下のような方法があります。

外部キー参照として使用される RowID フィールドは、パブリックである必要があります。パブリック (またはプライベート) RowID フィールドを含むテーブルを定義する方法については、"RowID は非表示か" を参照してください。

1 つのテーブル (クラス) のための外部キーの最大数は 400 です。

外部キーの参照整合性チェック

外部キー制約では、更新または削除時の参照アクションを指定できます。DDL を使用したこの参照アクションの定義については、"CREATE TABLE" の "参照アクション節" を参照してください。テーブルに投影される永続クラスを使用したこの参照アクションの定義については、"クラス定義リファレンス" の "OnDelete" および "OnUpdate" Foreign Key キーワードで定義されています。シャード・テーブルの作成時には、これらの参照アクションを NO ACTION に設定する必要があります。

既定では、InterSystems IRIS® データ・プラットフォームは INSERTUPDATEDELETE の各操作に対して、外部キーの参照整合性チェックを実行します。操作が参照整合性に違反する場合、その操作は行われず、その操作によって 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^IRISSql16:USER] 

他の方法でテーブルにデータを入力する場合、参照整合性制約が適用されない可能性があります。これが心配な場合は、テーブル・データを検証してください。

このチェックをシステム全体で抑制するには、$SYSTEM.SQL.Util.SetOption()Opens in a new tab メソッドを SET status=$SYSTEM.SQL.Util.SetOption("FilerRefIntegrity",0,.oldval) のように使用します。既定値は 1 です (参照整合性制約チェックが実行されます)。現在の設定を確認するには、$SYSTEM.SQL.CurrentSettings()Opens in a new tab を呼び出します。

既定では、外部キーを持つ行が削除されると、InterSystems IRIS は対応する参照先テーブルの行に対する長期間 (トランザクションが終了するまで) の共有ロックを取得します。これにより、参照している行で DELETE トランザクションが完了するまで、参照先の行を更新または削除できなくなります。これにより、参照先の行が削除され、その後、参照している行の削除がロール・バックされる状況を回避することができます。もし、このような状況が発生した場合、外部キーは存在しない行を参照することになります。外部キーが NoCheck を指定して定義されている場合、または参照している行の DELETE が %NOCHECK または %NOLOCK と共に指定されている場合、このロックは取得されません。

テーブルの定義に永続クラス定義を使用している場合、NoCheck キーワードを指定して外部キーを定義すると、その外部キーの今後のチェックを抑制できます。CREATE TABLE にはこのキーワード・オプションはありません。

特定の操作のチェックを抑制するには、%NOCHECK キーワード・オプションを使用します。

既定では、InterSystems IRIS は次の各操作に対しても、外部キーの参照整合性チェックを実行します。指定されたアクションが参照整合性に違反する場合、このコマンドは実行されません。

  • 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 トリガは実行されません。

親子リレーションシップでは、子の順序は定義されていません。アプリケーション・コードは特定の順序に依存しないでください。

親テーブルと子テーブル

このセクションでは、親/子リレーションシップの定義および操作の概要について説明します。詳細は、"クラスの定義と使用" の “リレーションシップの定義と使用” の章を参照してください。

親テーブルと子テーブルの定義

テーブルに投影される永続クラスを定義する際、リレーションシップ・プロパティを使用して、2 つのテーブル間の親子リレーションシップを指定できます。

以下の例では、親テーブルを定義します。

Class Sample.Invoice Extends %Persistent 
{
Property Buyer As %String(MAXLEN=50) [Required];
Property InvoiceDate As %TimeStamp;
Relationship Pchildren AS Sample.LineItem [ Cardinality = children, Inverse = Cparent ];
}

以下の例では、子テーブルを定義します。

Class Sample.LineItem Extends %Persistent 
{
Property ProductSKU As %String;
Property UnitPrice As %Numeric;
Relationship Cparent AS Sample.Invoice [ Cardinality = parent, Inverse = Pchildren ];
}

管理ポータルの SQL インタフェース [カタログの詳細] タブの [テーブル情報] で、子テーブルまたは親テーブル (あるいはその両方) の名前を指定します。子テーブルの場合は、Cparent->Sample.Invoice など、親テーブルへの参照を指定します。

子テーブル自体が、子テーブルの親になることができます (このような子の子は、"孫" テーブルと呼ばれます)。この場合、[テーブル情報] で親テーブルと子テーブル両方の名前を指定します。

親テーブルと子テーブルへのデータの挿入

親テーブルに各レコードを挿入してから、子テーブルに対応するレコードを挿入する必要があります。以下に例を示します。

INSERT INTO Sample.Invoice (Buyer,InvoiceDate) VALUES ('Fred',CURRENT_TIMESTAMP)
INSERT INTO Sample.LineItem (Cparent,ProductSKU,UnitPrice) VALUES (1,'45-A7',99.95)
INSERT INTO Sample.LineItem (Cparent,ProductSKU,UnitPrice) VALUES (1,'22-A1',0.75)

対応する親レコード ID がない子レコードを挿入しようとすると、SQLCODE -104 エラーが生成され、%msg は、"子テーブル 'Sample.LineItem' が親テーブル内の存在しない行を参照しています" のようになります。

子テーブルへの INSERT 操作時には、親テーブル内の対応する行に共有ロックがかかります。この行は、子テーブル行の挿入中はロックされます。その後、ロックは解除されます (トランザクションの終了までロック状態が継続することはありません)。これにより、参照される親の行がこの挿入操作の間に変更されることがなくなります。

親テーブルと子テーブルの識別

埋め込み SQL では、ホスト変数配列を使用して、親テーブルと子テーブルを識別できます。子テーブルでは、ホスト変数配列の添え字 0 は parentref の形式で親参照 (Cparent) に設定され、添え字 1 は parentref||childref の形式で子レコード ID に設定されています。親テーブル場合、添え字 0 は未定義です。詳細は、以下の例を参照してください。

   KILL tflds,SQLCODE,C1
   &sql(DECLARE C1 CURSOR FOR
        SELECT *,%TABLENAME INTO :tflds(),:tname
        FROM Sample.Invoice)
   &sql(OPEN C1)
        IF SQLCODE<0 {WRITE "Serious SQL Error:",SQLCODE," ",%msg  QUIT}
    &sql(FETCH C1)
       IF SQLCODE=100 {WRITE "The ",tname," table contains no data",!  QUIT}
       WHILE $DATA(tflds(0)) {
                              WRITE tname," is a child table",!,"parent ref: ",tflds(0)," %ID: ",tflds(1),!
                              &sql(FETCH C1)
                              IF SQLCODE=100 {QUIT}
                             }
      IF $DATA(tflds(0))=0 {WRITE tname," is a parent table",!}
    &sql(CLOSE C1)
      IF SQLCODE<0 {WRITE "Error closing cursor:",SQLCODE," ",%msg  QUIT}
   KILL tflds,SQLCODE,C1
   &sql(DECLARE C1 CURSOR FOR
        SELECT *,%TABLENAME INTO :tflds(),:tname
        FROM Sample.LineItem)
   &sql(OPEN C1)
       IF SQLCODE<0 {WRITE "Serious SQL Error:",SQLCODE," ",%msg  QUIT}
   &sql(FETCH C1)
       IF SQLCODE=100 {WRITE "The ",tname," table contains no data",! QUIT}
       WHILE $DATA(tflds(0)) {
                              WRITE tname," is a child table",!,"parent ref: ",tflds(0)," %ID: ",tflds(1),!
                              &sql(FETCH C1)
                              IF SQLCODE=100 {QUIT}
                             }
      IF $DATA(tflds(0))=0 {WRITE tname," is a parent table",!}
  &sql(CLOSE C1)
    IF SQLCODE<0 {WRITE "Error closing cursor:",SQLCODE," ",%msg  QUIT}

子テーブルの場合、tflds(0) および tflds(1) は以下のような値を返します。

parent ref: 1 %ID: 1||1
parent ref: 1 %ID: 1||2
parent ref: 1 %ID: 1||3
parent ref: 1 %ID: 1||9
parent ref: 2 %ID: 2||4
parent ref: 2 %ID: 2||5
parent ref: 2 %ID: 2||6
parent ref: 2 %ID: 2||7
parent ref: 2 %ID: 2||8

"孫" テーブルの場合 (子テーブルの子であるテーブル)、tflds(0) および tflds(1) は以下のような値を返します。

parent ref: 1||1 %ID: 1||1||1
parent ref: 1||1 %ID: 1||1||7
parent ref: 1||1 %ID: 1||1||8
parent ref: 1||2 %ID: 1||2||2
parent ref: 1||2 %ID: 1||2||3
parent ref: 1||2 %ID: 1||2||4
parent ref: 1||2 %ID: 1||2||5
parent ref: 1||2 %ID: 1||2||6
FeedbackOpens in a new tab