SQL サポート

次の表のように、EGL 生成 コードは、いずれかのターゲット・システム上 にあるリレーショナル・データベースにアクセスできます。

ターゲット・システム リレーショナル・データベースへのアクセスのサポート
CICS® for z/OS®、z/OS バッチ 生成されたコードは DB2® UDB に直接アクセスできる
AIX®、iSeries™、Linux™, Windows® 2000/NT/XP、z/OS UNIX® システム・サービス JDBC を使用して DB2 UDB、Oracle、または Informix® にアクセスできる
ターゲット・システム リレーショナル・データベースへのアクセスのサポート
AIX、iSeries、Linux, Windows 2000/NT/XP、UNIX システム・サービス JDBC を使用して DB2 UDB、Oracle、または Informix にアクセスできる

プログラムの作成時には、他のほとんどの言語でプログラムをコーディングしている場合と同じように、 SQL ステートメントをコーディングすることができます。SQL ステートメントを簡単に作成できるよう、EGL は埋めるだけでよい SQL ステートメントのテンプレートがあります。

これ以外にも、EGL ステートメントをコーディングする場合には、SQL レコードを入出力オブジェクトとして使用することができます。このようにレコードを使用すると、提供されている SQL ステートメントをカスタマイズしたり、SQL をコーディングしなくても済むデフォルトをそのまま使用して、 データベースにアクセスできます。

いずれの場合も、EGL の SQL サポートについて以下の点に注意してください。

EGL ステートメントと SQL

リレーショナル・データベースへのアクセスに利用できる EGL キーワードは、次の表のとおりです。この表には、各キーワードに対応する SQL ステートメントの概要も含まれています。例えば、EGL の add ステートメントをコーディングする場合は、SQL INSERT ステートメントを生成します。

多くのビジネス・アプリケーションでは、EGL の open 文と各種の get by position 文を使用します。このコードは、カーソル (これは、以下の振る舞いをする実行ランタイム・エンティティーです) を宣言し、オープンし、処理するのに役立ちます。
  • 検索基準を満たす行のリストである結果セット を戻す。
  • 結果セット内の特定の行を指す。

出力が Java™ コードの場合、EGL の open 文を使用して、 ストアード・プロシージャーを呼び出すことができます。このプロシージャーは、EGL の外部で作成されたロジックで構成され、 データベース管理システムに保管され、結果セットも戻します。(出力言語に関係なく、また、EGL の execute 文を使用してもストアード・プロシージャーを戻すことができます。)

結果セットの処理の詳細については、後のセクションで説明します。

SQL ステートメントを明示的にコーディングする場合は、EGL の execute ステートメントと、 場合によっては EGL の prepare ステートメントを使用します。

キーワードおよび目的 SQL ステートメントの概要 SQL を変更できるかどうか
add

データベース内に 1 行挿入する。 または、(SQL レコードの動的配列を使用している場合は) 配列の連続するエレメントの内容に基づき、行のセットを挿入する。

行の INSERT (挿入) (動的配列を指定している場合は、繰り返し発生します)。 可能
close

未処理の行を解放する。

カーソルの CLOSE (クローズ) 不可
delete

行をデータベースから削除する。

行の DELETE (削除)。行は、次の 2 つの方法で選択されました。
  • forUpdate オプションを指定して get 文を呼び出す場合 (同一のキー値を持つ複数の行の最初の行を選択する場合に該当)
  • forUpdate オプションを指定して open 文を呼び出し、続いて get next 文を呼び出す場合 (行のセットを選択し、取り出したデータをループ内で処理する場合に該当)
不可
forEach

ループで実行される一連の文の始まりを示します。最初の反復が発生するのは、指定された結果セットが使用可能であり、(多くの場合) その結果セット内の最後の行が処理されるまでの間、継続している場合だけです。

EGL は forEach 文を、ループ内で実行される SQL FETCH ステートメントに変換します。 不可
freeSQL

動的に準備された SQL ステートメントに関連したリソースを解放し、その SQL ステートメントに関連したすべてのオープン・カーソルをクローズする。

  不可
