データを挿入する際の値の選択

表に行を挿入するときに、挿入された行から値を同時に選択することもできます。

このタスクについて

1つ以上の新しい行をテーブルに挿入すると、次の値を含む行を取得できます。
  • ROWID または ID 列などの、自動的に生成された列の値
  • 列に対するデフォルト値のいずれか
  • 挿入された行のすべての値 (個々の列名を指定せずに)
  • 複数行 INSERT 操作によって挿入されたすべての値
  • BEFORE INSERT トリガーによって変更される値

プロシージャー

挿入される行から値を選択するには、

SELECT ステートメントのFROM節に INSERT ステートメントを指定してください。
ターゲット表に挿入する行によって結果表が生成され、その表の列を照会の SELECT リストで参照できます。 この結果表の列は、ターゲット表に定義された列、制約、およびトリガーによって影響されます。
  • 結果表には、ID 列、ROWID 列または行変更タイム・スタンプ列に対するDb2が生成した値が含まれます。
  • Db2結果テーブルを生成する前に、挿入操作に影響を与える制約(つまり、チェック制約、一意のインデックス制約、および参照整合性制約)を適用します。
  • 結果表には、挿入操作によってアクティブにされた BEFORE トリガーから発生する 何らかの変更が含まれます。 AFTER トリガーは、結果表の値には影響しません。

Db2サンプル表で例に加えて、このトピックの例では、次の定義を持つEMPSAMP表を使用します。

CREATE TABLE EMPSAMP
  (EMPNO     INTEGER GENERATED ALWAYS AS IDENTITY,
   NAME      CHAR(30),
   SALARY    DECIMAL(10,2),
   DEPTNO    SMALLINT,
   LEVEL     CHAR(30),
   HIRETYPE  VARCHAR(30) NOT NULL WITH DEFAULT 'New Hire',
   HIREDATE  DATE NOT NULL WITH DEFAULT);
例 1: 生成された列値の取得
新規従業員の行を、EMPSAMP 表に挿入する必要があるとします。 生成された EMPNO、HIRETYPE、および HIREDATE 列の値を見つけるには、次の SELECT FROM INSERT ステートメントを使用します。
SELECT EMPNO, HIRETYPE, HIREDATE
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, DEPTNO, LEVEL)
                    VALUES('Mary Smith', 35000.00, 11, 'Associate'));

SELECTステートメントは、EMPNO列のDb2生成されたID値、HIRETYPE列のデフォルト値「NewHire」、およびHIREDATE列のCURRENTDATE特殊レジスターの値を返します。

推奨: INSERT ステートメントを使用して親テーブルに行を挿入し、 Db2 (ROWIDまたはID列)によって生成された主キーの値を取得します。 別の INSERT ステートメントで、 この生成された値を従属表の外部キーの値として指定します。
例2:トリガーの更新値を取得します。
EMPSAMP 表に BEFORE INSERT トリガーが作成されて、'Associate' レベルのすべての新規従業員の給与を $5000 増額するものとします。 トリガーには次の定義が行われます。
CREATE TRIGGER NEW_ASSOC
  NO CASCADE BEFORE INSERT ON EMPSAMP
  REFERENCING NEW AS NEWSALARY
  FOR EACH ROW MODE DB2SQL
    WHEN (NEWSALARY.LEVEL = 'ASSOCIATE')
    BEGIN ATOMIC
      SET NEWSALARY.SALARY = NEWSALARY.SALARY + 5000.00;
    END;

次の SELECT ステートメントの FROM 文節の INSERT ステートメントで、 新規従業員が EMPSAMP 表に挿入されます。

SELECT NAME, SALARY
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, LEVEL)
                    VALUES('Mary Smith', 35000.00, 'Associate'));

SELECT ステートメントが戻すのは、INSERT ステートメントで明示的に指定された 初任給の 35000.00 ではなく 40000.00 の Mary Smith の給与です。

単一の行を挿入する際に値を選択する:

