Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (日本語) » SQL Remote » SQL Remote のレプリケーション設計 » SQL Remote のレプリケーション設計と設定 » 切断データ分割の使用

 

BEFORE UDPATE トリガの使用

次の例では、3 つのテーブル Customers、Contacts、SalesReps に、営業担当者と顧客間の対話に関する情報が格納されています。各営業担当者は、複数の顧客に対して販売活動を行います。連絡先が 1 箇所だけの顧客もいれば、複数ある顧客もいます。

Contacts テーブルには、Customers テーブルへの外部キーがあります。Customers テーブルには、SalesReps テーブルへの外部キーがあります。

テーブルの詳細については、Contacts、Customers、SalesReps テーブルの説明を参照してください。

営業担当者は、SalesRep テーブルのコピー、営業担当者に割り当てられた顧客の詳細が格納されている Customers テーブルのコピー、顧客に対応する窓口の詳細が格納された Contacts テーブルのコピーを提供するパブリケーションに対してサブスクライブします。たとえば、各営業担当者は、次のパブリケーションに対してサブスクライブします。

CREATE PUBLICATION SalesRepData (
   TABLE SalesReps
   TABLE Customers
      SUBSCRIBE BY rep_key
   TABLE Contacts
      SUBSCRIBE BY (SELECT rep_key
         FROM Customers
         WHERE Contacts.cust_key = Customers.cust_key )
);

このパブリケーションの詳細については、切断データ分割の使用を参照してください。

参照整合性の維持

サブスクライバ間のローの再割り当ては、営業担当者間に顧客を定期的に再割り当てする営業支援アプリケーションに共通の機能で、「領域の再編成」とも呼ばれます。

統合データベースでは、新しい営業担当者に顧客が再割り当てされると、Customers テーブルの rep_key 値が更新されます。

次の文では、顧客 cust1 を別の営業担当者 rep2 に再割り当てします。

UPDATE Customers
SET rep_key = 'rep2'
WHERE cust_key = 'cust1';

この更新は、次のようにレプリケートされます。

  • 以前の営業担当者のリモート・データベースの Customers テーブルに対する DELETE 文として。

  • 新しい営業担当者のリモート・データベースの Customers テーブルに対する INSERT 文として。

Contacts テーブルは変更されません。統合データベースのトランザクション・ログには、Contacts テーブルに関するエントリがありません。そのため、リモート・データベースの SQL Remote は、Contacts テーブルの cust_key ローを再割り当てできません。この再割り当てができないことによって、以前の営業担当者のリモート・データベースの Contacts テーブルには、すでに存在しない顧客の cust_key 値が含まれるという参照整合性の問題が発生します。

解決法としては、BEFORE UPDATE トリガを使用します。BEFORE UPDATE トリガはデータベース・テーブルをまったく変更しませんが、統合データベースのトランザクション・ログにエントリを作成します。

この BEFORE UPDATE トリガは、次のように起動する必要があります。

  • UPDATE 文が実行される前。したがって、ローの BEFORE 値が評価され、トランザクション・ログに追加されます。

  • 各文ではなく FOR EACH ROW。トリガの提供する情報を新しいサブスクリプション式とする必要があります。

たとえば、次の文では、BEFORE UPDATE トリガを作成します。

CREATE TRIGGER "UpdateCustomer" BEFORE UPDATE OF "rep_key"
// only fire the trigger when we modify rep_key, not any other column
ORDER 1 ON "Cons"."Customers"
/* REFERENCING OLD AS old_name NEW AS new_name */
REFERENCING NEW AS NewRow
   OLD AS OldRow
FOR EACH ROW 
BEGIN
// determine the new subscription expression
   // for the Customers table
	 UPDATE Contacts
   PUBLICATION SalesRepData
   OLD SUBSCRIBE BY ( OldRow.rep_key )
   NEW SUBSCRIBE BY ( NewRow.rep_key )
   WHERE cust_key = NewRow.cust_key;
END
;

