SQL の get に関する考慮事項

SQL のコンテキストでは、get 文は、 結果セットからレコード・データを取り出します。

get ステートメントで結果セットを使用する場合、次の 2 とおりの方法があります。

EGL は、get 文やその文にある SQL レコード変数のプロパティーに基づき、 生成したコードに SQL SELECT 文を作成します。 この暗黙の SQL コードについて詳しくは、SQL データ・アクセスを参照してください。 あるいは、#sql ディレクティブを使用して、 独自の組み込み SQL コードを作成することもできます (sql ディレクティブを参照)。EGL の prepare 文を使用して実行時に SQL コードをアセンブルし、get 文からそのコードを参照することもできます。 この動的 SQL の使用について詳しくは、SQL データ・アクセスを参照してください。

singleRow オプションを指定する場合、SQL SELECT 文はスタンドアロンになります。 singleRow を指定しない場合は、SQL SELECT がカーソル宣言 (SQL OPEN 文) の文節になります。 EGL が生成する SQL コードについて詳しくは、SQL データ・アクセス を参照してください。

EGL では、get 文で使用するさまざまな位置オプション (absolute および next など) を提供しています。 これにより、結果セットの現在の位置に相対的な特定レコードを取得できます。 これを行うには、cursor を使用して、現在の位置をトラッキングする必要があります。 結果セットのカーソルのある位置にアクセスするには、定位置の get を使用する前に EGL の open ステートメントを使用します。 get...forUpdate ステートメントを使用することもできますが、 これはあまり一般的ではありません。

get 文のターゲットが単一の SQL レコード変数である場合、 この文はユーザーが提供する基準 (暗黙または組み込み) に一致する最初のレコードを戻します。 また、SQL レコード変数の動的配列をステートメントのターゲットに指定することもできます。この場合、get ステートメントは、一致する各行を、配列内の要素として戻します。

構文

get 文の構文図
SQLRecordVariable
SQL レコード変数の名前。 レコード・パーツ・プロパティー keyItems および defaultSelectCondition の値に従ってデータベース行を見つける動作がデフォルトの動作です。
forUpdate
get 文を使用して新規の結果セットを作成し、 後で任意のデータベース行を置換または削除する予定である場合は、このキーワードを組み込み、結果セットに対応する行をロックします。 データベース・マネージャーは、コミットが実行されるまで、ロックされた行の変更を他のプログラムに対して許可しません。 コミット処理の詳細については、作業論理単位を参照してください。
resultSetID
get 文を使用して新規の結果セットを作成する場合、 forUpdate キーワードで任意の ID を指定することにより、 後続の EGL の replacedeleteexecute、 または定位置の get 文、あるいは EGL の close 文中で、同じ結果セットを使用できます。
singleRow
このオプションは、get 文のキーが 1 行にのみ適用されることが確かであり、その行を更新または削除しない場合などに使用する、さらに効率的な SQL を生成します。 この場合、EGL はカーソルを作成しません。 キーが複数行に適用されるときにこのオプションを指定すると、実行時入出力エラーが発生します。
#sql{ sqlSelectStatement }
経験豊かな SQL プログラマーであれば、独自の SQL SELECT 文を組み込むことにより、 EGL が生成する SQL コードをオーバーライドできます (『sql ディレクティブ』の解説を参照)。 #sql と左中括弧の間にスペースを入れないでください。
次のような場合について考えてみます。ユーザーのコードには、SQL レコードを使用する get ステートメントまたは open ステートメントがあり、明示的な SQL を含み、INTO 文節がありません。例えば、このような get ステートメントを含む EGL コードを以下に示します。
customer CustomerRecordPart{};
get customer with #sql{
   select MySCHEMA.CUSTOMER.Column01
   from MYSCHEMA.CUSTOMER
   where MYSCHEMA.Column02 = "AZ"}; 
このコード内で参照されたレコード・パーツは、以下のとおりです。
Record CustomerRecordPart type SQLRecord {tableNames = [["MYSCHEMA.CUSTOMER"]]}
   customerNumber INT    {column = "MYSCHEMA.CUSTOMER.Column01"};
   ...
end

今ここで説明した get ステートメントまたは open ステートメントでは、SQL の SELECT 文節の列名に使用される修飾は、レコード・パーツ内の対応するフィールドで使用される修飾と一致する必要があります。

制約事項: 比較的複雑な SQL SELECT ステートメントをコーディングするとき、INTO 文節の作成を EGL 生成プログラムに依存するのではなく、ユーザーがこの文節を指定しなければならないことがあります。この状況は、(例として) 以下に示すように SELECT ステートメントで SQL CASE 式が使用される場合に発生します。
SELECT 
   CASE 
      WHEN  address1 <> '' THEN address1 
      WHEN  address2 <> '' THEN address2 
   END... 