表に新しい行を挿入するときには、SELECT FROM INSERT ステートメントの結果表から任意の列を取り出すことができます。 このステートメントをアプリケーションに埋め込む場合、SELECT ...を使用して、行をホスト変数に取得します。 ステートメントの INTO書式。

例4: 構造体に挿入された行のあらゆる値を取得します。
構造体に挿入された行のすべての値を取得できます。 たとえば、次のステートメントでは、:empstructは、EMPSAMP表各列の変数で宣言されたホスト変数構造です。
EXEC SQL SELECT * INTO :empstruct
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, DEPTNO, LEVEL)
                    VALUES('Mary Smith', 35000.00, 11, 'Associate'));
例4:ビューにデータを挿入する場合の値の選択
検索条件を指定して定義されたビューを INSERT ステートメントが参照する場合、 そのビューは、WITH CASCADED CHECK OPTION オプションを指定して定義する必要があります。 ビューにデータを挿入するとき、SELECT FROM INSERT ステートメントの結果表に含まれる行は、ビュー定義の条件を満たす行のみです。

ビュー V1 は WITH CASCADED CHECK OPTION オプションを指定して定義されているため、INSERT ステートメントで V1 を参照できます。

CREATE VIEW V1 AS
  SELECT C1, I1 FROM T1 WHERE I1 > 10
  WITH CASCADED CHECK OPTION;

SELECT C1 FROM
  FINAL TABLE (INSERT INTO V1 (I1) VALUES(12));

値 12 はビュー定義の検索条件を満たし、この 結果表は挿入された行の C1 の値で構成されます。

ビュー定義の検索条件を満たさない値を使用すると、挿入操作が失敗し、Db2エラーが返されます。

例 5: 複数の行を挿入する場合の ROWID 値の選択
アプリケーション・プログラムで、複数行の挿入から値を取り出す には、INSERT ステートメントが、カーソルの SELECT ステートメントの FROM 文節内にあるように カーソルを宣言します。

従業員写真・履歴書表に挿入された ROWID 列の値を調べるには、次のカーソルを宣言できます。

EXEC SQL DECLARE CS1 CURSOR FOR
  SELECT EMP_ROWID
  FROM FINAL TABLE (INSERT INTO DSN8C10.EMP_PHOTO_RESUME (EMPNO)
                    SELECT EMPNO FROM DSN8C10.EMP);
例 6: FETCH FIRST節を使います。
従業員写真・履歴書表に挿入された先頭 5 行のみを見る場合は、FETCH FIRST 節を使用します。
EXEC SQL DECLARE CS2 CURSOR FOR
  SELECT EMP_ROWID
  FROM FINAL TABLE (INSERT INTO DSN8C10.EMP_PHOTO_RESUME (EMPNO)
                    SELECT EMPNO FROM DSN8C10.EMP)
  FETCH FIRST 5 ROWS ONLY;
例 7: INPUT SEQUENCE節を使います。
挿入される順序で行を取り出すには、INPUT SEQUENCE 節を使用します。
EXEC SQL DECLARE CS3 CURSOR FOR
  SELECT EMP_ROWID
  FROM FINAL TABLE (INSERT INTO DSN8C10.EMP_PHOTO_RESUME (EMPNO)
                    VALUES(:hva_empno)
                    FOR 5 ROWS)
  ORDER BY INPUT SEQUENCE;

INPUT SEQUENCE 文節を指定できるのは、INSERT ステートメントが SELECT ステートメント の FROM 文節内にある場合に限られます。 この例で、行は従業員番号の配列から挿入されます。

例8:複数のエンコードCCSIDを持つ行の挿入
ASCII 表に EBCDIC 表からの値を入れた後、ASCII 表から選択された値を見るものとします。 次のカーソルを使用すると、EBCDIC 列を選択し、ASCII 表に値を入れてから、ASCII 値を 取り出すことができます。
EXEC SQL DECLARE CS4 CURSOR FOR
  SELECT C1, C2
  FROM FINAL TABLE (INSERT INTO ASCII_TABLE
                    SELECT * FROM EBCDIC_TABLE);
