SQL データ

SQL (3 つの文字をばらばらに発音します) は、リレーショナル・データベース管理システム (DBMS) と通信するための言語です。一方、DBMS は、相互に接続された表でビジネス情報を管理するデータベースを制御するシステムです。

EGL には、SQL データを処理するための 2 つの方法が用意されています。

EGL を使用すれば、2 つのスタイルを組み合わせることもできます。ユーザーは、EGL が EGL コードから生成した SQL ステートメントにアクセスし、変更することができます (暗黙の SQL ステートメントの表示を参照してください)。

このセクションのトピックには、以下の情報が記載されています。

EGL の方式

下の表に、EGL を使用してリレーショナル・データベースと対話する方法の概略を示します。

表 1. EGL SQL のためのベスト・プラクティス
SQL の目的 EGL によるアプローチ
簡単な SQL データ操作 (SELECT、UPDATE、INSERT、DELETE)。主キー・コントロール WHERE および ORDER BY。 EGL キーワード (getreplaceadddelete) を使用して、EGL で暗黙的 SQL を生成します。
再使用可能なカスタム WHERE 文節による、簡単な SQL データ操作。 カスタムの WHERE 文節を defaultSelectCondition プロパティーに指定します。
カスタムの WHERE 文節を含む SQL SELECT ステートメント。 #sql ディレクティブを介して、明示的 SQL を使用します。
SQL テーブルの JOIN ステートメント。 ワークベンチで「SQL を検索」機能を使用して defaultSelectCondition プロパティーを作成し、主キーおよび外部キーでテーブルが正しく結合されるように使用します。
defaultSelectCondition = #sqlCondition{
  customer.customer_ID = 
  orders.customer_ID }
SELECT コマンド内の派生データ (MAX()、AVG() など) #sql ディレクティブを介して明示的 SQL を使用し、派生フィールドを中括弧内に指定します。
個々のフィールドの column プロパティーで派生式または計算式を指定する、カスタム SQLRecord を作成します。
複雑な、あるいはカスタムの、SQL UPDATE、INSERT、または DELETE ステートメント。 EGL の replaceadd、または delete の各ステートメントを、明示的 SQL (#sql ディレクティブ) とともに使用します。
execute #sql ステートメントを介して、明示的 SQL を使用します。
簡単なデータ操作以外の SQL ステートメント (CREATE TABLE など)。 execute #sql ステートメントを介して、明示的 SQL を使用します。
動的 SQL (準備済み SQL ステートメント)。 execute #sql ステートメントを介して、明示的 SQL を使用します。
ストアード・プロシージャー。

次のような明示的 SQL を使用します。
open result_set with #sql{
  CALL stored_proc ( :host_var) }

SQL SELECT ステートメントの結果セットの行を個別に処理。 EGL open コマンドを使用して結果セットを開き、以下のいずれかのステートメントを使用してループを開始します。
  • forEach (from result_set)
  • while (sqlLib.sqlData.sqlcode == 0)
オンライン検索のためのプログラマチック・ページング。 「データ・アクセス・アプリケーション」ウィザードを使用します。
SQL テーブルへのデータの追加。 ワークベンチのデータ・パースペクティブで、テーブル・エディターを使用します。
SQL ステートメントの妥当性検査 EGL エディターのコンテキスト・メニューで、「SQL の妥当性検査」を選択します。
ワークベンチのデータ・パースペクティブで SQL エディターを使用して、対話式 SQL を実行します。

結果セット処理

一連の行を更新するための一般的な方法を使用するには、以下の手順に従います。
  1. forUpdate オプションを使用して EGL open ステートメントを実行することで、カーソルを宣言して開きます。このオプションにより、選択された行は、これ以降の更新または削除のためにロックされます。
  2. EGL get next ステートメントを実行することで、1 つの行を取り出します。
  3. forEach ループで、以下のアクションを実行します。
    1. データを結果セットからホスト変数内に取り出します。 ホスト変数は SQL ステートメントの変数で、冒頭にコロン文字 (:) を追加することにより、ホスト言語 (この場合、EGL が SQL ステートメントをホストします) の変数と同じ名前になります。
    2. EGL replace または EGL delete ステートメントを実行することで、行を更新または削除します。
    3. EGL get next ステートメントを実行することで、別の行を取り出します。
  4. EGL commit() 関数を実行することで、変更をコミットします。

カーソルを開き、そのカーソルの行で動作するステートメントは、結果セット ID によってお互いに関連しています。この ID は、プログラム内のすべての結果セット ID およびプログラム変数の中で固有でなければなりません。カーソルを開く open ステートメントでその ID を指定し、 ループを作成する forEach ステートメントで同じ ID を参照します。 また、個々の行に影響を与える get nextdelete、および replace ステートメントや、 カーソルを閉じる close ステートメントで、その ID を参照します。