SQL Remote は、トランザクション・ログに記録された情報を使用して、どのサブスクライバがどのローを受信するかを決定します。

この文を実行した後、統合データベースのトランザクション・ログには 2 つのエントリが含まれています。

  • BEFORE UPDATE トリガによって生成された、Contacts テーブルの INSERT 文と DELETE 文。

    --BEGIN TRIGGER-1029-0000461705
    --BEGIN TRANSACTION-1029-0000461708
    BEGIN TRANSACTION
    go
    --UPDATE PUBLICATION-1029-0000461711 Cons.Contacts
    --PUBLICATION-1029-0000461711-0002-NEW_SUBSCRIBE_BY-rep2
    --PUBLICATION-1029-0000461711-0002-OLD_SUBSCRIBE_BY-rep1
    --NEW-1029-0000461711
    --INSERT INTO Cons.Contacts(contact_key,name,cust_key)
    --VALUES ('5','Joe','cust1')
    go
    --OLD-1029-0000461711
    --DELETE FROM Cons.Contacts
    -- WHERE contact_key='5'
    go
    --END TRIGGER-1029-0000461743
    
  • 実行された元の UPDATE 文と、それぞれローが挿入または削除されたユーザの INSERT 文と DELETE 文。

    --PUBLICATION-1029-0000461746-0002-NEW_SUBSCRIBE_BY-rep2
    --PUBLICATION-1029-0000461746-0002-OLD_SUBSCRIBE_BY-rep1
    --NEW-1029-0000461746
    --INSERT INTO Cons.Customers(cust_key,name,rep_key)
    --VALUES ('cust1','company1','rep2')
    go
    --OLD-1029-0000461746
    --DELETE FROM Cons.Customers
    -- WHERE cust_key='cust1'
    go
    --UPDATE-1029-0000461746
    UPDATE Cons.Customers
       SET rep_key='rep2'
    VERIFY (rep_key)
    VALUES ('1')
     WHERE cust_key='cust1'
    go
    --COMMIT-1029-0000461785
    COMMIT WORK

SQL Remote は、BEFORE タグと AFTER タグのトランザクション・ログをスキャンします。この情報に基づいて、どのリモート・ユーザが INSERT 文、UPDATE 文、または DELETE 文を取得するかが決定されます。

  • ユーザが BEFORE list に含まれていて AFTER list に含まれていない場合は、DELETE 文が Contacts テーブルに送信されます。

  • ユーザが AFTER list に含まれていて BEFORE list に含まれていない場合は、INSERT 文が Contacts テーブルに送信されます。

  • ユーザが BEFORE list と AFTER list の両方に含まれている場合は、Contacts テーブルに対して何も実行されませんが、Customers テーブルの UPDATE 文は送信されます。

BEFORE list と AFTER list の値が同じ場合は、リモート・ユーザがすでにローを保有しているため、UPDATE 文が送信されます。

トリガに関する注意事項

次の例では、BEFORE UPDATE トリガを使用する必要があります。他のコンテキストでは、BEFORE DELETE トリガと BEFORE INSERT トリガが必要です。

UPDATE table-name
PUBLICATION pub-name
   SUBSCRIBE BY sub-expression
WHERE search-condition;

この例では、BEFORE トリガを使用します。

UPDATE table-name
PUBLICATION publication-name
   OLD SUBSCRIBE BY old-subscription-expression
   NEW SUBSCRIBE BY new-subscription-expression
WHERE search-condition;

UPDATE 文は、変更が適用されるパブリケーションとテーブルをリストします。文中の WHERE 句は、変更が適用されるローを示します。この UPDATE 文では、テーブルのデータは変更されませんが、トランザクション・ログにエントリが作成されます。

この例では、サブスクリプション式は 1 つの値を返します。ただし、複数の値を返すサブクエリも使用できます。サブスクリプション式の値は、更新を実行した後の値とする必要があります。

この例では、ローへのサブスクライバのみが新しい営業担当者になります。既存のサブスクライバと新しいサブスクライバを持つローの例については、重複分割の使用を参照してください。