初期の SELECT 文節にあるすべての項目が以下のいずれかのカテゴリーから取得される場合、この状況は発生しません
  • 列名
  • リテラル
  • CURRENT TIMESTAMP などの特殊レジスター
  • 演算子 ||、+、-、*、/ のいずれかで結合された列名、リテラル、および特殊レジスター
しかし、SELECT 文節が複雑な場合、SQL レコードを使用する際に問題につながることがあります。これは、有効な INTO 節を生成するには、選択する内容と一致するように値を column プロパティーに割り当てる必要があるためです。例えば、以下の初期 SELECT 文節には、上記のカテゴリーの項目の組み合わせが含まれています。
SELECT COLUMN01 || 10 + COLUMN02 * 5
関連する SQL レコード・パーツを以下に示します。
Record MyRecordPart type SQLRecord
   myField int { column = "COLUMN01 || 10 + COLUMN02 * 5" };
end

この最後のケースで、column プロパティーを設定せずに、独自の INTO 文節を書き込むことを検討してください。 この理由は、複雑な column プロパティー値にアクセスする EGL add または replace ステートメントをコーディングする場合、生成される SQL INSERT および SQL UPDATE ステートメントが無効になることがあるためです。

into ... target
この文節は、EGL が作成する暗黙の SQL コードの INTO 文節に相当します。 この INTO 文節により、結果セットから値を受け取る EGL 変数が識別されます。 個々の変数を指定することも、レコード名を指定することもできます。 レコード名を指定した場合、EGL はそのレコード内のすべてのフィールドを使用します。 この文節は、以下のいずれかの場合に SQL を処理するときに必要です。
  • get 文で SQL レコード変数を指定しなかった。
  • SQL レコード変数も組み込み SQL SELECT ステートメントも指定したが、ターゲットの SQL レコード変数に対応するフィールドを持たない SQL SELECT 文節に、 1 列以上の列がある。

into 文節の作成先は、EGL であって、SQL ではありません。 SQL 文のホスト変数の場合のように文節内の変数の名前をコロンで始めることはしないでください。 詳しくは、ホスト変数を参照してください。

get positionOptionSQLDynamicArray とともに使用すると、レコード変数内の動的配列フィールド、または指定された出現個所がフィールドにある、構造化レコード内の動的配列フィールドをターゲットにすることができます。構造化レコードを使用すると、COBOL 生成におけるパフォーマンスを向上させることができます。関連付けられた rowSetSize が、構造化レコード内の出現フィールドに指定された要素より大きい場合に、get positionOption ステートメントが、出現した配列の最大索引を超える要素に値を埋めようとすると、IndexOutOfBoundException がスローされます。
preparedStatementID
この識別子は、実行時に SQL SELECT 文を準備する EGL prepare 文を指します。 get 文 SQL SELECT 文を動的に実行します。詳しくは、SQL の prepare に関する考慮事項を参照してください。
using ... field
この文節は、EGL が作成する暗黙の SQL コードの USING 文節に相当します。 この USING 文節により、実行時に準備済み SQL SELECT 文で使用可能な EGL 変数が識別されます。 using 文節の作成先は、EGL であって、SQL ではありません。 SQL 文のホスト変数の場合のように文節内の変数の名前をコロンで始めることはしないでください。 詳しくは、ホスト変数を参照してください。
usingKeys ... field
ここで、SQL レコードのフィールド名を指定して、そのレコード定義で指定したキー・フィールドをオーバーライドできます。 例えば、CustomerRecord で定義したキー・フィールドは customerNumber であるが、customerName でレコードを検索したいという場合は、以下のコードを使用することができます。
get myCustomer usingKeys myCustomer.customerName;
または、全く別のレコードのフィールドに基づいて検索することもできます。
get myCustomer usingKeys myOrders.customerName;

usingKeys で指定するフィールド (複数可) は、 EGL が get 文から生成する暗黙の SQL 文の WHERE 文節に挿入されます。 その文の後に組み込み SQL コードを続ける場合は、その組み込みコードにより暗黙のコードがオーバーライドされます。

動的配列の場合、usingKeys 文節のフィールド (または SQL レコードのホスト変数) は、動的配列の基礎である SQL レコード変数に存在していてはなりません

forUpdate キーワードを指定すると、キー項目に関連付けられた列は、FOR UPDATE OF 文節でリストされる列から除外されます。

