SQL에 대한 get 고려사항

SQL의 컨텍스트에서 get 문은 결과 세트에서 레코드 데이터를 검색합니다.

get 문에서 두 가지 방법으로 결과 세트를 사용할 수 있습니다.
  • get 문을 통해 결과 세트 작성
  • 이전 EGL open 문으로 작성한 결과 세트에서 읽기(absolute 또는 next와 같은 위치 옵션을 get 문과 함께 지정하는 경우)

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 문과 함께 많은 위치 옵션(예: absolutenext)을 제공합니다. 이를 사용하여 결과 세트에서 현재 위치에 상대적인 특정 레코드를 검색할 수 있습니다. 이를 수행하려면 커서를 사용하여 현재 위치의 추적을 유지해야 합니다. 커서의 결과 세트에 액세스할 수 있으려면 위치 get을 사용하기 전에 EGL open 문을 사용하십시오. get...forUpdate 문을 사용할 수도 있지만 덜 일반적입니다.

get 문의 대상이 단일 SQL 레코드 변수인 경우, 이 명령문은 사용자가 제공하는 암시적 또는 임베디드 기준에 일치하는 첫 번째 레코드를 리턴합니다. SQL 레코드 변수의 동적 배열을 명령문 대상으로 지정할 수도 있습니다. 이 경우 get 문은 일치하는 각 행을 배열의 요소로 리턴합니다.

구문

get 문의 구문 다이어그램
SQLRecordVariable
SQL 레코드 변수의 이름입니다. 기본 동작은 keyItemsdefaultSelectCondition 레코드 파트 특성의 값에 따라 데이터베이스 행을 찾는 것입니다.
forUpdate
get 문을 사용하여 새 결과 세트를 작성하는 경우 나중에 데이터베이스 행을 대체하거나 삭제할 예정이면 이 키워드를 포함시켜서 결과 세트에 해당하는 행을 잠그십시오. 데이터베이스 관리자는 커미트가 발생할 때까지 다른 프로그램이 잠긴 행을 변경하도록 허용하지 않습니다. 커미트 처리에 대한 세부사항은 논리적 작업 단위의 내용을 참조하십시오.
resultSetID
get 문으로 새 결과 세트를 작성하는 경우 forUpdate 키워드와 함께 사용자가 선택한 ID를 지정하여 나중에 EGL replace, delete, execute 또는 위치 get 문이나 EGL close 문에서 동일한 결과 세트를 사용할 수 있습니다.
singleRow
이 옵션은 get 문의 키가 단일 행에만 적용되고 행을 업데이트하거나 삭제할 의도가 없는 경우에 사용할 수 있는 더 효율적인 SQL을 생성합니다. EGL은 이 경우 커서를 작성하지 않습니다. 키가 복수 행에 적용되는 경우 이 옵션을 지정하면 런타임 I/O 오류가 발생합니다.
#sql{ sqlSelectStatement }
sql 지시문에서 설명하는 것처럼 숙련된 SQL 프로그래머는 자신의 SQL SELECT 문을 임베드하여 EGL이 생성하는 SQL 코드를 대체할 수 있습니다. #sql과 왼쪽 중괄호 사이에 공백을 남기지 마십시오.
코드에 SQL 레코드를 사용하고 명시적 SQL을 포함하며 INTO 절이 없는 get 또는 open 문이 있는 경우를 고려하십시오. 예를 들어, 이러한 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 문을 코딩하는 경우, EGL 생성기가 INTO 절의 작성하도록 의존하는 대신 사용자가 INTO 절을 지정해야 할 수도 있습니다. 이 상황은 예를 들어 여기에 나타낸 것처럼 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

마지막 경우에서 사용자 자신의 INTO 절을 쓰고 column 특성을 설정하지 않을 것을 고려하십시오. 복합 column 특성에 액세스하는 EGL add 또는 replace 문을 코딩하는 경우, 생성된 SQL INSERT 및 UPDATE 문은 올바르지 않을 수 있기 때문입니다.

into ... target
이 절은 EGL이 작성하는 암시적 SQL 코드의 INTO 절에 해당합니다. INTO 절은 결과 세트에서 값을 수신하는 EGL 변수를 식별합니다. 개별 변수를 지정할 수도 있고 레코드 이름을 지정할 수도 있으며, 레코드 이름을 지정하는 경우 EGL은 레코드의 모든 필드를 사용합니다. 이 절은 다음과 같은 경우에 SQL을 처리할 때 필수입니다.
  • get 문에 SQL 레코드 변수를 지정하지 않았습니다.
  • SQL 레코드 변수와 임베디드 SQL SELECT 문을 둘 다 지정했지만 SQL SELECT 절에 대상 SQL 레코드 변수에 해당 필드가 없는 열이 하나 이상 있습니다.

