SQL サポート

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

ターゲット・システム リレーショナル・データベースへのアクセスのサポート
AIX®、HP-UX、iSeries™、Linux®、 Solaris、UNIX® システム・サービス、 Windows® 2000/NT/XP JDBC を使用して DB2® UDB、Oracle、Informix®、または Microsoft® SQL Server にアクセスできる

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

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

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

EGL 文と SQL

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

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

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
  // プログラムを終了する
  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);  // プログラムを終了する
  end

  try
    get next from selectEmp into :myRecord.empname;
  onException
    if (sysVar.sqlcode != 100)
      myErrorHandler(8);  // プログラムを終了する
    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); // プログラムを終了する
    end

    try
      get next from selectEmp into :myRecord.empname;
    onException
      if (sysVar.sqlcode != 100)
        myErrorHandler(8);  // プログラムを終了する
      end
    end
  end  // end while; 結果セットの最後の行が読み取られると
       // カーソルは自動的にクローズされる

  sysLib.commit;

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

  VGVar.handleHardIOErrors  = 1;

  try
    open selectEmp forUpdate for emp;
  onException
    myErrorHandler(8);    // プログラムを終了する
  end

  try
    get next emp;
  onException
    if (sysVar.sqlcode not noRecordFound)
      myErrorHandler(8);  // プログラムを終了する
    end
  end

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

    try
      replace emp;
    onException
      myErrorHandler(10);   // プログラムを終了する
    end

    try
      get next emp;
    on exception
      if (sysVar.sqlcode not noRecordFound)
        myErrorHandler(8);  // プログラムを終了する
      end
    end
  end  // end while; 結果セットの最後の行が読み取られると
       // カーソルは自動的にクローズされる

  sysLib.commit;

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

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)    // テーブル行に
                          // 同じキーがある場合
      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 の有無のテストおよびその設定

ビルド記述子オプション itemsNullable は、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 の処理の詳細については、『isNullable』および『itemsNullable』を 参照してください。

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

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

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

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

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

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

フィードバック
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.