アプリケーション開発の手引き

検索済みデータの更新と削除

カーソルによって参照された行は、更新したり削除したりできます。更新可能な行の場合、カーソルに対応する照会は読み取り専用であってはなりません。照会が更新可能または削除可能になる条件については、 SQL 解説書 の説明を参照してください。

検索されたデータの更新

カーソルを用いて更新を行うためには、 UPDATE ステートメントで WHERE CURRENT OF 文節を使用してください。結果表の列を更新したいシステムを示すには、FOR UPDATE 文節を使用します。 FOR UPDATE での列の指定は全部を選択しなくてもよいため、カーソルで明確に検索されない列でも更新することができます。 FOR UPDATE 文節を列名を使わずに指定すると、表の中のすべての列や、外部で全選択された最初の FROM 文節で識別された視点は更新可能であるとみなされます。 FOR UPDATE 文節では、必要以上の列を指定しないでください。 FOR UPDATE 文節の余分な列に名前を付けると、 DB2 がデータにアクセスする能率を低下させる場合もあります。

検索されたデータの削除

カーソルを用いた削除は、DELETE ステートメントで WHERE CURRENT OF 文節を使用して行います。一般に、FOR UPDATE 文節はカーソルの現在行の削除には必要ありません。 SAA1 に設定された LANGLEVEL でプリコンパイルされ、 BLOCKING ALL でバインドされたアプリケーション内の SELECT ステートメントまたは DELETE ステートメントのいずれかに対して動的 SQL (動的 SQL については、動的 SQL プログラムの作成を参照) を使った場合だけは例外です。この場合、SELECT ステートメントで FOR UPDATE 文節を指定する必要があります。プリコンパイラー・オプションの詳細については、 コマンド解説書 を参照してください。

DELETE ステートメントを使用すると、カーソルで参照される行を削除することができます。このとき、カーソルは次の 行の前に置かれたままになるため、カーソルに対して WHERE CURRENT OF 操作をさらに実行する前に、 FETCH ステートメントを発行する必要があります。

カーソルのタイプ

カーソルは以下の 3 種類に分類されます。

読み取り専用
このカーソルの行は読み取り専用で、更新することはできません。読み取り専用カーソルは、アプリケーションがデータを読み取る場合にだけ使用され、データの修正には使用されません。カーソルは、読み取り専用の選択ステートメントに基づいている場合に限り、読み取り専用とみなされます。更新可能でない結果表を定義する選択ステートメントについては、 検索されたデータの更新で説明した規則を参照してください。

読み取り専用カーソルにはパフォーマンス上の利点もあります。読み取り専用カーソルの詳細については、 管理の手引き: インプリメンテーション を参照してください。

更新可能
このカーソルの行は更新することができます。アプリケーションがカーソルの行の取り出しに伴ってデータを修正する場合に、更新可能カーソルを使用します。指定した照会は、表または視点を 1 つだけ参照することができます。また、照会には FOR UPDATE 文節を組み込んで、更新されるそれぞれの列に名前を付ける必要があります (LANGLEVEL MIA プリコンパイル・オプションを使用しない場合)。

未確定
定義または文脈からはカーソルが更新可能か読み取り専用かを判別することができません。こうした状況は、本来なら読み取り専用のはずのカーソルが動的 SQL ステートメントによって変更される場合に生じます。

未確定カーソルは、プリコンパイル時またはバインド時に BLOCKING ALL オプションが指定されると読み取り専用とみなされます。そうでない場合は、更新可能とみなされます。
注:動的に処理されるカーソルは常に未確定です。

カーソルが読み取り専用か更新可能か未確定かを判別するための基準を示した全リストについては、 SQL 解説書 を参照してください。

例: OPENFTCH プログラム

この例では、カーソルを使用して表から選択し、カーソルをオープンし、その表から行を取り出します。そして、取り出したそれぞれの行に対して、削除すべきか更新すべきかを (単純な基準に基づいて) 判別します。このサンプルは、以下のプログラミング言語で入手可能です。

C
openftch.sqc

Java
Openftch.sqlj および OpF_Curs.sqlj

COBOL
openftch.sqb

REXX 言語は静的 SQL をサポートしないため、サンプルはありません。

OPENFTCH プログラムの動作の仕組み

  1. カーソルを宣言する。 DECLARE CURSOR ステートメントはカーソル c1 を照会に関連付けます。照会は、アプリケーションが FETCH ステートメントを用いて取り出す行を識別します。 staffjob フィールドは、結果表に指定されていなくても更新可能として定義されます。
  2. カーソルをオープンする。カーソル c1 がオープンすると、データベース・マネージャーは照会を実行し、結果表を作成します。カーソルは第 1 行目より前に 置かれます。
  3. 行を取り出す。 FETCH ステートメントはカーソルを次の行に置き、その行の内容をホスト変数に移動します。この行が現在 行になります。
  4. 現在行を更新または削除する。現在行が更新されるか削除されます。更新か削除かは、 FETCH ステートメントで戻される dept の値によって決まります。

    UPDATE ステートメントは現在行の位置を変更しないため、カーソルの位置はこの行から変わりません。

    一方、DELETE ステートメントを用いると、現在 行は削除されるため、状況は変化します。これは、次の 行の前に置かれることと同じであり、追加の WHERE CURRENT OF 操作が実行される前に FETCH ステートメントを発行する必要があります。

  5. カーソルをクローズする。 CLOSE ステートメントを発行すると、カーソルに関連したリソースが解放されます。ただし、カーソルは再度オープンすることができます。