例9:データを挿入時追加列の選択
INCLUDE 文節を使用して、結果表に新規列を導入できますが、ターゲット表に列を追加することはできません。

部門番号データをプロジェクト表に挿入する必要があるとします。 また、部門番号および対応する各部門の管理職番号を取り出したいとします。 MGRNO はプロジェクト表の列ではないので、INCLUDE 文節を使用して結果に管理職番号を含めることはできますが、挿入操作に含めることはできません。 次の SELECT FROM INSERT ステートメントは、挿入操作を実行し、データを取り出します。

DECLARE CS1 CURSOR FOR
 SELECT manager_num, projname FROM FINAL TABLE
   (INSERT INTO PROJ (DEPTNO) INCLUDE(manager_num CHAR(6))
      SELECT DEPTNO, MGRNO FROM DEPT);
例 10: 複数の行を挿入するときのカーソルの結果表
アプリケーション・プログラムで、表に複数行を挿入するときは、 INSERT ステートメントが、カーソルの SELECT ステートメントの FROM 文節内にあるように、 カーソルを宣言します。 カーソルの結果表は、OPEN カーソル処理の間に決められます。 結果表は、アプリケーションの他の処理の影響を受ける場合もあれば、 受けない場合もあります。

両方向スクロール・カーソルを宣言する際、INSERT ステートメントが カーソル指定の FROM 文節内にある場合は、 カーソルを INSENSITIVE キーワードを指定して宣言する必要があります。 結果表は、OPEN カーソル処理の際に生成され、 その後の変更を反映しません。 SENSITIVE DYNAMIC または SENSITIVE STATIC キーワードを指定したカーソルを宣言することはできません。

順方向カーソルを宣言すると、検索された更新内容または削除内容は、カーソルの結果表に影響しません。 結果表の行は、OPEN カーソル処理の間に決められます。

たとえば、アプリケーションがカーソルを宣言し、カーソルを開き、フェッチを実行し、表を更新してから、追加の行をフェッチするとします。

EXEC SQL DECLARE CS1 CURSOR FOR
  SELECT SALARY
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, LEVEL)
                    SELECT NAME, INCOME, BAND FROM OLD_EMPLOYEE);
EXEC SQL OPEN CS1;
EXEC SQL FETCH CS1 INTO :hv_salary;
/* print fetch result */
...
EXEC SQL UPDATE EMPSAMP SET SALARY = SALARY + 500;
while (SQLCODE == 0) {
  EXEC SQL FETCH CS1 INTO :hv_salary;
  /* print fetch result */
  ...
}

更新後にフェッチが行われると、カーソルのオープン後に生成された行が戻されます。 単純なSELECT(FROM節にINSERTステートメントがない)を使用する場合、使用するアクセスパスDb2によっては、フェッチによって更新された値が返される場合があります。

例11: WITH HOLD の効果
カーソルを WITH HOLD オプション指定で宣言して、カーソルをオープンすると、 すべての行がターゲット表に挿入されます。 WITH HOLD オプションは、カーソル定義の SELECT FROM INSERT ステートメントには影響しません。 ご使用のアプリケーションがコミットを行った後は、 挿入された行のすべての取り出しを継続できます。

Db2 サンプルアプリケーションのemployeeテーブルに5つの行があると想定します。 ご使用のアプリケーションは WITH HOLD カーソルの宣言、 カーソルのオープン、2 つの行のフェッチを行い、 コミットを行ってから、3 番目の行のフェッチを正常に行います。

EXEC SQL DECLARE CS2 CURSOR WITH HOLD FOR
  SELECT EMP_ROWID
  FROM FINAL TABLE (INSERT INTO DSN8C10.EMP_PHOTO_RESUME (EMPNO)
                    SELECT EMPNO FROM DSN8C10.EMP);
