기본 SELECT 문 구현

Objectives

After completing this lesson, you will be able to:
  • ABAP SQL의 기본 기능 이해
  • 데이터베이스에서 단일 값을 읽습니다.

기본 ABAP SQL 구문

SQL(Structured Query Language)

모든 관계형 데이터베이스 시스템은 SQL(Structured Query Language)의 변형을 사용하여 작업할 수 있습니다. 표준 SQL은 다음과 같은 세 가지 주요 컴포넌트로 구성됩니다.

데이터 조작 언어(DML, Data Manipulation Language)
DML은 데이터베이스 테이블의 정보로 작업해야 하는 명령문으로 구성됩니다. 신규 레코드를 추가하기 위한 INSERT, 데이터를 읽는 SELECT, 기존 레코드를 변경하려면 UPDATE, 테이블 내용을 삭제하는 DELETE가 있습니다. 이러한 명령문은 ABAP에 ABAP SQL의 형태로 반영됩니다.
데이터 정의 언어(DDL, Data Definition Language)
데이터 정의 언어는 데이터베이스 테이블 및 기타 데이터베이스 아티팩트(예: 스키마, 테이블 인덱스, 뷰)를 생성하고 삭제할 수 있는 명령을 제공합니다. SAP 시스템에서는 ABAP 프로그램이 아닌 ADT의 전용 편집기를 사용하여 이러한 태스크를 수행합니다. 한 가지 예로 앞에서 살펴본 데이터베이스 테이블 정의 편집기가 있습니다.
데이터 제어 언어(DCL, Data Control Language)
SQL에서는 데이터 제어 언어를 사용하여 데이터베이스의 데이터에 대한 특정 사용자의 액세스를 제한합니다. 데이터베이스 레벨의 사용자는 최종 사용자와 일대일로 일치하지 않기 때문에 이는 ABAP에서 기존 형태로 사용되지 않습니다. 따라서 ABAP에는 고유 권한 개념이 있습니다.

ABAP SQL 아키텍처

이전에는 SAP 시스템에서 다양한 데이터베이스 플랫폼을 지원해야 했으며, 각 플랫폼의 SQL 표준 구현에는 조금씩 차이가 있었습니다. 즉 각 플랫폼에서 특정 태스크를 수행하기 위한 명령어도 조금씩 달랐습니다. ABAP 코드가 데이터베이스별로 고유해지는 것을 방지하기 위해 SAP는 원래 호출된 ABAP SQL 또는 Open SQL을 개발했습니다.

노트

Open SQL 및 ABAP SQL에서 이름이 변경되면 7.53 릴리스 ABAP에서는 SAP HANA만 DBMS로 지원됩니다.

ABAP SQL은 ABAP 레벨에서 구현되고 ABAP 언어에 통합된 추상 SQL 명령어 세트입니다. 런타임 시 ABAP SQL은 데이터베이스에서 인식되는 SQL 변형으로 변환됩니다. ABAP에 통합된 SQL 변형인 ABAP SQL과 구분하기 위해 이 변형을 Native SQL이라고 합니다. ABAP SQL에서 Native SQL로의 변환은 데이터베이스 인터페이스에서 수행되며, 이는 일반 부분과 데이터베이스 고유 라이브러리로 구성된 ABAP 시스템의 컴포넌트입니다.

최신 ABAP 릴리스는 SAP HANA만 DBMS로 지원하지만 SAP는 여전히 ABAP SQL과 데이터베이스 인터페이스의 개념을 유지해 왔습니다. 그 이유는 다음과 같습니다.

아키텍처 호환성
ABAP SQL과 데이터베이스 인터페이스는 시스템 아키텍처의 핵심 요소입니다.
코드 호환성
이전 SAP 제품(고객 고유 개발 포함)의 ABAP SQL 코딩은 최신 SAP HANA 전용 ABAP 환경에서 부작용 없이 실행되어야 합니다.
데이터베이스 인터페이스 태스크
데이터베이스 인터페이스는 명령문만 번역하는 것이 아니라 자동 클라이언트 처리와 같은 ABAP 고유 태스크도 담당합니다.