特化されたタイプの EGL レコード、SQLRecord を使用して、リレーショナル・データベースに読み書きする情報を保持することができます。以下の例は、SQL をユーザー自身でコーディングするときの一連の行の更新方法を示したものです。
  try
    open selectEmp forUpdate for emp;
  onException(sqlx SqlException)
    myErrorHandler(sqlx);    // プログラムを終了する
  end

  foreach(emp)
    emp.empname = emp.empname :: " " :: "III";
    try 
      replace emp;
    onException(sqlx SqlException)
      myErrorHandler(sqlx);    // プログラムを終了する
    end
  end  // end while; 結果セットの最後の行が読み取られると
       // カーソルは自動的にクローズされる

  sysLib.commit();

EGL open ステートメントを処理するときに (SQL レコードを使用しているかどうかに関係なく) 定期的に変更をコミットするには、hold ステートメント・オプションを使用し、これによってコミット後もカーソル位置は保持されます。ただし、CICS® を 宛先としたプログラムがセグメント化されている場合、セグメント化されたプログラム の converse によって CICS トランザクションが終了し、プログラムがファイルやデータベースの位置を保存しないため、hold オプションは効果がありません。

SQL レコードおよびその使用法

SQLRecord パーツを定義した後、そのパーツに基づいて変数を宣言します。このレコード変数を使用して、あたかもファイルにアクセスするかのように、リレーショナル・データベースにアクセスすることができます。例えば、変数 myEmpRecord がデータベース表 EMPLOYEE を参照している SQLRecord パーツに基づいている場合、EGL add ステートメントで myEmpRecord を使用することができます。
  add myEmpRecord;
この場合、EGL はデータを myEmpRecord から EMPLOYEE に挿入します。EGL ステートメントが実行された後、レコード変数には以下のとおり、エラー状態についての情報が含まれます。
  try
    add myEmpRecord;
  onException(sqlx SqlException)
    if (myEmpRecord is unique) // テーブル行が同じキーを持った場合
      myErrorHandler(sqlx);
    end
  end
myEmpRecord などのレコード変数を使用して、リレーショナル・データベースと対話します。
  • SQLRecord パーツを定義して、関連するレコード変数を宣言します。
  • SQL レコードを使用して入出力を実行する EGL ステートメントを書き込みます。
  • EGL ステートメントのデフォルトの振る舞いを受け入れるか (ほとんどの場合、これで必要な状態が提供される)、またはビジネス・ロジックに適した SQL 変更を行います。

SQLRecord パーツと関連レコードの定義

SQLRecord パーツを定義し、各フィールドとリレーショナル・テーブルまたはビューの列を関連付けます。EGL は自動的にこれを行うことができます。 SQL テーブル・データの検索を参照してください。

SQLRecord パーツが固定レコード・パーツでない場合、プリミティブ・フィールドと他の変数を組み込むことができます。通常、以下の種類の変数を組み込みます。
  • 他の SQL レコード。各レコードは、親テーブルと子テーブルの間の 1 対 1 の関係を表します。
  • SQL レコードの配列。各レコードは、親テーブルと子テーブルの間の 1 対多の関係を表します。

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

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

SQLRecord パーツの定義後、そのパーツに基づいたレコード変数を宣言します。

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

各ステートメントがレコード変数をステートメントの入出力オブジェクトとして使用する、一連のステートメントを作成することができます。各ステートメントに対して、EGL は暗黙の SQL ステートメントを提供します。このステートメントは、ソースにはありませんが、レコード変数と EGL ステートメントの組み合わせによって暗黙で存在します。 例えば、EGL add ステートメントの場合、暗黙 の SQL INSERT ステートメントは特定のレコード内のフィールド値を、関連付けられたテーブル列に配置します。レコード変数に、テーブル列が割り当てられていないフィールドが含まれている場合、フィールド名が列名と同一であるという前提で、EGL は暗黙の SQL ステートメントを形成します。

以下の EGL ステートメントは、示された SQL ステートメントに対応します。

表 2. 暗黙の SQL 文
EGL ステートメント SQL ステートメント
add INSERT
delete DELETE
getopen SELECT
replace UPDATE

暗黙の SELECT ステートメント