into 절은 SQL이 아니라 EGL로 쓰십시오. SQL문에서 호스트 변수에 대해 사용할 수 있는 것처럼 이 절에서 변수 이름을 콜론으로 시작하지 마십시오. 자세한 정보는 호스트 변수의 내용을 참조하십시오.

get positionOptionSQLDynamicArray와 함께 사용되는 경우, 대상은 레코드 변수 내의 동적 배열 필드 또는 필드에 지정된 발생이 있는 구조화된 레코드가 될 수 있습니다. 구조화된 레코드를 사용하면 COBOL 생성 시 더 나은 성능을 제공할 수 있습니다. 연관된 rowSetSize가 구조화된 레코드에서 발생한 필드에 지정된 요소보다 큰 경우, get positionOption 문에서 발생한 배열의 최대 색인을 초과하는 요소에 값을 채우려고 시도하면 IndexOutOfBoundException이 처리됩니다.
preparedStatementID
이 ID는 런타임 시 SQL SELECT 문을 준비하는 EGL prepare 문을 가리킵니다. get 문은 SQL SELECT 문을 동적으로 실행합니다. 자세한 정보는 SQL에 대한 prepare 고려사항의 내용을 참조하십시오.
using ... field
이 절은 EGL이 작성하는 암시적 SQL 코드의 USING 절에 해당합니다. USING 절은 런타임 시 준비된 SQL SELECT 문이 사용할 수 있는 EGL 변수를 식별합니다. using 절은 SQL이 아니라 EGL로 쓰십시오. SQL문에서 호스트 변수에 대해 사용하는 것처럼 이 절에서 변수 이름을 콜론으로 시작하지 마십시오. 자세한 정보는 호스트 변수의 내용을 참조하십시오.
usingKeys ... field
여기에서 SQL 레코드의 필드 이름을 지정하여 레코드 정의에서 지정한 키 필드를 대체할 수 있습니다. 예를 들어, customerNumberCustomerRecord에서 정의한 키 필드이지만 customerName으로 레코드를 검색하려면 다음 코드를 사용할 수 있습니다.
get myCustomer usingKeys myCustomer.customerName;
또는 전혀 다른 레코드의 필드를 기반으로 검색할 수 있습니다.
get myCustomer usingKeys myOrders.customerName;

EGL이 get 문으로부터 생성하는 암시적 SQL문의 WHERE 절에 대해 usingKeys 플러그로 지정하는 필드입니다. 임베드된 SQL 코드로 이 명령문을 수행하는 경우, 임베드된 코드가 암시적 코드를 대체합니다.

동적 배열의 경우 usingKeys 절에 있는 필드(또는 SQL 레코드의 호스트 변수)는 동적 배열의 기초인 SQL 레코드 배열에 있지 않아야 합니다.

forUpdate 키워드를 지정하면 키 항목과 연관된 열이 FOR UPDATE OF 절에 나열된 열에서 제외됩니다.

positionOption
새로 작성한 결과 세트가 아니라 기존 결과 세트에서 데이터를 검색하려면 이 옵션을 사용하십시오. 사용 가능한 옵션 및 세부사항에 대해서는 이 주제의 "위치 옵션 사용"을 참조하십시오.
from resultSetID
위치 옵션을 사용하는 경우 resultSetID를 사용하여 위치로 레코드 정보를 검색할 결과 세트를 지정할 수 있습니다. 이전 open 또는 get 문에서 이 ID를 지정했습니다. 결과 세트를 지정하지 않으면 EGL은 컨텍스트에서 현재 결과 세트를 판별합니다. 이 주제의 "위치 옵션 사용"을 참조하십시오.
SQLDynamicArray
이 변수는 SQL 레코드 변수로 구성된 동적 배열의 이름을 지정합니다. EGL은 결과 세트에서 일치하는 모든 행을 검색하여 해당 값을 배열의 개별 레코드 변수 요소에 삽입합니다. 프로그램이 처리할 수 있는 것보다 많은 데이터를 한 번에 검색하지 않도록 배열의 maxSize 특성을 설정하십시오. EGL은 배열이 최대 크기에 도달한 후 결과 검색을 중지합니다. 동적 배열 특성을 참조하십시오.
positionOption과 함께 사용되는 경우 다음 rowset은 SQLDynamicArray 변수 선언 또는 open 문의 rowSetSize 특성을 기반으로 동적 배열로 리턴됩니다. get positionOption이 처음 수행된 경우 배열 요소가 작성됩니다. get positionOption이 두 번째 이후로 수행된 경우에는 배열의 요소가 대체됩니다.
sqlCallStatement
데이터베이스 관리 시스템에서 스토어드 프로시저에 대한 호출입니다. 프로시저는 단 하나의 결과 세트를 리턴해야 합니다. 예를 들어, "스토어드 프로시저 호출"을 참조하십시오.