EXEC SQL OPEN CS2;                                /* Inserts 5 rows */
EXEC SQL FETCH CS2 INTO :hv_rowid;   /* Retrieves ROWID for 1st row */
EXEC SQL FETCH CS2 INTO :hv_rowid;   /* Retrieves ROWID for 2nd row */
EXEC SQL COMMIT;                                  /* Commits 5 rows */
EXEC SQL FETCH CS2 INTO :hv_rowid;   /* Retrieves ROWID for 3rd row */
例12: SAVEPOINT とROLLBACK の効果
セーブポイントは、リカバリー単位内でリレーショナル・データベースへの変更をロールバックできる先の時点です。 SAVEPOINT ステートメントを使用してセーブポイントを設定できます。

カーソルのオープン前にセーブポイントを設定してから、 そのセーブポイントをロールバックすると、挿入はすべて取り消されます。

ご使用のアプリケーションが、カーソルの宣言、セーブポイントの設定、カーソルのオープン、別のセーブポイントの設定、2 番目のセーブポイントへのロールバックを行い、次に最初のセーブポイントにロールバックするものとします。

EXEC SQL DECLARE CS3 CURSOR FOR
  SELECT EMP_ROWID
  FROM FINAL TABLE (INSERT INTO DSN8C10.EMP_PHOTO_RESUME (EMPNO)
                    SELECT EMPNO FROM DSN8C10.EMP);
EXEC SQL SAVEPOINT A ON ROLLBACK RETAIN CURSORS;       /* Sets 1st savepoint */ 
EXEC SQL OPEN CS3;
EXEC SQL SAVEPOINT B ON ROLLBACK RETAIN CURSORS;       /* Sets 2nd savepoint */
...
EXEC SQL ROLLBACK TO SAVEPOINT B;  /* Rows still in DSN8C10.EMP_PHOTO_RESUME */ 
...
EXEC SQL ROLLBACK TO SAVEPOINT A;            /* All inserted rows are undone */
例13: SELECT INTO 処理中エラー
アプリケーション・プログラムで SELECT FROM INSERT ステートメントを使用して 1 つ以上の行を表に挿入したときには、アプリケーション処理の中でエラーが発生した場所に応じて、挿入操作の結果表に影響が出る場合と出ない場合があります。

SELECT INTO ステートメントの際に挿入処理または選択処理が失敗した場合は、 ターゲット表に行は挿入されず、挿入処理の結果表から行は戻されません。 たとえば、Db2サンプルアプリケーションのemployeeテーブルに1つの行があり、SALARY列の値が9999000.00であるとします。

EXEC SQL SELECT EMPNO INTO :hv_empno
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY)
                    SELECT FIRSTNAME || MIDINIT || LASTNAME,
                           SALARY + 10000.00 
                    FROM DSN8C10.EMP)

10000.00 を追加すると、小数部のオーバーフロー が発生し、EMPSAMP 表に行は挿入されません。

例14: OPEN カーソル処理中エラー
OPEN カーソル処理の際に行の挿入が失敗すると、 それまでに正常に行われた挿入は取り消されます。 挿入の結果表は空になります。
例15:FETCH処理中のエラー
挿入操作の結果表から行を取り出す際に FETCH ステートメントが失敗すると、 アプリケーションには負の SQLCODE が戻されますが、 結果表には、依然として OPEN カーソル処理の際に確定されたオリジナルの数の行が入っています。 この時点では、挿入結果をすべて元に戻すことができます。

結果表に 100 行が入っていて、カーソルからフェッチされる 90 番目の行が負の SQLCODE を返すものとします。

EXEC SQL DECLARE CS1 CURSOR FOR
  SELECT EMPNO
  FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY)
                    SELECT FIRSTNAME || MIDINIT || LASTNAME, SALARY + 10000.00 
                      FROM DSN8C10.EMP);
EXEC SQL OPEN CS1;                                 /* Inserts 100 rows */
while (SQLCODE == 0) 
  EXEC SQL FETCH CS1 INTO :hv_empno;
if (SQLCODE == -904)           /* If SQLCODE is -904, undo all inserts */
  EXEC SQL ROLLBACK;
else                                           /* Else, commit inserts */
  EXEC SQL COMMIT;