데이터베이스에서 단일 레코드 읽기

ABAP의 SELECT 문

데이터베이스에서 데이터를 읽으려면 SELECT 문을 사용합니다.

ABAP SQL에서 SELECT 문을 작성할 때 구문 점검은 사용자가 작성한 내용을 테이블과 뷰의 정의와 비교합니다. 존재하지 않는 테이블, 뷰 또는 필드를 처리하려고 하면 구문 오류가 발생합니다.

SELECT 문의 기본 구문에는 절이라고 하는 여러 섹션이 포함되어 있으며 'ABAP의 SELECT 문' 그림의 패턴을 항상 따릅니다. SELECT 문에서 가장 중요한 절은 다음과 같습니다.

FROM
SELECT 문의 FROM 절에서 읽을 데이터 소스를 지정합니다. 데이터베이스 테이블일 수도 있고 뷰일 수도 있습니다. 특수 SQL 기법을 사용하면 여러 소스의 데이터를 동일한 SELECT 문으로 결합할 수 있습니다.
FIELDS
SELECT 문의 FIELDS 절에서 읽으려는 데이터베이스 테이블의 열을 나열합니다. 쉼표를 사용하여 리스트의 열을 구분해야 합니다. 전체 테이블 라인을 읽으려는 경우 열 리스트 대신 FIELDS *를 지정하면 됩니다. 그러나 이로 인해 필요한 열만 읽는 것보다 데이터베이스가 상당히 많이 작동할 수 있다는 점에 유의하십시오.
WHERE

WHERE 절에 테이블에서 읽을 행에 대해 설명하는 조건을 지정할 수 있습니다. 예를 들어 WHERE carrier_id = 'LH' 조건은 (CARRIER_D 열에 LH 값이 포함된) 해당 행만 읽는다는 것을 의미합니다.

WHERE 절에는 AND와 OR 연산자로 연결된 여러 개의 조건이 포함될 수 있습니다. 예를 들어 WHERE carrier_id = 'LH' 및 connection_id = '0400'은 항공편 연결 LH 0400 의 데이터를 반환합니다. 또한 NOT을 사용하여 조건을 부정할 수도 있습니다. WHERE 절은 선택사항인 유일한 절입니다. 그러나 WHERE 절이 없으면 테이블에서 모든 데이터를 읽거나 테이블에 클라이언트 필드가 있는 경우 사용자의 로그온 클라이언트에 속하는 모든 데이터에 유의하십시오. WHERE 절이 없는 SELECT는 심각한 성능 문제를 일으킬 수 있으므로 피해야 합니다.

INTO
INTO 절은 데이터를 배치할 ABAP 프로그램의 변수를 지정합니다. 이는 일반적으로 구조 또는 내부 테이블이며 FIELDS 절의 열 리스트와 동일한 컴포넌트 순서를 갖는 것이 좋습니다.

노트

ABAP에는 다른 형태의 SQL 구문이 표시됩니다. 이는 이전에 사용된 것으로 호환성을 위해 유지되었습니다. 최신 구문은 이전 형태보다 훨씬 더 많은 기능을 제공하므로 이를 사용하는 방법을 숙지해야 합니다.

'예 1: 단일 레코드의 단일 필드 읽기' 그림에 데이터베이스에서 단일 값을 읽는 SELECT 문이 나와 있습니다. FROM 절은 명령문이 데이터베이스 테이블 /DMO/CONNECTION에서 읽음을 지시합니다. 키워드 SELECT 뒤에 있는 SINGLE 옵션은 하나의 행(단일 레코드)만 읽는다는 것을 나타냅니다. 이 행은 키 필드 carrier_id 및 connection_id 에 대한 키 필터 값을 제공하여 WHERE 절에서 식별됩니다. 데이터베이스 인터페이스는 나머지 키 필드 클라이언트에 필터를 추가합니다.

FIELDS 절에는 AIRPORT_FROM_ID 열의 테이블 열 하나만 나열됩니다.

