Objectives
After completing this lesson, you will be able to:
- 복잡한 내부 테이블에 데이터를 입력합니다.
- 복합 내부 테이블(Internal Table)의 내용에 액세스합니다.
- ABAP SQL에서 복잡한 내부 테이블(Internal Table)을 사용한다.
복합 내부 테이블 입력
이미 학습한 것처럼 내부 테이블에 신규 행을 추가하는 가장 간단한 방법은 유형이 내부 테이블의 행 유형에 해당하는 데이터 오브젝트가 있는 APPEND 문입니다. 이 데이터 오브젝트를 작업 영역이라고도 합니다.
단순 내부 테이블의 경우 APPEND에 사용되는 작업 영역은 스칼라 변수, 상수 또는 리터럴일 수 있습니다. 복잡한 내부 테이블의 경우 작업 영역을 구조화해야 합니다.
이 예에서는 내부 테이블(Internal Table) 연결을 입력하는 데 구조화 변수 연결이 사용됩니다.
원칙적으로 작업 영역 연결을 선언하는 방법에는 두 가지가 있습니다.
- st_connection 행 유형을 직접 참조하십시오.
- LIKE LINE OF <internal_table>을 사용하여 행 유형을 간접적으로 참조합니다.
LIKE LINE OF로 작업 영역을 정의하면 두 가지 이점이 있습니다.
- 내부 테이블(Internal Table)의 작업 영역으로서 구조화된 변수의 목적이 표시됩니다.
- 내부 테이블(Internal Table)의 정의가 변경되더라도 작업 영역이 내부 테이블(Internal Table)에 적합하도록 보장
APPEND 문 앞에 작업 영역을 입력하지 않으면 내부 테이블의 신규 행에 유형별 초기 값이 입력됩니다.
힌트
특수 변형 APPEND INITIAL LINE TO <internal_table> 과 동일한 결과가 표시됩니다. 이 변형에는 작업 영역도 필요하지 않습니다.
구조화된 작업 영역을 채우려면 개별 컴포넌트를 채우거나 예제에서 볼 수 있듯이 VALUE #( ) 표현식을 사용합니다.
이 예에서 볼 수 있듯이 APPEND 문에서 직접 VALUE #( ) 표현식을 사용할 수도 있습니다. 이 경우 작업 영역이 필요하지 않습니다.
노트
이는 프로그램의 전체 메모리 사용에 긍정적인 영향을 미칠 수 있습니다.
내부 테이블에 직접 지정할 수 있는 VALUE #( ) 식의 변형이 있습니다. 이 변형 VALUE #( )에서 추가 괄호 쌍은 테이블 행을 서로 구분하는 데 사용됩니다.
코드 예는 각각 carrier_id와 carrier_name 에 대해 다른 값으로 세 개의 행으로 내부 테이블 캐리어를 채웁니다. 따라서 currency_code 열은 언급되지 않고 유형별 초기 값으로 채워집니다.
노트
위의 지정을 사용하면 테이블에 새로운 행이 입력되기 전에 기존의 모든 테이블 행이 제거됩니다.
두 개의 내부 테이블에서 이름이 동일한 필드 간에 데이터를 복사하려면 CORRESPONDING 연산자를 사용합니다. 이는 구조의 CORRESPONDING과 유사하게 작동합니다. 소스 내부 테이블의 각 행에 대해 대상 내부 테이블에 신규 행이 생성되고 이름이 동일한 필드 간에 데이터가 복사됩니다. 동일한 이름의 필드가 대상에 없는 소스 필드는 복사되지 않습니다. 동일한 이름의 필드가 없는 대상 필드는 유형별 초기 값으로 채워집니다.
이 예에서는 소스 내부 테이블(source internal table) 캐리어에 세 개의 행이 있습니다. 따라서 값 지정 후에는 대상 내부 테이블(Internal Table) 연결에도 세 개의 행이 포함됩니다.
carrier_id 필드와 carrier_name 필드가 두 내부 테이블 모두에 존재합니다. 소스에서 대상으로 복사됩니다. currency_code 필드는 소스에만 있습니다. 복사되지는 않습니다. connection_id, airport_from_id 및 airport_to_id 필드는 대상에만 존재합니다. 초기 값으로 채워집니다.
노트
지정 전에 대상 내부 테이블에 데이터가 포함된 경우 해당 데이터가 삭제됩니다.
복합 내부 테이블(Internal Table)을 디버그하는 방법
사용해 보기: 복합 내부 테이블 채우기
- 이 과정의 첫 번째 연습문제에서는 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
- 다음 코드 스니핏을 if_oo_adt_classrun~main( ) 메소드의 구현 부분에 복사합니다.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE STANDARD TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
carrier_name TYPE /dmo/carrier_name,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
TYPES tt_carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carriers TYPE tt_carriers.
* Example 1: APPEND with structured data object (work area)
**********************************************************************
* DATA connection TYPE st_connection.
" Declare the work area with LIKE LINE OF
DATA connection LIKE LINE OF connections.
* connection-carrier_id = 'NN'.
* connection-connection_id = '1234'.
* connection-airport_from_id = 'ABC'.
* connection-airport_to_id = 'XYZ'.
* connection-carrier_name = 'My Airline'.
" Use VALUE #( ) instead assignment to individual components
connection = VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline' ).
APPEND connection TO connections.
out->write( `--------------------------------` ).
out->write( `Example 1: APPEND with Work Area` ).
out->write( connections ).
* Example 2: APPEND with VALUE #( ) expression
**********************************************************************
APPEND VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline'
)
TO connections.
out->write( `----------------------------` ).
out->write( `Example 2: Append with VALUE` ).
out->write( connections ).
* Example 3: Filling an Internal Table with Several Rows
**********************************************************************
carriers = VALUE #( ( carrier_id = 'AA' carrier_name = 'American Airlines' )
( carrier_id = 'JL' carrier_name = 'Japan Airlines' )
( carrier_id = 'SQ' carrier_name = 'Singapore Airlines')
).
out->write( `-----------------------------------------` ).
out->write( `Example 3: Fill Internal Table with VALUE` ).
out->write( carriers ).
* Example 4: Filling one Internal Table from Another
**********************************************************************
connections = CORRESPONDING #( carriers ).
out->write( `--------------------------------------------` ).
out->write( `Example 4: CORRESPONDING for Internal Tables` ).
out->write( data = carriers
name = `Source Table CARRIERS:`).
out->write( data = connections
name = `Target Table CONNECTIONS:`).
- 키보드에서 CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱을 실행합니다.
- 콘솔 출력을 분석합니다. 프로그램을 디버그하고 소스 코드를 사용하여 개념을 숙지합니다.
복합 내부 테이블(Internal Table)에 액세스
이 과정의 앞에서는 내부 테이블(Internal Table) 표현식을 사용하여 단순 내부 테이블에서 단일 행을 검색하는 방법을 학습했습니다. 그 뒤로 인덱스 액세스를 사용했습니다. 즉, 내부 테이블에서의 위치를 통해 행을 식별했습니다. 이 인덱스 액세스는 복잡한 내부 테이블에서 동일한 방식으로 작동합니다. 하지만 복잡한 내부 테이블의 경우 키 액세스 권한을 갖는 내부 테이블(Internal Table) 표현식이 중요해지고 여기에서 해당 내용을 통해 행을 식별할 수 있습니다.
노트
이를 키 액세스라고 하지만 내부 테이블의 키 필드뿐만 아니라 모든 필드를 선택에 사용할 수 있습니다. 둘 이상의 행이 요구사항을 충족하면 STANDARD 테이블은 첫 번째 행, 즉 인덱스가 가장 낮은 행을 반환합니다.
이 예에서는 내부 테이블(Internal Table) 연결에서 단일 행을 읽습니다. 이 내부 테이블의 키는 필드, carrier_id 및 connection_id로 구성되지만 키 액세스는 airport_from_id와 airport_to_id를 사용하여 행을 식별합니다. Internal Table에는 공항 SFO에서 SIN으로의 두 개의 연결이 포함되어 있으므로 첫 번째 연결이 반환됩니다.
ABAP 런타임에서 요구사항을 충족하는 행이 없으면 CX_SY_ITAB_LINE_NOT_FOUND 예외가 발생합니다. 런타임 오류를 방지하기 위해 TRY … CATCH … ENDTRY 구조에서 이 예외 처리
필드를 지정하여 내부 테이블의 여러 라인을 처리하려면 LOOP AT <internal table> INTO <target> WHERE <condition>을 사용합니다. WHERE 조건에는 AND와 OR을 사용하여 조인된 구성 표현식이 개수 제한 없이 포함될 수 있습니다. 표현식에는 같음 연산자(=)뿐만 아니라 >, >=, <, <=, <> 및 BETWEEN 연산자도 사용할 수 있습니다.
테이블 행의 내용을 작업 영역에 읽은 후 작업 영역의 변경사항을 내부 테이블에 다시 작성하려고 하는 경우가 있습니다. 이를 위한 한 가지 방법은 MODIFY TABLE 문입니다.
시스템에서 작업 영역의 키 필드 내용을 사용하여 수정해야 하는 테이블 행을 식별하기 때문에 이 명령문은 키 액세스에 해당합니다. 그런 다음 이 테이블 행을 작업 영역의 내용으로 덮어씁니다.
이 예에서는 작업 영역 운송업체의 키 필드 carrier_id 에 'JL' 값이 포함되어 있습니다. 이 값을 기준으로 업데이트할 두 번째 행이 식별됩니다. 그러면 이 행이 작업 영역의 값으로 업데이트됩니다.
노트
MODIFY TABLE을 사용해서만 키 필드가 아닌 필드를 변경할 수 있습니다. 문은 키 필드 변경을 지원하지 않습니다.
MODIFY 문(키워드 TABLE 없음) 은(는) 키 필드와 키 필드가 아닌 필드를 구분하지 않습니다. 전체 테이블 행을 작업 영역의 신규 값으로 덮어씁니다. 업데이트할 행이 내부 테이블에서 해당 위치로 식별되므로 이 명령문은 인덱스 액세스로 간주됩니다. 일반적으로 인덱스는 추가 요소 INDEX 와 정수 인수(리터럴, 상수, 변수, 표현식)를 사용하여 명시적으로 지정됩니다.
노트
INDEX 추가 요소가 없는 특수 변형도 있습니다. 이 변형에 대해서는 다음에 살펴보겠습니다.
예시에서 MODIFY 문은 INDEX 추가 요소를 사용하여 첫 번째 테이블 행을 처리합니다. 이 행에서 모든 필드를 작업 영역의 값으로 덮어씁니다(키 필드 carrier_id 포함).
내부 테이블(Internal Table)의 여러 행 또는 모든 행의 내용을 수정해야 하는 경우가 종종 있습니다. 이렇게 하려면 테이블에 루프를 구현하여 각 행을 작업 영역에 연속적으로 변경해야 합니다. 루프 내에서 먼저 작업 영역의 내용을 변경한 다음 MODIFY 문을 사용하여 변경사항을 내부 테이블(Internal Table)에 다시 기록합니다.
노트
변경사항을 테이블에 다시 쓰지 않으면 작업 영역에 다음 행의 데이터가 입력되면 변경사항이 손실됩니다.
이 예에서 루프는 필드 currency_code가 아직 채워지지 않은 내부 테이블(Internal Table) 캐리어의 모든 행을 읽습니다. 마지막 두 행에 대한 경우입니다. 이러한 각 행에 대해 currency_code 필드의 초기 값이 신규 값 'USD'로 대체됩니다. 마지막으로 MODIFY 문을 사용하여 현재 행을 업데이트된 값으로 덮어씁니다.
코드 예제는 인덱스를 명시적으로 지정하는 대신 INDEX 추가 요소가 누락된 MODIFY 문의 짧은 형식을 사용합니다. 이 짧은 서식은 LOOP … ENDLOOP 사이에서만 허용됩니다. 현재 작업 중인 행만 암시적으로 업데이트할 수 있습니다.
LOOP…ENDLOOP 외부에서 INDEX 없이 MODIFY 를 사용하는 경우 캐치 불가능한 런타임 오류를 수정하고 트리거할 행을 시스템에서 알 수 없습니다. 이러한 런타임 오류를 방지하려면 구문 점검에서 관련 경고를 무시하지 마십시오!
사용해 보기: 복합 내부 테이블(Internal Table)에 액세스
- 이 과정의 첫 번째 연습문제와 마찬가지로 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
- 다음 코드 스니핏을 if_oo_adt_classrun~main( ) 메소드의 구현 부분에 복사합니다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
TYPES: BEGIN OF st_connection,
carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.
TYPES tt_connections TYPE SORTED TABLE OF st_connection
WITH NON-UNIQUE KEY carrier_id
connection_id.
DATA connections TYPE tt_connections.
DATA connection LIKE LINE OF connections.
TYPES: BEGIN OF st_carrier,
carrier_id TYPE /dmo/carrier_id,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.
DATA carriers TYPE STANDARD TABLE OF st_carrier
WITH NON-UNIQUE KEY carrier_id.
DATA carrier LIKE LINE OF carriers.
* Preparation: Fill internal tables with data
**********************************************************************
connections = VALUE #( ( carrier_id = 'JL'
connection_id = '0408'
airport_from_id = 'FRA'
airport_to_id = 'NRT'
carrier_name = 'Japan Airlines'
)
( carrier_id = 'AA'
connection_id = '0017'
airport_from_id = 'MIA'
airport_to_id = 'HAV'
carrier_name = 'American Airlines'
)
( carrier_id = 'SQ'
connection_id = '0001'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'Singapore Airlines'
)
( carrier_id = 'UA'
connection_id = '0078'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'United Airlines'
)
).
carriers = VALUE #( ( carrier_id = 'SQ'
currency_code = ' '
)
( carrier_id = 'JL'
currency_code = ' '
)
( carrier_id = 'AA'
currency_code = ' '
)
( carrier_id = 'UA'
currency_code = ' '
)
).
* Example 1: Table Expression with Key Access
**********************************************************************
out->write( `--------------------------------------------` ).
out->write( `Example 1: Table Expressions with Key Access` ).
out->write( data = connections
name = `Internal Table CONNECTIONS: ` ).
" with key fields
connection = connections[ carrier_id = 'SQ'
connection_id = '0001' ].
out->write( data = connection
name = `CARRIER_ID = 'SQ' AND CONNECTION_ID = '001':` ).
" with non-key fields
connection = connections[ airport_from_id = 'SFO'
airport_to_id = 'SIN' ].
out->write( data = connection
name = `AIRPORT_FROM_ID = 'SFO' AND AIRPORT_TO_ID = 'SIN':` ).
* Example 2: LOOP with key access
**********************************************************************
out->write( `-------------------------------` ).
out->write( `Example 2: LOOP with Key Access` ).
LOOP AT connections INTO connection
WHERE airport_from_id <> 'MIA'.
"do something with the content of connection
out->write( data = connection
name = |This is row number { sy-tabix }: | ).
ENDLOOP.
* Example 3: MODIFY TABLE (key access)
**********************************************************************
out->write( `-----------------------------------` ).
out->write( `Example 3: MODIFY TABLE (key access` ).
out->write( data = carriers
name = `Table CARRRIERS before MODIFY TABLE:`).
carrier = carriers[ carrier_id = 'JL' ].
carrier-currency_code = 'JPY'.
MODIFY TABLE carriers FROM carrier.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY TABLE:`).
* Example 4: MODIFY (index access)
**********************************************************************
out->write( `--------------------------------` ).
out->write( `Example 4: MODIFY (index access)` ).
carrier-carrier_id = 'LH'.
carrier-currency_code = 'EUR'.
MODIFY carriers FROM carrier INDEX 1.
out->write( data = carriers
name = `Table CARRRIERS after MODIFY:`).
* Example 5: MODIFY in a LOOP
**********************************************************************
out->write( `----------------------------` ).
out->write( `Example 5: MODIFY in a LOOP` ).
LOOP AT carriers INTO carrier
WHERE currency_code IS INITIAL.
carrier-currency_code = 'USD'.
MODIFY carriers FROM carrier.
ENDLOOP.
out->write( data = carriers
name = `Table CARRRIERS after the LOOP:`).
- 키보드에서 CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱을 실행합니다.
- 콘솔 출력을 분석합니다. 프로그램을 디버그하고 소스 코드를 사용하여 개념을 숙지합니다.
ABAP SQL의 복합 내부 테이블(Internal Table)
ABAP SQL 문 SELECT는 데이터베이스 테이블 또는 CDS 뷰에서 데이터를 읽습니다. SINGLE 옵션을 사용하면 WHERE 절의 조건을 충족하는 데이터가 더 있더라도 데이터베이스에서 정확히 하나의 레코드를 읽습니다.
앞에서 학습한 것처럼 이 단일 레코드 결과를 받는 한 가지 방법은 키워드 INTO 뒤의 구조화 변수입니다.
SINGLE 없이 SELECT를 사용하는 경우 WHERE 절의 조건과 일치하는 모든 레코드에 관심이 있음을 나타냅니다. 그런 다음 실제로 여러 개의 레코드를 수신하고 저장할 수 있는지 확인해야 합니다. 이 작업을 수행하는 확실한 방법은 복합 내부 테이블을 SELECT 문의 대상으로 사용하는 것입니다. 이는 가능하지만 키워드 INTO 와 내부 테이블 이름 사이에 TABLE 을 추가해야 합니다.
이 예제에서는 런던과 관련된 3개의 공항을 모두 읽어보고 싶을 뿐 아니라 하나의 공항도 읽고자 합니다. 따라서 SELECT 뒤에 키워드 SINGLE 을, INTO 뒤에 키워드 TABLE 을 추가하고, SELECT 문의 대상으로 Internal Table airports_full 을 사용합니다.
이 예에서는 FIELDS 다음에 내부 테이블 airports_full 의 열과 일치하는 명시적 필드 리스트를 사용합니다. 필드 리스트에서 FIELDS *, INTO CORRESPONDING FIELDS OF TABLE, 별칭 이름도 사용할 수 있습니다.
이 예에서는 명시적 필드 리스트 대신 FIELDS * 를 사용하고 INTO TABLE 대신 INTO CORRESPONDING FIELDS OF TABLE 을 사용합니다.
내부 테이블 공항의 행 유형에는 AirportID 와 Name 이라는 두 개의 구성요소만 포함되어 있으므로, 데이터베이스에서 이름이 같은 필드만 읽습니다.
INTO TABLE을 추가한 후 SELECT 문에서 DATA( )를 사용하는 경우 내부 테이블을 인라인으로 선언합니다. 이 내부 테이블의 행 유형은 FIELDS 절에서 파생됩니다. 테이블 필드 및 뷰 요소의 경우 별칭 이름은 선택사항입니다. FIELDS 절의 표현식의 경우 INTO 절에 인라인 선언이 포함된 경우 별칭 이름이 필수입니다.
노트
내부 테이블(Internal Table)의 인라인 선언은 INTO TABLE 이후에만 지원됩니다. INTO CORRESPONDING FIELDS OF TABLE 뒤에는 인라인 선언을 사용할 수 없습니다.
인라인 선언 내부 테이블은 항상 키가 없는 표준 테이블입니다. 인라인 선언을 사용하여 정렬 테이블 또는 해시 테이블을 선언할 수 없습니다. 내부 테이블에 많은 행을 입력하고 키 액세스를 많이 사용하면 성능 문제가 발생할 수 있습니다.
데이터베이스에서 여러 개의 레코드를 읽는 경우 몇 가지 특수 SQL 기법이 특히 유용합니다. 이러한 기법 중 하나는 여러 SELECT 문의 결과를 결합하는 UNION 지시어입니다.
다음 두 개의 SELECT 결과 조합이 그림에 나와 있습니다.
첫 번째 SELECT 결과는 CurrencyCode = 'GBP' 을 사용하여 모든 운송업체의 ID와 NAME을 읽습니다. 두 번째 SELECT는 City = 'London' 을 사용하여 모든 공항의 ID와 NAME을 읽습니다. 첫 번째 SELECT는 하나의 레코드를 리턴하고 두 번째 SELECT는 세 개의 레코드를 리턴합니다. 이러한 결과를 별도로 검색하는 대신 4개의 레코드와 함께 하나의 결과로 결합됩니다. 이는 데이터베이스 내에서 발생한다는 점을 지적하는 것이 중요합니다.
이 기법을 사용하기 위해서는 두 결과가 서로 호환되어야 합니다. 즉, 필드 수와 필드 이름이 동일해야 합니다. 필수는 아니지만 필드 유형도 동일한 것이 좋습니다.
이 예제의 ABAP SQL 구문은 두 개의 SELECT 문으로 구성됩니다. SELECT 문마다 고유한 FROM 절, FIELDS 절, WHERE 절이 있지만 맨 끝에는 INTO 절이 하나만 있습니다. 두 개의 SELECT 문은 UNION ALL 키워드로 연결됩니다.
노트
UNION ALL 대신 UNION을 사용하면 데이터베이스에서 결과를 반환하기 전에 중복 항목을 찾아 제거할 수 있습니다. 불필요한 데이터베이스 추가 로드를 피하기 위해 UNION ALL을 사용합니다.
두 필드 리스트는 세 개의 요소로 구성되며, 첫 번째 요소와 두 번째 요소는 두 FIELDS 절에서 별칭 이름이 동일합니다. 두 CDS 뷰에서 필드 이름이 동일하기 때문에 세 번째 필드에는 별칭이 필요하지 않습니다.
노트
FIELDS의 첫 번째 요소는 결합된 결과에서 항공사와 공항을 구분할 수 있는 리터럴 텍스트입니다.
사용해 보기: ABAP SQL의 내부 테이블
- 이 과정의 첫 번째 연습에서처럼 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
- 다음 코드 스니핏을 if_oo_adt_classrun~main( ) 메소드의 구현 부분에 복사합니다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
TYPES: BEGIN OF st_airport,
airportid TYPE /dmo/airport_id,
name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE KEY airportid.
DATA airports TYPE tt_airports.
* Example 1: Structured Variables in SELECT SINGLE ... INTO ...
**********************************************************************
DATA airport_full TYPE /DMO/I_Airport.
SELECT SINGLE
FROM /DMO/I_Airport
FIELDS AirportID, Name, City, CountryCode
WHERE City = 'Zurich'
INTO @airport_full.
out->write( `-------------------------------------` ).
out->write( `Example 1: SELECT SINGLE ... INTO ...` ).
out->write( data = airport_full
name = `One of the airports in Zurich (Structure):` ).
* Example 2: Internal Tables in SELECT ... INTO TABLE ...
**********************************************************************
DATA airports_full TYPE STANDARD TABLE OF /DMO/I_Airport
WITH NON-UNIQUE KEY AirportID.
SELECT
FROM /DMO/I_Airport
FIELDS airportid, Name, City, CountryCode
WHERE City = 'London'
INTO TABLE @airports_full.
out->write( `------------------------------------` ).
out->write( `Example 2: SELECT ... INTO TABLE ...` ).
out->write( data = airports_full
name = `All airports in London (Internal Table):` ).
* Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE
**********************************************************************
SELECT
FROM /DMO/I_Airport
FIELDS *
WHERE City = 'London'
INTO CORRESPONDING FIELDS OF TABLE @airports.
out->write( `----------------------------------------------------------` ).
out->write( `Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE` ).
out->write( data = airports
name = `Internal Table AIRPORTS:` ).
* Example 4: Inline Declaration
**********************************************************************
SELECT
FROM /DMO/I_airport
FIELDS AirportID, Name AS AirportName
WHERE City = 'London'
INTO TABLE @DATA(airports_inline).
out->write( `----------------------------------------------------------` ).
out->write( `Example 4: Inline Declaration after INTO TABLE` ).
out->write( data = airports_inline
name = `Internal Table AIRPORTS_INLINE:` ).
** Example 4: ORDER BY and DISTINCT
***********************************************************************
*
* SELECT
* FROM /DMO/I_Airport
* FIELDS DISTINCT CountryCode
* ORDER BY CountryCode
* INTO TABLE @DATA(countryCodes).
*
* out->write( countryCodes ).
* Example 5: UNION (ALL)
**********************************************************************
SELECT FROM /DMO/I_Carrier
FIELDS 'Airline' AS type, AirlineID AS Id, Name
WHERE CurrencyCode = 'GBP'
UNION ALL
SELECT FROM /DMO/I_Airport
FIELDS 'Airport' AS type, AirportID AS Id, Name
WHERE City = 'London'
* ORDER BY type, Id
INTO TABLE @DATA(names).
out->write( `----------------------------------------------` ).
out->write( `Example 5: UNION ALL of Airlines and Airports ` ).
out->write( data = names
name = `ID and Name of Airlines and Airports:` ).
- 키보드에서 CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱을 실행합니다.
- 콘솔 출력을 분석합니다. 프로그램을 디버그하고 소스 코드를 사용하여 개념을 숙지합니다.
복합 내부 테이블 사용
이번 연습문제에서는 테이블형 특성을 선언하고 SELECT 문을 사용하여 입력하고 컨텐트에 액세스합니다.
태스크 1: 템플릿 복사
템플릿 클래스를 복사합니다. 또는 이전 연습문제의 솔루션을 복사합니다.
단계
클래스 /LRN/CL_S4D400_STS_STRUCTURE 를 사용자의 패키지에 속한 클래스에 복사합니다(제안 이름: ZCL_##_ITAB, ##은 그룹 번호).
전역 클래스 /LRN/CL_S4D400_STS_STRUCTURE 의 소스 코드를 엽니다.
프로젝트 탐색기 뷰를 편집기와 연결합니다.
프로젝트 탐색기 뷰에서 클래스 /LRN/CL_S4D400_STS_STRUCTURE 를 마우스 오른쪽 버튼으로 클릭하여 단축 메뉴를 엽니다.
단축 메뉴에서 Duplicate .... 를 선택합니다.
패키지 필드에 패키지 이름을 입력합니다. 이름 필드에 이름 ZCL_##_ITAB 를 입력합니다. 여기서 ##은 그룹 번호입니다.
내역을 조정하고 다음 을 선택합니다.
전송 요청을 확인하고 Finish를 선택합니다.
태스크 2: 내부 테이블 선언
로컬 클래스에서 테이블형 정적 특성 공항을 선언하여 사용 가능한 모든 공항에 대한 세부 정보를 버퍼링합니다. 먼저 로컬 클래스 내에서 전용 구조 유형 st_airport 와 테이블 유형 tt_airportals 를 정의합니다.
단계
로컬 클래스 lcl_connection 으로 전환합니다.
전역 클래스에서 로컬 유형 을 선택합니다.
다음 컴포넌트를 사용하여 전용 구조 유형 st_airport 를 정의합니다.
구조 유형 st_airport의 컴포넌트:
| 컴포넌트 이름 | 데이터 유형 |
|---|
| AirportID | /dmo/airport_id |
| 성명 | /dmo/airport_name |
코드를 다음과 같이 조정합니다.
1234567891011121314
TYPES:
BEGIN OF st_details,
DepartureAirport TYPE /dmo/airport_from_id,
DestinationAirport TYPE /dmo/airport_to_id,
AirlineName TYPE /dmo/carrier_name,
END OF st_details.
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
다음 속성을 사용하여 전용 테이블 유형 tt_airportals 를 정의합니다.
테이블 유형 tt_airports의 속성:
| Property | 값 |
|---|
| 라인 유형 | st_airport |
| 테이블 종류 | 표준 테이블 |
| 키 정의 | 비고유 기본 키 |
코드를 다음과 같이 조정합니다.
12345678910
TYPES:
BEGIN OF st_airport,
AirportId TYPE /dmo/airport_id,
Name TYPE /dmo/airport_name,
END OF st_airport.
TYPES tt_airports TYPE STANDARD TABLE OF st_airport
WITH NON-UNIQUE DEFAULT KEY.
신규 비공개 정적 특성 공항을 선언하고 테이블 유형 tt_airportals 로 입력합니다.
클래스 정의 끝에 다음 코드를 추가합니다.
123
CLASS-DATA airports TYPE tt_airports.
태스크 3: 클래스 생성자에 정적 특성 입력
클래스 생성자를 정의하고 CDS 뷰 엔티티 /DMO/I_Airport에서 정적 특성 공항으로 사용 가능한 모든 공항을 읽는 SELECT 문을 구현합니다.
단계
Quick Fix를 사용하여 로컬 클래스 lcl_connection 에 클래스 생성자를 추가합니다.
클래스 이름에 커서를 놓고 Ctrl + 1 을 누릅니다.
클래스 생성자 생성 을 더블 클릭합니다.
클래스 생성자에서 CDS 뷰 엔티티 /DMO/I_Airport의 모든 데이터 세트를 정적 특성 공항 으로 읽는 SELECT 문을 구현합니다.
class_constructor 메소드의 구현으로 이동합니다.
메소드 구현 안에 다음 코드를 추가합니다.
12345
SELECT FROM /DMO/I_Airport
FIELDS AirportID, Name
INTO TABLE @airports.
태스크 4: 내부 테이블(Internal Table)의 내용 액세스
메소드 get_output 에서 내부 테이블 공항의 컨텐트를 사용하여 공항 이름을 출력에 추가합니다.
단계
get_output 메소드의 구현으로 이동합니다.
이전 연습문제에서 완료한 대로 진행합니다.
메소드 시작 시 출발 공항의 세부사항을 읽고 구조화된 데이터 오브젝트 출발을 확인합니다.
힌트
데이터 오브젝트 출발에는 테이블식 airports[ ... ] 및 인라인 선언을 사용합니다.
메소드 시작 부분에 다음 코드를 추가합니다.
123
DATA(departure) = airports[ airportID = details-departureairport ].
마찬가지로 대상 공항의 세부사항을 구조화 데이터 오브젝트 대상으로 읽어옵니다.
코드를 다음과 같이 조정합니다.
1234
DATA(departure) = airports[ airportID = details-departureairport ].
DATA(destination) = airports[ airportID = details-destinationairport ].
두 구조의 컴포넌트 이름을 사용하여 출력에 공항 이름을 추가합니다.
코드를 다음과 같이 조정합니다.
1234
APPEND |Departure: { details-departureairport } { departure-name }| TO r_output.
APPEND |Destination: { details-destinationairport } { destination-name }| TO r_output.
선택사항: 구조화 데이터 오브젝트를 생략하고 문자열 템플릿에서 테이블식을 직접 사용합니다.
구조 출발과목적지를 채우는 코드 라인을 주석 처리합니다.
문자열 템플릿에서 departure-name 을 airports[ airportid = details-departureairport ]-name 으로 바꿉니다.
마찬가지로 destination-name 을 airports[ airportid = details-destinationairport ]-name 으로 바꿉니다.
클래스를 활성화합니다. 이를 실행하고 콘솔 출력을 분석합니다. 출력에 모든 특성에 대한 데이터가 표시되는지 확인합니다.
Ctrl + F3 을 눌러 클래스를 활성화합니다.
F9 를 눌러 클래스를 실행합니다.