レコード変数を使用する EGL ステートメント、および SQL SELECT ステートメントまたはカーソル宣言のいずれかを生成する EGL ステートメントを定義すると、EGL は暗黙の SQL SELECT ステートメントを提供します。このステートメントは、カーソル宣言があれば、そのカーソル宣言に 組み込まれます。例えば、以下の SQLRecord パーツに基づいて変数を宣言することができます。
  Record Employee type sqlRecord
    { tableNames = [["EMPLOYEE"]],
      keyItems = ["empnum"] }
    empnum decimal(6,0);
    empname char(40);
  end
次に、このレコードに基づいて変数を宣言します。
myEmpRecord Employee;
その後、get ステートメントをコーディングすることができます。
  get myEmpRecord;
暗黙の SQL SELECT ステートメントは以下のとおりです。
  SELECT empnum, empname
  FROM   EMPLOYEE
  WHERE  empnum = :empnum
また、EGL は、スタンドアロンの SELECT ステートメント (カーソル宣言が使用されていない場合)、またはカーソルに関連付けられた FETCH ステートメントに INTO 文節を配置します。 この INTO 文節により、SELECT ステートメントの最初の文節にリストされている列から値を 受け取るホスト変数がリストされます。
  INTO :empnum, :empname
暗黙の SELECT ステートメントは、各列の値を対応するホスト変数に読み取り、レコード変数で指定されたテーブルを参照し、以下の 2 つの要因の組み合わせによって異なる検索基準 (WHERE 文節) を持ちます。
  • defaultSelectCondition レコード・プロパティーに指定した値。
  • 以下の 2 組の値の間の関係 (同等など)。
    • テーブル・キーを構成する列の名前。
    • レコード・キーを構成するホスト変数の値。
    EGL は、tableNames レコード・プロパティー または EGL ステートメントのusingKeys 節から関係を推論します。

暗黙の SELECT ステートメントについて詳しくは、「EGL 言語解説書」の個々のキーワード・トピックを参照してください。

カーソルによる SQL レコード

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

また、特定のレコード変数に対して 1 つのカーソルのみを開くことができます。 EGL ステートメントによってカーソルが開かれる場合、同じレコード変数に対して別のカーソルが開かれていると、生成されたコードによって最初のカーソルは自動的に閉じます。

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

入出力オブジェクトとして SQL レコード変数を使用する EGL ステートメントがある場合、以下の 2 つのうちのいずれかの方法で先に進むことができます。
  • 暗黙の SQL ステートメントを受け入れます。この場合、SQLRecord パーツに対する変更は、実行時に使用される SQL ステートメントに影響を与えます。例えば、後に別のフィールドを SQL レコードのキーとして使用することを示した場合、EGL によって SQLRecord パーツに基づいた任意のカーソル宣言で使用される暗黙の SELECT ステートメントが変更されます。
  • 代わりに、SQL ステートメントを明示的にすることを選択します。EGL は、ユーザーの コードに暗黙の SQL ステートメントを挿入し、ユーザーがそれらのステートメントを変更できるよう にします。 この場合、その SQL ステートメントの詳細は SQLRecord パーツとは分離しており、SQLRecord パーツに対するこれ以降の変更は、実行時に使用される SQL ステートメントに影響を与えません。

    ソースから明示的な SQL ステートメントを除去すれば、暗黙の SQL ステートメントが (もしあれば) 生成時に再び使用可能になります。

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

部門の一連の従業員のデータを取り出すようなプログラムを許可する場合、2 つの SQLRecord パーツと 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(myDeptRecord Dept)
   get myDeptRecord.employees usingKeys myDeptRecord.deptNo;
end

NULL テストおよび設定

変数を NULL 可能にする、すなわち変数に NULL 値を受け入れる場合、変数を「?」型拡張文字で宣言します。
Record Employee type SQLRecord
   employeeID CHAR(6);
   empDeptNo INT?;
end
NULL 値をテストするには、標準 EGL if ステートメントを使用します。
if (myEmpRecord.empDeptNo == null)
   ...
end
NULL 値を直接変数に割り当てることができます。
myEmpRecord.empDeptNo = null;
この構文は、ターゲットが NULL 可能ではない場合でも機能します。そのような場合、 このステートメントは、次のステートメントと同じ効果をもたらします。
set myEmpRecord.empDeptNo empty;

互換性

表 3. SQL の互換性に関する考慮事項
プラットフォーム 問題
CICS for z/OS®、z/OS バッチ、iSeriesC 生成されたコードは、DB2® UDB に直接アクセスできます
AIX®、HP-UX、iSeriesJ、Linux、Solaris、z/OS UNIX システム・サービス、Windows 2000/NT/XP JDBC は DB2 UDB、Oracle、Informix®、または Microsoft SQL Server へのアクセスを提供します

フィードバック