INTO 절은 나머지 명령문과 일치해야 합니다. 이 예에서는 airport_from_id 변수를 대상 오브젝트로 지정하고 테이블 필드 airport_from_id와 유형이 동일한 스칼라 데이터 오브젝트를 지정합니다.

노트

@ 기호는 airport_from_id를 ABAP 데이터 오브젝트의 이름으로 식별합니다. ABAP SQL 문에서 사용하는 모든 변수와 상수에는 필수 항목입니다. 예를 들어, 데이터 오브젝트와 테이블 필드의 이름이 동일한 경우 모호성을 방지해야 합니다.

'예 2: 단일 레코드의 여러 필드 읽기' 그림에 데이터베이스의 동일한 레코드에서 두 개의 값을 읽는 SELECT 문이 나와 있습니다.

이번에는 FIELDS 절에 테이블의 두 열 AIRPORT_FROM_ID 열과 AIRPORT_TO_ID 열이 나열됩니다.

이를 위해 INTO 절은 airport_from_id 및 airport_to_id 변수를 대상 오브젝트로 지정합니다. 쉼표로 구분되고 괄호 쌍으로 둘러싸여서 SELECT 문의 대상을 형성한다는 점을 명확히 합니다.

SELECT 문을 구현할 때는 데이터베이스 테이블에 데이터가 전혀 포함되어 있지 않거나 WHERE 절의 조건에 맞는 행이 포함되어 있지 않기 때문에 항상 결과가 없을 수 있다는 점을 고려해야 합니다. 위 그림의 예에서는 데이터베이스 테이블에 carrier_id = 'XX', connection_id = '1234'인 행이 없습니다.

ABAP SQL에서는 시스템 필드 SY-SUBRC를 사용하여 명령문의 실행이 성공하거나 실패했음을 나타냅니다. 시스템 필드 SY-SUBRC는 정수 유형입니다. 초기 값 0은 항상 실행에 성공했음을 나타냅니다. SELECT 문 뒤에 SY-SUBRC 의 값이 4 이면 데이터베이스가 빈 결과를 반환했음을 나타냅니다.

데이터베이스에서 빈 결과가 반환되면 ABAP SQL이 INTO 다음에 대상 변수를 건드리지 않습니다!

특히 오류 발생 시 대상 변수가 초기화되지 않습니다.

각 SELECT 문 바로 뒤에 시스템 필드 sy-subrc의 내용을 평가하는 것이 좋습니다.

사용해 보기: SELECT 예제

  1. 이 과정의 첫 번째 연습문제와 마찬가지로 인터페이스 IF_OO_ADT_CLASSRUN을 구현하는 신규 전역 클래스를 생성합니다.
  2. 다음 코드 스니핏을 if_oo_adt_classrun~main( ) 메소드의 구현 부분에 복사합니다.
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
    DATA airport_from_id TYPE /DMO/airport_from_id. DATA airport_to_id TYPE /DMO/airport_to_id. DATA airports TYPE TABLE OF /DMO/airport_from_id. * Example 1: Single field from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO @airport_from_id. out->write( `----------` ). out->write( `Example 1:` ). out->write( |Flight LH 400 departs from { airport_from_id }.| ). * Example 2: Multiple Fields from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO ( @airport_from_id, @airport_to_id ). out->write( `----------` ). out->write( `Example 2:` ). out->write( |Flight LH 400 flies from { airport_from_id } to { airport_to_id }| ). * Example 3: Empty Result and sy-subrc ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'XX' AND connection_id = '1234' INTO @airport_from_id. IF sy-subrc = 0. out->write( `----------` ). out->write( `Example 3:` ). out->write( |Flight XX 1234 departs from { airport_from_id }.| ). ELSE. out->write( `----------` ). out->write( `Example 3:` ). out->write( |There is no flight XX 1234, but still airport_from_id = { airport_from_id }!| ). ENDIF.
  3. CTRL + F3 을 눌러 클래스를 활성화하고 F9 를 눌러 콘솔 앱으로 실행합니다.
  4. 콘솔 출력을 분석합니다. 프로그램을 디버그하고 소스 코드를 사용하여 개념을 숙지합니다.