CHECKERR マクロ / 関数は、プログラム外部にあるエラー検査ユーティリティーです。エラー検査ユーティリティーの所在は、ご使用のプログラミング言語により異なります。

C
DB2 API を呼び出す C プログラムの場合、 utilapi.c 内の sqlInfoPrint 関数は、 utilapi.h 内の API_SQL_CHECK として再定義されます。 C 組み込み SQL プログラムの場合、 utilemb.sqc 内の sqlInfoPrint 関数は、 utilemb.h 内の EMB_SQL_CHECK として再定義されます。

Java
すべての SQL エラーは SQLException としてスローされ、アプリケーションの catch ブロックで処理されます。

COBOL
CHECKERRcheckerr.cbl という名前の外部プログラムです。

このエラー検査ユーティリティーのソース・コードについては、 プログラム例での GET ERROR MESSAGE の使用を参照してください。

C の例: OPENFTCH.SQC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "utilemb.h"
EXEC SQL INCLUDE SQLCA;
int main(int argc, char *argv[]) 
{
   EXEC SQL BEGIN DECLARE SECTION;
      char   pname[10];
      short  dept;
      char userid[9];
      char passwd[19];
   EXEC SQL END DECLARE SECTION;
   printf( "Sample C program: OPENFTCH\n" );
   if (argc == 1) 
   {
      EXEC SQL CONNECT TO sample;
      EMB_SQL_CHECK("CONNECT TO SAMPLE");
   }
   else if (argc == 3) 
   { 
      strcpy (userid, argv[1]);
      strcpy (passwd, argv[2]);
      EXEC SQL CONNECT TO sample USER :userid USING :passwd;
      EMB_SQL_CHECK("CONNECT TO SAMPLE");
   }
   else 
   {
      printf ("\nUSAGE: openftch [userid passwd]\n\n");
      return 1;
   } /* endif */
   
   EXEC SQL DECLARE c1 CURSOR FOR  (1)
            SELECT name, dept FROM staff WHERE job='Mgr'
            FOR UPDATE OF job;
   EXEC SQL OPEN c1;  (2)
   EMB_SQL_CHECK("OPEN CURSOR");
   do 
   {
      EXEC SQL FETCH c1 INTO :pname, :dept;  (3)
      if (SQLCODE != 0) break;
      if (dept > 40) 
      {
         printf( "%-10.10s in dept. %2d will be demoted to Clerk\n",
            pname, dept );
         EXEC SQL UPDATE staff SET job = 'Clerk'  (4)
            WHERE CURRENT OF c1;
         EMB_SQL_CHECK("UPDATE STAFF");
      } 
      else 
      {
         printf ("%-10.10s in dept. %2d will be DELETED!\n",
            pname, dept);
         EXEC SQL DELETE FROM staff WHERE CURRENT OF c1;
         EMB_SQL_CHECK("DELETE");
      } /* endif */
   } while ( 1 );
   EXEC SQL CLOSE c1;  (5)
   EMB_SQL_CHECK("CLOSE CURSOR");
   EXEC SQL ROLLBACK;
   EMB_SQL_CHECK("ROLLBACK");
   printf( "\nOn second thought -- changes rolled back.\n" );
   EXEC SQL CONNECT RESET;
   EMB_SQL_CHECK("CONNECT RESET");
   return 0;
}
/* end of program : OPENFTCH.SQC */

Java の例: Openftch.sqlj

OpF_Curs.sqlj

//  PURPOSE : This file, named OpF_Curs.sqlj, contains the definition 
//            of the class OpF_Curs used in the sample program Openftch. 
import sqlj.runtime.ForUpdate;
#sql public iterator OpF_Curs implements ForUpdate (String, short);

Openftch.sqlj