get (キー値による取得とも呼ばれる)

データベースから単一の行を読み取る。 または、(SQL レコードの動的配列を使用する場合) 連続する行を配列内の連続するエレメントに読み込む。

行の SELECT (選択)。ただし、singleRow オプションを設定した場合のみ。 それ以外の場合は、以下の規則が適用されます。
  • EGL では、get 文が以下のものに変換されます。
    • SELECT または (forUpdate オプションを設定している場合は) SELECT FOR UPDATE でカーソルを DECLARE (宣言)
    • カーソルの OPEN (オープン)
    • 行の FETCH (取り出し)
  • forUpdate オプションを指定しなかった場合は、EGL はカーソルもクローズします。
  • singleRow および forUpdate オプションは、動的配列ではサポートされていません。 その場合、EGL ランタイムはカーソルを宣言してオープンし、連続した行を取り出した後、カーソルをクローズします。
可能
get absolute

open 文によって選択された結果セット内の、番号で指定された行を読み取る。

EGL では、get absolute ステートメントが SQL FETCH ステートメントに変換されます。 不可
get current

open 文によって選択された結果セット内の、現在すでにカーソルが位置付けられている行を読み取る。

EGL では、get current ステートメントが SQL FETCH ステートメントに変換されます。 不可
get first

open 文によって選択された結果セット内の最初の行を読み取る。

EGL では、get first ステートメントが SQL FETCH ステートメントに変換されます。 不可
get last

open 文によって選択された結果セット内の最後の行を読み取る。

EGL では、get last ステートメントが SQL FETCH ステートメントに変換されます。 不可
get next

open 文によって選択された結果セット内の次の行を読み取る。

EGL では、get next ステートメントが SQL FETCH ステートメントに変換されます。 不可
get previous

open 文によって選択された結果セット内の前の行を読み取る。

EGL では、get previous ステートメントが SQL FETCH ステートメントに変換されます。 不可
get relative

open 文によって選択された結果セット内の、番号で指定された行を読み取る。この行は、結果セット内のカーソル位置との相対関係で識別されます。

EGL では、get relative ステートメントが SQL FETCH ステートメントに変換されます。 不可
execute

(例えば、CREATE TABLE 型の) SQL データ定義ステートメントを実行する。または、(例えば、INSERT または UPDATE の) データ操作ステートメントを実行する。または、SELECT 文節から始まらない準備済み SQL ステートメントを実行する。

作成した SQL ステートメントは、 データベース管理システムで使用できます。
execute の主な用途は、次の例に示しているように、 生成時に完全にフォーマット設定された単一 SQL ステートメントのコーディングです。
try
  execute
  #sql{    // no space after "#sql"
    delete
    from EMPLOYEE
    where department =
      :myRecord.department
  };
onException
  myErrorHandler(10);
end

完全にフォーマット設定された SQL ステートメントの WHERE 文節には、ホスト変数を組み込むことができます。

可能
open

後で get next 文を使用して行のセットを取り出すために、リレーショナル・データベースからその行セットを選択する。

EGL は、open 文を call 文に変換する (ストアード・プロシージャーにアクセスするため)、または以下の文に変換する。
  • SELECT または SELECT FOR UPDATE を使用した、カーソルの DECLARE (宣言)
  • カーソルの OPEN (オープン)
可能
prepare

SQL PREPARE ステートメントを指定する。このステートメントは、実行時にしかわからない詳細がオプションに含まれています。EGL の execute ステートメントを実行するか、(SQL ステートメントが SELECT で始まっている場合は) EGL の open または get ステートメントを実行して、準備済み SQL ステートメントを実行します。

EGL は prepare ステートメントを SQL の PREPARE ステートメントに変換します。このステートメントは、常に実行時に構成されます。以下に示した EGL の prepare 文の例では、 各パラメーター・マーカー (?) は、その後の execute 文の USING 文節によって解決されます。
myString = 
  "insert into myTable " +
  "(empnum, empname) " +
    "value ?, ?";