데이터베이스 테이블에서 데이터 읽기

이번 연습문제에서는 출발 공항과 도착 공항에 대한 특성으로 로컬 클래스를 확장하고 데이터베이스 테이블에서 이러한 특성의 값을 읽습니다.

템플릿:

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR(전역 클래스)

솔루션:

  • /LRN/CL_S4D400_DBS_SELECT(전역 클래스)

태스크 1: 템플릿 복사

템플릿 클래스를 복사합니다. 또는 이전 연습문제의 솔루션을 복사합니다.

단계

  1. 클래스 /LRN/CL_S4D400_CLS_CONSTRUCTOR 를 자체 패키지의 클래스(제안 이름: ZCL_##_SELECT, ##은 그룹 번호)에 복사합니다.

    1. 전역 클래스 /LRN/CL_S4D400_CLS_CONSTRUCTOR 의 소스 코드를 엽니다.

    2. 프로젝트 탐색기 뷰를 편집기와 연결합니다.

    3. 프로젝트 탐색기 뷰에서 클래스 /LRN/CL_S4D400_CLS_CONSTRUCTOR 를 마우스 오른쪽 버튼으로 클릭하여 단축 메뉴를 엽니다.

    4. 단축 메뉴에서 Duplicate .... 를 선택합니다.

    5. 패키지 필드에 패키지 이름을 입력합니다. 이름 필드에 이름 ZCL_##_SELECT 를 입력합니다. 여기서 ##은 그룹 번호입니다.

    6. 내역을 조정하고 다음 을 선택합니다.

    7. 전송 요청을 확인하고 Finish를 선택합니다.

태스크 2: 추가 특성 선언

로컬 클래스 lcl_connection 을 private 인스턴스 특성 airport_from_idairport_to_id 로 확장합니다. 신규 특성의 출력을 get_output 메소드의 구현에 추가합니다.

노트

신규 특성이 아직 입력되지 않았습니다. 이를 위해 이 연습문제의 다음 태스크 중 하나에서 생성자에 SELECT 문을 추가합니다.

단계

  1. 로컬 클래스 lcl_connection 으로 전환합니다.

    1. 전역 클래스에서 로컬 유형 을 선택합니다.

  2. 클래스 정의에 다음 전용 특성을 추가합니다.

    특성

    특성 이름범위데이터 유형
    airport_from_id인스턴스/DMO/AIRPORT_FROM_ID
    airport_to_id인스턴스/DMO/AIRPORT_TO_ID
    1. 코드를 다음과 같이 조정합니다.

      Code Snippet
      12345678910
      PRIVATE SECTION. DATA carrier_id TYPE /dmo/carrier_id. DATA connection_id TYPE /dmo/connection_id. DATA airport_from_id TYPE /dmo/airport_from_id. DATA airport_to_id TYPE /dmo/airport_to_id. ENDCLASS.
  3. get_output 메소드의 구현을 확장합니다. 리턴 매개변수 r_output 에 문자열 템플릿을 더 추가합니다. 신규 특성을 표현식으로 문자열 템플릿에 임베드합니다.

    1. get_output 메소드의 구현으로 이동합니다.

    2. 코드를 다음과 같이 조정합니다.

      Code Snippet
      1234567
      APPEND |--------------------------------| TO r_output. APPEND |Carrier: { carrier_id }| TO r_output. APPEND |Connection: { connection_id }| TO r_output. APPEND |Departure: { airport_from_id }| TO r_output. APPEND |Destination: { airport_to_id }| TO r_output.
  4. 클래스를 활성화합니다. 이를 실행하고 콘솔 출력을 분석합니다.

    1. Ctrl + F3 을 눌러 클래스를 활성화합니다.

    2. F9 를 눌러 클래스를 실행합니다.

태스크 3: 데이터베이스 테이블 분석

데이터베이스 테이블 /DMO/CONNECTION의 정의를 분석합니다.

단계

  1. 데이터베이스 테이블 /DMO/CONNECTION의 정의가 포함된 개발 오브젝트를 엽니다.

    1. Eclipse 툴바에서 Open ABAP Development Object 를 선택하거나 Ctrl + Shift + A 를 누릅니다.

    2. 입력 필드에 /dmo/con 을 검색 문자열로 입력합니다.

    3. 일치하는 항목 리스트에서 /DMO/CONNECTION (데이터베이스 테이블)을 클릭하고 확인 을 선택합니다.

  2. 데이터베이스 테이블 /DMO/CONNECTION 의 요소 정보(F2) 를 엽니다.

    1. 키워드 /dmo/connection 다음에 define table 를 클릭하고 F2 를 눌러 요소 정보를 표시합니다.

태스크 4: 데이터베이스의 데이터 읽기

로컬 클래스 lcl_connection 의 메소드 생성자에서 데이터베이스 테이블 /DMO/CONNECTION의 신규 특성 값을 읽는 SELECT 문을 구현합니다.

단계

  1. 전역 클래스의 lcl_connection 로컬 클래스로 돌아갑니다.

    1. Eclipse 의 편집기 뷰에서 ZCL_##_SELECT 탭을 엽니다.

    2. 전역 클래스에서 로컬 유형 을 선택합니다.

  2. 메소드 생성자의 구현으로 이동합니다.

    1. 코드 라인 METHOD constructor. 을 검색합니다.

  3. ENDIF. 문 뒤에 데이터베이스 테이블 /DMO/CONNECTION에서 단일 레코드를 읽는 SELECT 문을 추가합니다.

    1. 코드를 다음과 같이 조정합니다.

      Code Snippet
      123456789
      IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. SELECT SINGLE FROM /dmo/connection
  4. FIELDS 절을 구현합니다. 테이블 필드 airport_from_id와airport_to_id를 읽습니다.

    힌트

    자동 완성(Ctrl + Space)을 사용하여 필드 이름을 입력합니다.
    1. FROM /DMO/CONNECTION 다음에 FIELDS 입력합니다.

    2. 비워 둔 후 Ctrl + Space 를 누르고 airport_from_id 를 선택합니다.

    3. 쉼표를 입력하고 공백 뒤에 Ctrl + Space 를 다시 누르고 airport_to_id 를 선택합니다.

    4. 전체 FIELDS 절은 다음과 같아야 합니다.

      Code Snippet
      123
      FIELDS airport_from_id, airport_to_id
  5. WHERE 조건을 구현합니다. 임포트 매개변수 i_carrier_id 및i_connection_id 의 값으로 데이터베이스 테이블의 모든 키 필드를 제한합니다(클라이언트 필드 제외). 접두부가 @ 인 매개변수는 이스케이프해야 합니다.

    힌트

    자동 완성(Ctrl + Space)을 사용하여 요소 이름과 매개변수 이름을 입력합니다.
    1. 다음 코드를 FIELDS 절 뒤에 추가합니다.

      Code Snippet
      1234
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id
  6. INTO 절을 구현합니다. 특성 airport_from_id 및airport_to_id에 SELECT 결과를 저장합니다. 접두부가 @ 인 특성은 이스케이프해야 합니다.

    힌트

    자동 완성(Ctrl + Space)을 사용하여 특성 이름을 입력합니다.
    1. 코드를 다음과 같이 조정합니다.

      Code Snippet
      123456
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
    2. 전체 SELECT 문은 다음과 같아야 합니다.

      Code Snippet
      12345678
      SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
  7. SELECT 문 뒤에 오류 처리를 구현합니다. 시스템 필드 sy-subrc의 내용을 확인합니다. 0이 아니면 CX_ABAP_INVALID_VALUE 예외가 발생합니다.

    1. SELECT 문 뒤에 다음 코드를 추가합니다.

      Code Snippet
      12345
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF.
  8. 클래스를 활성화합니다. 이를 실행하고 콘솔 출력을 분석합니다. 신규 특성에 대한 출력에 데이터가 표시되는지 확인합니다.

    1. Ctrl + F3 을 눌러 클래스를 활성화합니다.

    2. F9 를 눌러 클래스를 실행합니다.