親テーブルと子テーブルの定義
テーブルに投影される永続クラスを定義する際、リレーションシップ・プロパティを使用して、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