try
  prepare myStatement
    from myString;
onException
  // exit the program
  myErrorHandler(12);
end

try
  execute myStatement
  using :myRecord.empnum,
        :myRecord.empname;
onException
  myErrorHandler(15);
end
可能
replace

変更された行をデータベースに戻す。

行の UPDATE (更新)。行は、次の 2 つの方法で選択されました。
  • forUpdate オプションを指定して get 文を呼び出す場合 (同一のキー値を持つ複数の行の最初の行を選択する場合に該当)。または、
  • forUpdate オプションを指定して open 文を呼び出し、続いて get next 文を呼び出す場合 (行のセットを選択し、取り出したデータをループ内で処理する場合に該当)。
可能
注: いかなる場合でも、単一の EGL ステートメントをコーディングして、複数のデータベース表を更新することはできません。

結果セットの処理

一連の行を更新する一般的な方法は、以下のとおりです。
  1. forUpdate オプションを指定して EGL の open 文を実行し、 カーソルを宣言してからオープンする。このオプションを指定することにより、選択された行が、 それ以降の更新または削除に対してロックされます。
  2. EGL get next 文を実行して、1 つの行を取り出す。
  3. ループの中で以下の操作を行う。
    1. 取り出したデータの格納先のホスト変数内のデータを変更する。
    2. EGL replace 文を実行して、行を更新する。
    3. EGL get next 文を実行して、別の行を取り出す。
  4. EGL 関数 commit を実行して、変更をコミットする。

カーソルをオープンし、そのカーソルの行に対して実行される文は、 結果セット ID によって互いに関連付けられています。この結果セット ID は、 すべての結果セット ID、プログラム変数、およびプログラム内のプログラム・パラメーターに渡って一意である必要があります。この ID は、 カーソルをオープンする open 文で指定し、 個々の行に影響を与える get nextdeletereplace 文、およびカーソルをクローズする close 文で参照します。追加情報については、『resultSetID』を参照してください。

SQL をコーディングしている場合に、連続した行を更新する方法を次のコードに示します。
  VGVar.handleHardIOErrors  = 1;

  try
    open selectEmp forUpdate with
    #sql{  										// no space after "#sql"
      select empname
      from EMPLOYEE
      where empnum >= :myRecord.empnum
      for update of empname
    };
      
  onException
    myErrorHandler(8);    // exits program
  end

  try
    get next from selectEmp into :myRecord.empname;
  onException
    if (sysVar.sqlcode != 100)
      myErrorHandler(8);  // exit the program
    end
  end

  while (sysVar.sqlcode != 100)
    myRecord.empname = myRecord.empname + " " + "III";

    try
      execute
      #sql{
        update EMPLOYEE
        set empname = :empname
        where current of selectEmp
      };
    onException
      myErrorHandler(10);   // exits program
    end

    try
      get next from selectEmp into :myRecord.empname;
    onException
      if (sysVar.sqlcode != 100)
        myErrorHandler(8);  // exits program
      end
    end
  end  // end while; cursor is closed automatically
       // when the last row in the result set is read

  sysLib.commit;

上記の例で、あまり複雑なことをしたくない場合には、SQL レコードを考慮してみてください。SQL レコードを使用すると、コードを簡素化することができ、データベース管理システム全体で変わることのない入出力エラー値を使用することができます。次の例は上記の例と等価ですが、emp という SQL レコードを使用しています。

  VGVar.handleHardIOErrors  = 1;

  try
    open selectEmp forUpdate for emp;
  onException
    myErrorHandler(8);    // exits program
  end

  try
    get next emp;
  onException
    if (sysVar.sqlcode not noRecordFound)
      myErrorHandler(8);  // exit the program
    end
  end

  while (sysVar.sqlcode not noRecordFound)
    myRecord.empname = myRecord.empname + " " + "III";

    try
      replace emp;
    onException
      myErrorHandler(10);   // exits program
    end

    try
      get next emp;
    on exception
      if (sysVar.sqlcode not noRecordFound)
        myErrorHandler(8);  // exits program
      end
    end
  end  // end while; cursor is closed automatically
       // when the last row in the result set is read

  sysLib.commit;