positionOption
新規の結果セットを作成するのではなく、既存の結果セットからデータを取り出す場合に、このオプションを使用します。 使用可能なオプションおよび詳細については、このトピックの『位置オプションの使用』を参照してください。
from resultSetID
位置オプションを使用する場合、resultSetID を使用して、 位置によりレコード情報を検索する対象としての結果セットを指定することができます。 この ID は前の open 文や get 文で割り当てたものです。 結果セットを指定しない場合は、EGL はコンテキストから現在の結果セットを判別します。 このトピックの『位置オプションの使用』を参照してください。
SQLDynamicArray
この変数は、SQL レコード変数によって構成される動的配列に名前を付けます。 EGL は結果セットから一致するすべての行を取得し、それらの値を配列の個々のレコード変数要素に挿入します。 配列の maxSize プロパティーを設定することにより、 プログラムが処理可能な量よりも多くのデータを一度に取り出さないようにできます。 配列がその最大サイズに達すると、EGL は結果の取得を停止します。 動的配列のプロパティー を参照してください。
positionOption とともに使用すると、SQLDynamicArray 変数宣言または open ステートメントに指定された、rowSetSize プロパティーに基づいて、その次の行セットが動的配列に返されます。これが get positionOption の初回の実行である場合には、配列要素が作成されます。これが get positionOption の 2 回目以降の実行である場合には、要素が配列内に配置されます。
sqlCallStatement
データベース管理システムでのストアード・プロシージャーの呼び出しです。 プロシージャーは、結果セットを必ず 1 つ返す必要があります。例については、『ストアード・プロシージャーの呼び出し』を参照してください。

位置オプションの使用

get 文に指定して位置オプションを使用する場合、 ユーザーは新規結果セットを作成しませんが、前の get 文または open 文で作成した結果セットからレコードを検索します。 既存の結果セットを操作するため、次の制限が適用されます。
  • #sql ディレクティブに SQL を組み込むことはできません。
  • singleRow オプションは使用できません。
  • forUpdate オプションは使用できません (これは、結果セットを作成した文に設定される場合とされない場合があります)。
  • 準備済みの文は使用できません。
get 文の位置オプションは、以下の条件が当てはまる場合に使用できます。
  • EGL の open 文を使用して結果セットを作成した。
  • open 文に指定して scroll オプションを使用した。

next 位置オプションは、他の状況においても使用することができます。

absolute (position)
結果セットの先頭から順方向にカウントする (正の値を指定する場合) か、結果セットの終わりから逆方向にカウントする (負の値を指定した場合) 数で指定する行を検索します。
current
現行カーソル位置の行を検索します。
first
結果セットの最初の行を検索します。
last
結果セットの最後の行を検索します。
next
現行カーソル位置に続く、最初の行を検索します。
previous
現行カーソル位置の前の、最後の行を検索します。
relative (position)
現行カーソル位置から順方向にカウントする (正の値を指定する場合) か、現行カーソル位置から逆方向にカウントする (負の値を指定した場合) 数で指定する行を検索します。 値がゼロの場合、現行カーソル位置のレコードを検索します。 これは、current オプションと同じです。

結果セットでのカーソル (または位置標識) の初期位置は、結果の最初の行の前です。 通常、プログラムは forEach 文を使用するか、get next を繰り返し使用して、結果内で反復的に処理を行います。

暗黙の SQL SELECT 文

SQL レコード変数を get 文に指定したが、#sql ディレクティブで組み込み SQL 文を指定しない場合は、 暗黙の SQL コードを作成します。暗黙の SQL SELECT には、次の特性があります。

  • SQL テーブルの各キー列の値が SQL レコード変数の対応するキー・フィールドの値と等しい限り、get 文が選択するテーブル行は、defaultSelectCondition レコード固有プロパティーによって決まります。 レコード・キーもデフォルトの選択条件も指定しなかった場合は、結果セットにすべてのテーブル行が含まれます。 複数のテーブル行が選択され、単一の SQL レコード変数 (レコード変数の配列ではなく) を get 文のターゲットとして指定した場合は、 最初に検索された行がレコード変数に入ります。
  • レコード定義におけるレコード・フィールドと SQL テーブル列の関連付けの結果として、特定のフィールドが、関連する SQL 結果セット列のコンテンツを受け取ります。
  • forUpdate オプションを指定した場合、SQL SELECT FOR UPDATE 文には読み取り専用のレコード・フィールドが含まれません。
  • 特定のレコード用の SQL SELECT 文は、以下の文のようになります。 ただし、FOR UPDATE OF 文節は、get 文に forUpdate オプションが含まれる場合にのみ表示されます。
      SELECT column01, 
             column02, 
             ... 
             columnNN
      FROM   tableName 
      WHERE  keyColumn01 = :keyField01
      FOR UPDATE OF
             column01, 
             column02, 
             ... 
             columnNN
    スタンドアロンの SQL SELECT またはカーソルに関連する FETCH 文の SQL INTO 文節は、 以下の文節のようになります。
      INTO   :recordField01,
             :recordField02, 
             ...
             :recordFieldNN

    INTO 文節を指定しておらず、SQL レコード変数に組み込み SQL SELECT 文が付いている場合、EGL は SQL INTO 文節を派生します。 派生した INTO 文節のフィールドは、SQL 文の SELECT 文節にリストされた列と関連付けられたフィールドです。 (フィールドと列との関連付けは、カスタム SQL レコード・パーツ内で行われます。SQLRecord ステレオタイプを参照してください。) 列がフィールドと関連付けられていない場合は、EGL INTO 文節が必要です。

