You are here: Home DOA マニュアル シーケンス/デフォルト値/トリガーの利用
Document Actions

シーケンス/デフォルト値/トリガーの利用

SEQUENCEによるAutoIncカラムの実現

ORACLEのテーブルのカラム型には、いわゆるAutoInc型やAutoNumber型のように、新規レコードを挿入すると自動的にインクリメントされてユニークになることが保証されるカラム型というものはありません。

かわりに、SEQUENCEというカウンタ様の仕組みを利用して、新しいキー値を取得して使います。

  CREATE SEQUENCE MySeq
  START WITH 1
  INCREMENT BY 1;

のようにして作成したシーケンスを使って、新しいキーを取得してデータを挿入するには、このようにして、シーケンスのカウントアップを行います。

  INSERT INTO MyTable VALUES (MySeq.NextVal, Data1, Data2 ... )

あるいは、以下のように、シーケンスのカウントアップと挿入を2段階に分けて実行します。

  DECLARE
    NewKey NUMBER(10);
  BEGIN
    SELECT MySeq.Nextval INTO NewKey FROM dual;
    INSERT INTO TESTINS VALUES(NewKey, 'AA');
  END;

後者の方法は、Master/Detail関係にある複数テーブルに一度に新規レコードを追加する場合などにとられます。たとえばこんな風に…

  DECLARE
    NewKey NUMBER(10);
  BEGIN
    SELECT MySeq.Nextval INTO NewKey FROM dual;
    INSERT INTO MASTER VALUES(NewKey, 'AA');
    INSERT INTO DETAIL VALUES(NewKey, 0, 'CCD', 'EEE');
    INSERT INTO DETAIL VALUES(NewKey, 1, 'CCF', 'GGG');

  END;

TOracleDataSetを用いてデータを挿入する際に、SequenceFieldプロパティをセットしておくと、テーブルの特定カラムの値を、シーケンスから取得するようにできます。

  • TOracleDataSet
    • property SequenceField : 新規レコードの特定のカラムに、シーケンスから値を取得するよう設定します
      • Sequence: シーケンスの名称
      • Field : シーケンスから取得した値をセットすべきフィールド名
      • ApplyMoment: シーケンスからのキー取得のタイミング。 以下の3つのいずれかです。
        • On New Record : Append/Insert のタイミングでNextValを取得します
        • On Post : レコードを PostするタイミングでNextValを取得します
        • On Server : NextValは、INSERT文/UPDATE文の一部として実行されます。

たとえば、TOracleDataSet.SQL = SELECT EMPNO, ENAME, ...FROM EMP のとき、Sequence = MySeq, Field=EMPNOの場合、

  1. ApplyMoment = On New Record だとすると、OracleDataSet1.Append; によってSELECT MySeq.NextVal INTO *** が実行されて、その結果が即座にDataSetにセットされます。この場合、データセットの更新をCancelしても、シーケンスの値は元に戻らないので、カウンタの値を一つ無駄にしてしまうことになります。
  2. ApplyMoment = On Post だと、Appendの時点でDataSetのEMPNOフィールドはNULLのままで、ENAMEプロパティをセットしてPostするタイミングで、まずSELECT MySeq.NextVal INTO *が実行され、ついでその結果のキー値をDataSetのEMPNOフィールドにセットしてから、INSERT文が実行されます。(このApplyMoment=OnPost**が基本と考えていいでしょう)
  3. ApplyMoment = On Server の場合、Append/ Post の時点で、データセットのEMPNOフィールドはNULLのまま、INSERT INTO EMP VALUES( MySeq.NextVal, ENAME, ....) が実行されます。これによって、データベース上のテーブルには新しいキー値を持つ有効なレコードが作成されますが、このままではローカルのTOracleDataSet上のレコードのEMPNOはNULLのままです。そのため、TOracleDataSetのRefreshOptionsプロパティを適切にセットして、データの更新後にレコードの再読込を行わせる必要があります。なお、RefreshOptions.roAfterInsertがセットされている場合には、この方法が効率的です。

デフォルト値およびトリガーによる更新に関する考慮

テーブルのカラムはデフォルト値が設定できます。たとえば

  create table TestTable
  (
    KEY  number not null,
    DATA number default 0 not null
  );

のようにして作成したテーブルにデータを挿入する際、DATAフィールドの値が与えられなかった場合、デフォルト値の0がテーブルにセットされます。

また、このようにトリガーが設定されていると、テーブルデータを更新する都度、トリガーが働いてデータが更新されます。

  create or replace trigger MyTrigger
    before update on testtable  
    for each row
  begin
    Update testtable
    Set data = data + 1;
  end MyTrigger;

これらの機能はデータの整合性を保つために有用ですが、サーバ上でデータが自動的に更新されることによって、クライアントのTOracleDataSetが保持しているデータレコードと、サーバ上のレコードのデータ間に不一致が生ずる原因となりえます。この不一致を解消するためには、随時サーバからデータを読み込みなおす必要があります。このためにRefreshOptionsプロパティを使います。

  • TOracleQuery
    • property RefreshOptions: サーバデータ読み込みのタイミングを設定します。以下の4つのタイミングの組み合わせです
      • roAfterInsert : INSERT終了後に、サーバからデータを読み直し、デフォルト値やトリガーの結果を反映します
      • roAfterUpdate : UPDATE終了後に、サーバからデータを読み直し、デフォルト値やトリガーの結果を反映します
      • roBeforeEdit : 他のユーザがレコードを更新していれば、その変更を編集直前に再読込します。後述の、レコードロックに関する説明を参考にしてください。
      • roAllFields : TRUEの場合JOINで結合された他のテーブルのレコードや、計算項目も読み直します。この際、もとのSQL文のWHERE句に rowid = :rowid を加えたクエリが実行されますが、もとのWHERE句の条件によってはこのクエリにヒットするレコードが0件になってしまう問題があるため、工夫が必要になることがあります。詳しくはTOracleQuery.RefreshOptionsのヘルプを参照してください。

△[] ▼[続き]