SQL レコードについては、後述のセクションで説明します。

COBOL のコーディングの場合にも、(SQL レコードを使用するかどうかには関係なく) EGL の open ステートメントを処理するときのように、 定期的に変更をコミットしたい場合は、Hold というステートメント・オプションを使用します。このオプションを使用すると、コミット後もカーソルの位置が保持されます。ただし、CICS 向けのプログラムをセグメント化している場合は、Hold オプションは何の影響も与えません。それは、セグメント化されたプログラム内での対話により、CICS トランザクションが終了し、 そのプログラムがファイルまたはデータベースの位置を保持できなくなるからです。

SQL レコードおよびその値

SQL レコードとは、SQL レコード・パーツを元にした変数です。このタイプのレコードを使用すると、 あたかもファイルにアクセスしているかのように、リレーショナル・データベースと対話することができます。例えば、 変数 EMP がデータベース表 EMPLOYEE を参照している SQL レコード・パーツに基づいている場合、EGL の add ステートメントで EMP を次のように使用することができます。
  add EMP;
この場合、EGL は EMP のデータを EMPLOYEE に挿入します。SQL レコードにも状態情報が含まれるので、EGL ステートメントの実行後にその SQL レコードをテストして、データベース・アクセスが原因で発生した入出力エラー値に従って、タスクを条件付きで実行することができます。
  VGVar.handleHardIOErrors  = 1;

  try
    add EMP;
  onException
    if (EMP is unique)     // if a table row 
                          // had the same key
      myErrorHandler(8);
    end
  end
EMP のような SQL レコードを使用すると、以下のようにリレーショナル・データベースと対話することができます。
  • SQL レコード・パーツおよび関連する SQL レコードを宣言する
  • それぞれの EGL ステートメントが、SQL レコードを入出力オブジェクトとして使用する EGL ステートメントセットを定義する
  • EGL ステートメントのデフォルトの振る舞いを受け入れるか、またはビジネス・ロジックに適切な SQL 変更を行う。

SQL レコード・パーツおよび関連するレコードの宣言

SQL レコード・パーツを宣言し、各レコード項目をリレーショナル・テーブルまたはビューの 1 つの列に関連付けます。EGL エディターの取り出し機能を使用すると、 この関連づけを自動的に EGL に実行させることができます。これについては、『宣言時のデータベース・アクセス』で説明します。

SQL レコード・パーツが固定レコード・パーツでない場合は、プリミティブ・フィールドをその他の変数と同様に組み込むことができます。特に、次の種類の変数を組み込むことがよくあります。
  • 他の SQL レコード。それぞれの存在が、親テーブルと子テーブルの間にある 1 つの 1 対 1 の関係を表しています。
  • SQL レコードの配列。それぞれの存在が、親テーブルと子テーブルの間にある 1 つの 1 対多の関係を表しています。

プリミティブ型のフィールドのみが、データベースの列を表すことができます。

フィールドの前にレベル番号がある場合、SQL レコード・パーツは固定レコード・パーツです。以下の規則が適用されます。
  • 各 SQL レコード・パーツ内の構造体は、フラット である (階層構造でない) ことが必要です。
  • すべてのフィールドがプリミティブ・フィールドであることが必要ですが、BLOB、CLOB、または STRING 型であってはなりません。
  • レコード・フィールドを構造体フィールド配列にすることはできません。

SQL レコード・パーツの宣言後に、そのパーツに基づく SQL レコードを宣言します。

SQL 関連の EGL ステートメントの定義