import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
class Openftch 
{   static
  {   try
    {   Class.forName ("COM.ibm.db2.jdbc.app.DB2Driver").newInstance ();
    } 
    catch (Exception e)
    {   System.out.println ("\n  Error loading DB2 Driver...\n");
      System.out.println (e);
      System.exit(1);
    }
  }
  public static void main(String argv[])
  {   try 
    {   System.out.println ("  Java Openftch Sample");
      String url = "jdbc:db2:sample";       // URL is jdbc:db2:dbname
      Connection con = null;          
      // Set the connection
      if (argv.length == 0) 
      {   // connect with default id/password
        con = DriverManager.getConnection(url);  
      }
      else if (argv.length == 2)
      {   String userid = argv[0];
        String passwd = argv[1];
        // connect with user-provided username and password
        con = DriverManager.getConnection(url, userid, passwd); 
      }
      else 
      {   throw new Exception(
                 "\nUsage: java Openftch [username password]\n");
      } // if - else if - else 
      // Set the default context
      DefaultContext ctx = new DefaultContext(con);            
      DefaultContext.setDefaultContext(ctx);
      // Enable transactions
      con.setAutoCommit(false);
      // Executing SQLJ positioned update/delete statements.
      try
      {   OpF_Curs forUpdateCursor;
        String name = null;
        short  dept=0;
        #sql forUpdateCursor = 
        {   SELECT name, dept 
                FROM staff
                WHERE job='Mgr' 
        }; // #sql            (1)(2)
        while (true) 
        {   #sql 
          {   FETCH :forUpdateCursor
                  INTO :name, :dept
          }; // #sql                        (3)
          if (forUpdateCursor.endFetch()) break;
          if (dept > 40)
          {   System.out.println (
                  name + " in dept. " 
                  + dept + " will be demoted to Clerk");
            #sql
            {   UPDATE staff SET job = 'Clerk'
                WHERE CURRENT OF :forUpdateCursor
            }; // #sql                    (4)
          }
          else
          {   System.out.println (
                  name + " in dept. " + dept
                  + " will be DELETED!");
            #sql
            {   DELETE FROM staff
                WHERE CURRENT OF :forUpdateCursor
            }; // #sql
          } // if - else
        }
        forUpdateCursor.close();  (5)
      }
      catch( Exception e )
      {   throw e; 
      } 
      finally
      {   // Rollback the transaction
        System.out.println("\nRollback the transaction...");
        #sql { ROLLBACK };
        System.out.println("Rollback done.");
      } // try - catch - finally
    }
    catch( Exception e )
    {   System.out.println (e);
    } // try - catch
  } // main
} // class Openftch

COBOL の例: OPENFTCH.SQB

       Identification Division.
       Program-ID. "openftch".
       Data Division.
       Working-Storage Section.
           copy "sqlca.cbl".
           EXEC SQL BEGIN DECLARE SECTION END-EXEC.
       01 pname             pic x(10).
       01 dept              pic s9(4) comp-5.
       01 userid            pic x(8).
       01 passwd.
         49 passwd-length   pic s9(4) comp-5 value 0.
         49 passwd-name     pic x(18).
           EXEC SQL END DECLARE SECTION END-EXEC.
       77 errloc          pic x(80).
       Procedure Division.
       Main Section.
           display "Sample COBOL program: OPENFTCH".
      * Get database connection information.
           display "Enter your user id (default none): " 
                with no advancing.
           accept userid.
           if userid = spaces
             EXEC SQL CONNECT TO sample END-EXEC
           else
             display "Enter your password : " with no advancing
             accept passwd-name.
      * Passwords in a CONNECT statement must be entered in a VARCHAR format
      * with the length of the input string.
           inspect passwd-name tallying passwd-length for characters
              before initial " ".
           EXEC SQL CONNECT TO sample USER :userid USING :passwd
               END-EXEC.
           move "CONNECT TO" to errloc.
           call "checkerr" using SQLCA errloc.
           EXEC SQL DECLARE c1 CURSOR FOR                               (1)
                    SELECT name, dept FROM staff
                    WHERE job='Mgr'
                    FOR UPDATE OF job END-EXEC.
           EXEC SQL OPEN c1 END-EXEC                                    (2)
           move "OPEN" to errloc.
           call "checkerr" using SQLCA errloc.
      * call the FETCH and UPDATE/DELETE loop.
           perform Fetch-Loop thru End-Fetch-Loop
              until SQLCODE not equal 0.
           EXEC SQL CLOSE c1 END-EXEC.                                  (5)
           move "CLOSE" to errloc.
           call "checkerr" using SQLCA errloc.
           EXEC SQL ROLLBACK END-EXEC.
           move "ROLLBACK" to errloc.
           call "checkerr" using SQLCA errloc.
           display "On second thought -- changes rolled back.".
           EXEC SQL CONNECT RESET END-EXEC.
           move "CONNECT RESET" to errloc.
           call "checkerr" using SQLCA errloc.
       End-Main.
           go to End-Prog.
       Fetch-Loop Section.
           EXEC SQL FETCH c1 INTO :pname, :dept END-EXEC.               (3)
           if SQLCODE not equal 0
              go to End-Fetch-Loop.
           if dept greater than 40
              go to Update-Staff.
       Delete-Staff.
           display pname, " in dept. ", dept,
              " will be DELETED!".
           EXEC SQL DELETE FROM staff WHERE CURRENT OF c1 END-EXEC.
           move "DELETE" to errloc.
           call "checkerr" using SQLCA errloc.
           go to End-Fetch-Loop.
       Update-Staff.
           display pname, " in dept. ", dept,
              " will be demoted to Clerk".
           EXEC SQL UPDATE staff SET job = 'Clerk'                      (4)
                    WHERE CURRENT OF c1 END-EXEC.
           move "UPDATE" to errloc.
           call "checkerr" using SQLCA errloc.
       End-Fetch-Loop. exit.
       End-Prog.
           stop run.


[ ページのトップ | 前ページ | 次ページ | 目次 | 索引 ]