위치 옵션 사용

get 문과 함께 위치 옵션을 사용하는 경우에는 새 결과 세트를 작성하지 않지만 이전에 get 또는 open 문으로 작성한 결과 세트에서 레코드를 검색합니다. 기존 결과 세트에 대해 작업하므로 다음과 같은 제한사항이 적용됩니다.
  • #sql 지시문에 SQL을 임베드할 수 없습니다.
  • singleRow 옵션을 사용할 수 없습니다.
  • forUpdate 옵션을 사용할 수 없습니다. (이 옵션은 해당 결과 세트를 작성한 명령문에서 설정되거나 설정되지 않았습니다.)
  • 준비된 명령문을 사용할 수 없습니다.
get 문에 대한 위치 옵션은 다음 조건이 참인 경우에 사용할 수 있습니다.
  • EGL open 문을 사용하여 결과 세트를 작성했습니다.
  • scroll 옵션을 open 문과 함께 사용했습니다.

next 위치 옵션은 다른 환경에서도 사용할 수 있습니다.

absolute (position)
결과 세트의 시작에서 앞쪽으로 센 수(양수 값) 또는 결과 세트의 끝에서 뒤쪽으로 센 수(음수 값)로 지정한 행을 검색합니다.
current
현재 커서 위치의 행을 검색합니다.
first
결과 세트의 첫 번째 행을 검색합니다.
last
결과 세트의 마지막 행을 검색합니다.
next
현재 커서 위치 다음의 첫 번째 행을 검색합니다.
previous
현재 커서 위치 이전의 마지막 행을 검색합니다.
relative (position)
현재 커서 위치에서 앞쪽으로 센 수(양수 값) 또는 현재 커서 위치에서 뒤쪽으로 센 수(음수 값)로 지정한 행을 검색합니다. 값 0은 현재 커서 위치의 레코드를 검색하며, current 옵션과 같습니다.

결과 세트에서 커서(또는 위치 표시기)의 초기 위치는 결과의 첫 번째 행 이전에 설정됩니다. 프로그램은 일반적으로 forEach 문을 사용하거나 get next를 반복적으로 사용하여 결과에 대해 반복합니다.

암시적 SQL SELECT 문

get 문에 SQL 레코드 변수를 지정하면서 #sql 지시문으로 임베디드 SQL문을 지정하지 않으면 암시적 SQL 코드가 작성됩니다. 암시적 SQL SELECT 문에는 다음과 같은 특성이 있습니다.

  • defaultSelectCondition 레코드 특정 특성은 각 SQL 테이블 키 열의 값이 SQL 레코드 변수의 해당 키 필드 값과 같은 경우 get 문이 선택하는 테이블 행을 판별합니다. 레코드 키 또는 기본 선택 조건을 지정하지 않으면 결과 세트에 모든 테이블 행이 포함됩니다. 복수 테이블 행이 선택된 경우 레코드 변수의 배열이 아니라 단일 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 문의 I/O 오브젝트로 지정하면서 임베디드 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);  // exits the program
  end
  myCustomer.customerName = newName;   // user entered name change
 
  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
or
eIDs INT[0]{};
uNames CHAR(20)[10]{};
Get Next employees into eIDs, uNames; 
or
DynamicEmployee DynamicEmployee;
Get Next employees into DynamicEmployee;
Record DynamicEmployee
   eIDs INT[10];
   uNames CHAR(20)[10];
    end
or
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 절에서 열 참조를 모두 제거하십시오.
  • getreplace 문 모두에 대해 기본값을 승인하십시오.

호환성

각 관계형 데이터베이스 관리 시스템(RDBMS)에는 SQL의 자체 버전이 있습니다. 모든 구현에서 모든 SQL문을 사용할 수 있는 것은 아닙니다. 임베디드 SQL을 코딩하기 전에 RDBMS의 문서를 참조하십시오.

표 1. get 및 SQL에 대한 호환성 고려사항
플랫폼 문제
iSeries COBOL absolute 옵션은 지원되지 않습니다.