EGL ステートメントのセットを定義して、そのセットのそれぞれの EGL ステートメントが SQL レコードを、 そのステートメントの入出力オブジェクトとして使用することができます。EGL は、 ステートメントごとに、暗黙の SQL ステートメントを提供します。このステートメントはソース内にはありませんが、SQL レコードと EGL ステートメントの組み合わせによって、 暗黙で存在しています。例えば、EGL の add ステートメントの場合、暗黙の SQL INSERT ステートメントによって、ある与えられたレコード項目の値が、そのレコード項目に関連付けられているテーブル列に挿入されます。テーブル列が割り当てられていないレコード項目が SQL レコードに含まれている場合、EGL は、 レコード項目の名前は列の名前と同一であると想定して、暗黙の SQL ステートメントを生成します。

暗黙の SELECT ステートメントの使用

SQL レコードを使用し、かつ SQL SELECT ステートメントまたはカーソル宣言を生成する EGL ステートメントを定義すると、EGL は 暗黙の SQL SELECT ステートメントを生成します。(この文は、 カーソル宣言があればそれに組み込まれます。)例えば、EMP という名前で、 以下のレコード・パーツに基づいている変数を宣言したとします。
  Record Employee type sqlRecord
    { tableNames = [["EMPLOYEE"]],
      keyItems = ["empnum"] }
    empnum decimal(6,0);
    empname char(40);
  end
さらに、次の get 文をコーディングしたとします。
  get EMP;
暗黙の SQL SELECT ステートメントは、次のようになります。
  SELECT empnum, empname
  FROM   EMPLOYEE
  WHERE  empnum = :empnum
EGL はまた、スタンドアロンの SELECT ステートメントか (カーソル宣言が含まれていない場合)、 カーソルに関連付けられている FETCH ステートメントに、INTO 文節を挿入します。INTO 文節は、SELECT ステートメントの最初の文節にリストされている列から値を受け取るホスト変数をリストします。
  INTO :empnum, :empname
暗黙の SELECT ステートメントは、各列値を対応するホスト変数に読み込み、SQL レコードで指定されているテーブルを参照します。また、2 つの因子の組み合わせ に依存する検索基準 (WHERE 文節) を持っています。
  • レコード・プロパティー defaultSelectCondition に対して指定した値
  • 2 つの値セットの間の関係 (等価関係など)
    • テーブル・キーを構成する列の名前
    • レコード・キーを構成するホスト変数の値
データを SQL レコードの動的配列に読み込むと、get ステートメントの場合にそうなることがあるように、 特別な状態になります。
  • カーソルがオープンしており、データベースの連続する行が、配列の連続するエレメントに読み込まれ、結果セットが解放され、カーソルがクローズされます。
  • SQL ステートメントを指定しない場合は、検索基準はレコード・プロパティー defaultSelectCondition によって異なり、以下の値セットの間の関係 (特に、以上、という関係) にも依存します。
    • EGL ステートメントで項目を指定するときに間接的に指定された列の名前
    • それら項目の値

    defaultSelectCondition プロパティーで指定されたホスト変数はすべて、 動的配列の基礎となる SQL レコードの外側にある必要があります。

暗黙の SELECT ステートメントについての詳細 (キーワードごとに変わります) は、get および open ステートメントを参照してください。

カーソルを使用した SQL レコードの使用

SQL レコードを使用している場合は、結果セット ID を使用する場合と同様に、 いくつかの EGL ステートメントで同一の SQL レコードを使用して、 カーソル処理ステートメント間を関連付けることができます。ただし、結果セット ID によって示されるステートメント相互関係が、SQL レコードで示される関係よりも優先し、 場合によっては、resultSetID を指定する必要があります。

また、特定の SQL レコードに対してオープンにしておくことのできるカーソルは 1 つだけです。別のカーソルが 同じ SQL レコードをオープンしているときに、EGL ステートメントによってあるカーソルがオープンしてしまうと、 生成されたコードは自動的に最初のカーソルをクローズしてしまいます。

SQL ステートメントのカスタマイズ