SQL レコード変数の動的配列を get ステートメントの入出力オブジェクトとして指定するが、 組み込み SQL 文を指定しない場合、暗黙の SQL SELECT は、以下の相違点を除いて、単一 SQL レコード変数で説明したものと同様になります。
  • 照会のキー値コンポーネントは、より大か等しい条件に基づく関係の集合です。
      keyColumn01 >= :keyField01 &
      keyColumn02 >= :keyField02 &
      ...
      keyColumnNN >= :keyFieldNN
  • usingKeys 文節中のフィールド (または SQL レコード中のホスト変数) は、 動的配列の基礎である SQL レコード変数に存在してはなりません

次の例では、get 文がデータベース行を検索するときに SQL レコード変数 myCustomer を使用し、 以降の更新または削除を実行することはできません。
  try
    get myCustomer singleRow into customerName with
      #sql{
        SELECT customer_name
        FROM Cusomter
        WHERE customer_number = :myCustomer.customerNumber
      };
  onException(sqlEx SQLException)
    myErrorHandler(8);
  end
次の例は、同じ SQL レコード変数を使用して SQL 行を置換します。
  try
    get myCustomer forUpdate into customerName with
      #sql{
        SELECT customer_name
        FROM Cusomter
        WHERE customer_number = :myCustomer.customerNumber
      };

  onException(sqlEx SQLException)
    myErrorHandler(8);    // プログラムを終了する
  end

  myCustomer.customerName = newName;   // ユーザーが入力した名前変更
 
  try
    replace myCustomer;
  onException(sqlEx SQLException)
    myErrorHandler(12);
  end
次の例は、複数行に対する get ステートメントを示しています。
employees Employee[0]{rowsetsize=10};
Open resultset1 scroll with #sql{ 
    select eID, uName, PASSWORD, fName, lName, office, sex, EMail
    from EMPLOYEETEST
} for employees;


Get Next employees;  //this empties the employees array and 
                     // populates with up to the next 10 rows from the result set
または
eIDs INT[0]{};
uNames CHAR(20)[10]{};
Get Next employees into eIDs, uNames; 
または
DynamicEmployee DynamicEmployee;
Get Next employees into DynamicEmployee;
Record DynamicEmployee
   eIDs INT[10];
   uNames CHAR(20)[10];
    end

または
structuredEmployee StructuredEmployee;
Get Next employees into structuredEmployee.eIDs, structuredEmployee.uNames; //
Get Next employees into structuredEmployee;

Record StructuredEmployee
   1 eIDs INT[10];
   1 uNames CHAR(20)[10];
 end

エラー条件

以下の条件は、get ステートメントを使用してリレーショナル・データベースからデータを読み取るときにはエラーを起こします。
  • SELECT 以外の型の SQL 文を指定する。
  • SQL SELECT 文に直接 SQL INTO 文節を指定する。
  • SQL INTO 文節以外に、SQL SELECT 文の文節のうち、必要な一部 (全部ではない) を指定する。
  • 存在しないか、関連するホスト変数との互換性がない列に関連付けられている SQL SELECT 文を指定する (または受け入れる)。
以下のエラー条件は、forUpdate オプションを使用する場合に発生する可能性があります。
  • 複数のテーブルを更新する意図を示す SQL 文を指定する (または受け入れる) 場合。
  • すべてのレコード・フィールドが読み取り専用である SQL レコード変数を使用する場合。
以下の両方の条件が当てはまる場合にもエラーが発生します。
  • forUpdate オプションを指定して EGL の get 文をカスタマイズしたが、 特定の SQL テーブル列が更新に使用可能であることを示していない場合。
  • get 文に関連付けられた replace 文が列を変更しようとした。
この不一致は、以下のいずれかの方法で解決できます。
  • EGL get 文をカスタマイズする際に、SQL SELECT 文の FOR UPDATE OF 文節に列名を組み込む。
  • EGL の replace 文をカスタマイズする際に、SQL UPDATE 文の SET 文節内にある列への参照をすべて除去する。
  • get 文と replace 文の両方について、デフォルトを受け入れる。

互換性

各リレーショナル・データベース管理システム (RDBMS) は、独自のバージョンの SQL を持っています。 すべての実装環境ですべての SQL 文を使用できるとは限りません。 組み込み SQL をコーディングする前に、ご使用の RDBMS の資料を参照してください。

表 1. get および SQL の互換性に関する考慮事項
プラットフォーム 問題
iSeries® COBOL absolute オプションはサポートされていません。

フィードバック