SQL レコードを入出力オブジェクトとして使用する EGL ステートメントが指定された場合、次のいずれかの方法を使用することができます。
  • 暗黙の SQL ステートメントを受け入れることができます。この場合は、SQL レコード・パーツに加えられた変更によって、 実行時に使用される SQL ステートメントが影響を受けます。例えば、SQL レコードのキーとして別のレコード項目を使用するということを後で示すと、EGL は、 その SQL レコード・パーツに基づいているカーソル宣言で使用される暗黙の SELECT ステートメントを変更します。
  • その代わりに、SQL ステートメントを明示的にすることができます。この場合は、SQL ステートメントの詳細は、SQL レコード・パーツから切り離され、 後からその SQL レコード・パーツに加えられた変更は、 実行時に使用される SQL ステートメントには影響を与えません。

    明示的な SQL ステートメントをソースから除去すると、 暗黙の SQL ステートメントがある場合は、生成時にそれがもう一度使用可能になります。

レコード内でのレコードの使用例

プログラムで、ある部門の一連の従業員のデータを取り出せるようにするには、次のように 2 つのレコード・パーツと 1 つの関数を作成します。
	DataItem DeptNo { column = deptNo } end

 Record Dept type SQLRecord
   deptNo DeptNo;
   managerID CHAR(6);
   employees Employee[];
 end

 Record Employee type SQLRecord
   employeeID CHAR(6);
   empDeptNo DeptNo;
 end

 Function getDeptEmployees(dept Dept)
   get dept.employees usingKeys dept.deptNo;
 end

NULL の有無のテストおよびその設定

EGL は、コード内の変数のサブセット用に、内部に NULL 標識を保守する場合があります。デフォルトの振る舞いを受け入れた場合、EGL は以下の特性を持つ変数用にのみ、内部で 1 つの変数につき 1 つの NULL 標識を保守します。
  • SQL レコード内に存在している
  • プロパティー isNullableyes に設定して宣言されている

SQL ステートメントでは、NULL 標識にホスト変数をコーディングしないでください (いくつかの言語ではコーディングすることがあります)。NULL 可能ホスト変数に NULL が含まれているかどうかをテストするには、EGL の if 文を使用します。切り捨てられた値を検索できるかどうかをテストすることもできますが、 これは NULL 標識が使用可能になっている場合だけです。

次の 2 つの方法のどちらかで、SQL テーブル列を NULL にすることができます。
  • EGL の set ステートメントを使用して、 NULL 可能ホスト変数を NULL にし、関連する SQL レコードをデータベースに書き込む。または、
  • SQL ステートメントを最初から作成するか、EGL の add ステートメントまたは replace ステートメントに関連付けられている SQL ステートメントをカスタマイズして、適切な SQL 構文を使用する。

NULL の処理の詳細については、『itemsNullable』および『SQL 項目のプロパティー』を参照してください。

宣言時のデータベース・アクセス

コードが実行時にアクセスするデータベースと同じ特性を持つデータベースに (宣言時に) アクセスすることに関しては、以下のような利点があります。
  • SQL レコードに関連付けられているテーブルまたはビューと等価なデータベース表またはビューに アクセスする場合に、EGL パーツ・エディターの取り出し機能を利用して、レコード項目を作成または上書きすることができます。取り出し機能は、データベース管理システムに保管されている情報にアクセスして、作成される項目の数およびデータ特性が表の列の数やデータ特性を反映することができるようにします。Retrieve 機能を起動した後、レコード項目の名前変更、レコード項目の削除、およびその他の変更を SQL レコードに対して行うことができます。
  • 適切に構造化されたデータベースに宣言時にアクセスすることは、等価 のデータベースに実行時にアクセスする SQL ステートメントが有効になること を保証する場合に有効です。

検索機能は、関連するテーブル列と各項目の名前が同じ (またはほとんど同じ) レコード項目を作成します。

DB2 の条件 WITH CHECK OPTIONS を使って定義されているビューは、取り出すことができない。

取り出し機能についての詳細は、『SQL テーブル・データの取り出し』を参照してください。命名の詳細については、『SQL 検索設定の変更』を参照してください。

宣言時にデータベースにアクセスするには、『SQL データベース接続設定の変更』を参照して、設定ページで接続情報を指定してください。

ご利用条件 | フィードバック
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.
(C) Copyright IBM Japan 2005.