ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Open SQL & Native SQL] SELECT
    SAP/Abap 2022. 1. 12. 13:17
    • [SELECT문 전체 구조]
    SELECT <cols> SELECT하고자 하는 테이블의 필드(컬럼)명 나열
    INTO <target> SELECT문을 통해 읽어온 데이터를 저장할 타겟변수 지정
    FROM <source> SELECT문이 동작할 테이블 지정
    WHERE <cond> SELECT하고자 하는 데이터의 조건 지정
    GROUP BY <fields> SELECT결과 데이터를 필드단위로 그룹으로 묶어 그룹별 데이터를 구한다.
    HAVING <cond> GROUP BY의 조건을 지정
    ORDER BY <fields> SELECT한 데이터를 정렬할 옵션을 지정

     

    [SELECT 구문]

    1) 에스터리스크(*) 기호를 통해 전체 필드를 읽어올 수 있지만, 다른 시스템에 비해 SAP 시스템의 주요 테이블에는 많은 필드가 존재하므로 SELECT * 구문은 전체 프로그램 성능에 큰 영향을 미칠 수 있다.

    • SELECT * 구문은 컬럼의 전체 필드를 한번에 읽어오지 못하고, 일정 크기만큼 잘라서 SELECT 결과를 반환한다.

     

    2) Database에서 하나의 라인값을 SELECT할 경우에는 SINGLE 키워드를 사용하고 이때 데이터의 조건이 명확해야한다.

    • SELECT SINGLE <cols>
    • SELECT SINGLE 할 데이터의 조건이 명확하지 않으면 여러개의 라인 중 임의의 라인을 반환한다.

     

    3) Database에서 여러 라인이 SELECT된 경우 중복값을 제거하기 위해 DISTINCT 키워드를 사용할 수 있다.

    • SELECT DISTINCT <cols>

    4) Database에서 여러 라인이 SELECT되면 해당 결과는 인터널 테이블(Internal Table)내부 또는 필드 및 구조체에 저장된다.

    • 인터널 테이블에 저장
      • Abap 메모리에 생성되는 데이터를 저장할 수 있는 가상 테이블을 생성하여 데이터를 임시 저장한다.
    • Work area(필드 및 구조체)에 저장
      • SELECT된 여러 값 중 하나의 값을 필드 및 구조체에 삽입하고 모든 값을 읽을때 까지 loop를 수행하며, 이 경우 SELECT문 마지막에 ENDSELECT 키워드를 추가해야 한다.
      • 여러 컬럼을 한번에 저장하는 인터널 테이블 저장방식에 비해 비효율적이다.
    REPORT ZA03_01.
    
    DATA : gt_itab TYPE STANDARD TABLE OF sflight,    " sflight 테이블과 같은 type의 테이블
           gs_wa   TYPE sflight.                      " sflight 테이블 컬럼과 같은 type의 구조체
    
    * 필드 및 구조체를 이용하는 SELECT 구문
    SELECT * INTO gs_wa
    FROM sflight
    WHERE carrid EQ 'AA'.
      WRITE :/ gs_wa-carrid, gs_wa-connid.
    ENDSELECT.
    
    * 인터널 테이블을 이용하는 SELECT 구문
    SELECT * INTO TABLE gt_itab
    FROM sflight
    WHERE carrid EQ 'AA'.
    * 인터널 테이블에 저장된 데이터를 LOOP처리
    LOOP AT gt_itab INTO gs_wa.
      WRITE :/ gs_wa-carrid, gs_wa-connid.
    ENDLOOP.

     

     

    5) AS 키워드를 사용하여 컬럼 명에 Alias(별명)을 지정할 수 있다.

    • SELECT <cols> [AS <alias>]

     

    6) SELECT문의 대상이 되는 컬럼을 동적으로 선언할 수 있다.

    • 동적 구문을 저장할 변수는 Type c, Length 72의 변수여야 한다. 
    REPORT ZA03_02.
    
    DATA : gt_itab       TYPE STANDARD TABLE OF sflight,    " sflight table type의 테이블 변수 선언
           gs_wa         LIKE LINE OF gt_itab,              " gt_itab table의 컬럼 형태의 구조체 선언
           gs_line(72)   TYPE c.                            " 동적 SELECT 컬럼값 저장을 위한 변수 선언
    
    gs_line = 'carrid connid'.                              " SELECT 대상 컬럼 지정
    
    SELECT DISTINCT (gs_line) INTO TABLE gt_itab
    FROM sflight.
    
    IF sy-subrc EQ 0.                                       " SELECT구문 정상 동작시 LOOP처리
      LOOP AT gt_itab INTO gs_wa.
        WRITE :/ gs_wa-carrid, gs_wa-connid.
      ENDLOOP.
    ENDIF.
    • 동적 구문의 길이가 72를 넘는경우 해당 변수를 테이블로 선언하여 사용한다.
    REPORT ZA03_02.
    
    DATA : gt_itab       TYPE STANDARD TABLE OF sflight,    " sflight table type의 테이블 변수 선언
           gs_wa         LIKE LINE OF gt_itab,              " gt_itab table의 컬럼 형태의 구조체 선언
           gs_line(72)   TYPE c,                            " 동적 SELECT 컬럼값 저장을 위한 변수 선언
           gt_list       LIKE TABLE OF gs_line(72).         " gs_line을 컬럼으로 갖는 table 생성
    
    gs_line = 'carrid connid'.                              " SELECT 대상 컬럼 지정
    APPEND gs_line TO gt_list.                              " 테이블 gt_list에 gs_line 추가
    
    SELECT DISTINCT (gt_list) INTO TABLE gt_itab
    FROM sflight.
    
    IF sy-subrc EQ 0.                                       " SELECT구문 정상 동작시 LOOP처리
      LOOP AT gt_itab INTO gs_wa.
        WRITE :/ gs_wa-carrid, gs_wa-connid.
      ENDLOOP.
    ENDIF.

     

    [INTO 구문]

    SELECT구문에서 조회한 결과값을 변수에 저장하는 구문으로 CORRESPONDING FIELDS OF 구문을 통해 SELECT구문의 필드와 동일한 필드에만 값을 할당할 수 있다.

    1) Work area(변수 및 구조체)에 저장

    • 테이블 내 하나의 컬럼만 조회하는 경우 사용한다.
    • SELECT INTO [CORRESPONDING FIELDS OF] <wa>

     

    2) Internal table에 저장

    • 테이블 내 다수의 컬럼을 조회하는 경우 사용한다.
    • SELECT INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE <itab> [PACKAGE SIZE <n>]
    • INTO: 인터널 테이블을 초기화 한 후 데이터를 삽입한다.
    • APPENDING: 인터널 테이블을 초기화 하지 않고 추가로 삽입한다.
    • PACKAGE SIZE: 인터널 테이블에 삽일할때 몇개의 라인씩 삽입할지 지정한다.
      • PACKAGE SIZE 키워드를 이용하는 경우 ENDSELECT 구문을 추가해야 한다.
    REPORT ZA03_04.
    
    DATA : gs_wa   TYPE sflight,
           gt_itab TYPE TABLE OF sflight.
    
    * spfli 테이블의 carrid, connid 필드를 sflight table type의 인터널 테이블에
    * 삽입하기 위해 CORRESPONDING FIELDS OF 구문 사용
    SELECT carrid connid
    FROM spfli
    INTO CORRESPONDING FIELDS OF TABLE gt_itab
    PACKAGE SIZE 5.
      LOOP AT gt_itab INTO gs_wa.
        WRITE :/ gs_wa-carrid, gs_wa-connid.
      ENDLOOP.
    ENDSELECT.

     

    3) INTO 구문을 통해 특정 변수에 SELECT 결과를 삽입할때는 다음 구문을 사용한다.

    • SELECT ... INTO (f1, f2...)

     

    [FROM 구문]

    • FROM 구문은 SELECT할 대상 테이블을 지정한다.
    • FROM <table> [<option>]
    • FROM 구문의 option
      CLIENT SPECIFIED 자동 client설정을 해제한다.
      BYPASSING BUFFER SAP local buffer에서 값을 읽지 않고 바로 DB table에 접근한다.
      UP TO n ROWS SELECT문의 대상 row개수를 제한한다. => 대량요청으로 인한 성능 저하 방지

    1) 정적 테이블 지정

    • SELECT ... FROM <dbtab> [AS <alias>] <option>

    2) 동적 테이블 지정

    • SELECT ... FROM (dbtab).
    • 동적으로 지정할 테이블 이름은 반드시 대문자여야하며, Abap dictionary에 존재해야한다.
    REPORT ZA03_05.
    
    * 동적으로 지정될 테이블이름을 파라미터로 사용자로부터 입력받음
    * PARAMETERS 사용시 자동으로 SELECTION SCREE이 생성된다.
    PARAMETERS p_tname TYPE char10.
    DATA gs_wa TYPE sflight.
    
    SELECT SINGLE * INTO gs_wa
    FROM (p_tname)
    WHERE carrid = 'AA'.
    
    WRITE :/ gs_wa-carrid, gs_wa-connid.

     

    3) JOIN 구문

    • SELECT ... FROM <tab> [INNER] JOIN <dbtab> [AS <alias>] ON <cond> <options>...
    • 여러 테이블의 값을 동시에 읽어올 경우 JOIN을 사용한다.
      • 이때, 대상이되는 테이블들 간의 연결 조건은 ON구문을 통해 지정하며, 조건에 해당하는 필드에 인덱스가 존재할때 빠른 성능이 보장된다.
    • 잘못된 코드: 인터널테이블에 저장된 데이터를 대상으로 LOOP를 돌려 추가 작업을 수행
      SELECT field1 INTO gt_itab FROM table1.
      LOOP AT gt_itab.
        SELECT field2 INTO gt_iteb-field2 FROM table2
        WHERE field1 = gt_itab-field1
        MODIFY gt_itab.
      ENDLOOP.​
    • 올바른 코드: JOIN연산을 사용
      SELECT a~field1 b~field2 INTO gt_itab
      FROM table1 AS a INNER JOIN table2 AS b
      ON a~filed1 = b~field1.​
    • SQL 구문에서는 WHERE 조건이 ON 조건보다 먼저 처리된다.
    REPORT ZA03_06.
    
    TYPES: BEGIN OF t_str,
      carrid     TYPE sflight-carrid,
      carrname   TYPE scarr-carrname,
    END OF t_str.
    
    DATA : gs_str TYPE t_str.
    
    SELECT SINGLE a~carrid b~carrname
    INTO CORRESPONDING FIELDS OF gs_str
    FROM sflight AS a
    INNER JOIN scarr AS b
    ON a~carrid EQ b~carrid
    WHERE a~carrid = 'AA'.
    
    WRITE :/ gs_str-carrid, gs_str-carrname.
    • OUTER JOIN
      • INNER JOIN은 ON조건을 기준으로 두 테이블의 공통데이터를 추출하므로, 특정 테이블 하나에 데이터가 없다면 다른 테이블에 데이터가 존재해도 해당 데이터는 추출되지 않는다.
      • OUTER JOIN은 특정 테이블에 다른 테이블에 해당하는 데이터가 없더라도 해당 데이터를 추출하는 연산이다.
      • 즉, 아래 프로그램에서는 확인이 어렵지만, 만약 sflight 테이블에 carrid가 'KO'인 데이터가 존재한다면 OUTER JOIN결과 scarr테이블에 'KO'에 해당하는 carrname이 없더라도 'KO'에 대한 데이터가 빈칸으로 조회될 것이다.
    REPORT ZA03_07.
    
    TYPES: BEGIN OF t_str,
      carrid     TYPE sflight-carrid,
      carrname   TYPE scarr-carrname,
    END OF t_str.
    
    DATA : gs_str TYPE t_str.
    
    SELECT DISTINCT a~carrid b~carrname
    INTO CORRESPONDING FIELDS OF gs_str
    FROM sflight AS a
    LEFT OUTER JOIN scarr AS b
    ON a~carrid EQ b~carrid.
      WRITE :/ gs_str-carrid, gs_str-carrname.
    ENDSELECT.

     

    4) Line 수 제한 구문

    • SELECT ... FROM <tab> UP TO <n> ROWS ...
    • 해당 구문은 테이블의 최대 조회 컬럼수를 제한하기 위해 사용된다.
    • SAP 시스템에는 방대한 양의 데이터가 있어 사용자가 조회조건 없이 조회를 한다면 시스템 성능에 영향을 줄 수 있기때문이다.

     

     

    [WHERE 구문]

    • WHERE조건에 사용되는 필드에 인덱스가 존재할때 빠른 성능이 보장된다.
    • WHERE구문 연산자
      EQ(=) NE(<>, ><) LT(<) LE(<=) GT(>) GE(>=)
      같음 같지 않음 보다 작음 보다 작거나 같음 보다 큼 보다 크거나 같음

    1) Interval 조건

    SELECT ... WHERE <s> [NOT] BETWEEN <f1> AND <f2>

    2) String 비교

    SELECT ... WHERE <s> LIKE <f1>                => Format 비교

    3) List value

    SELECT ... WHERE <s> [NOT] IN (<f1>, <f2>, ...)

    4) Selection table

    • 리스트 외에도 IN구문을 통해 Selection table, Range변수에 존재하는 값을 이용한 조회가 가능하다.
      • Selection table, range: 인터널 테이블과 같이 여러 row를 저장할 수 있는 변수
    SELECT ... WHERE <s> [NOT] IN <seltab>

    5) Dynamic(동적) 조건

    • SELECT 구문과 마찬가지로 Type c length 72조건을 갖는다.
    REPORT ZA03_08.
    
    DATA : gs_where     TYPE c LENGTH 72,
           gv_carrname  TYPE scarr-carrname,
           gv_carrid    TYPE scarr-carrid VALUE 'AC'.
    
    * '': 문자열 변수 내에서 quatation(')을 표현
    * gs_where => carrid = 'AC'
    CONCATENATE 'carrid = ''' gv_carrid '''' INTO gs_where.
    
    SELECT SINGLE carrname
    INTO gv_carrname
    FROM scarr
    WHERE (gs_where).
    
    WRITE :/ gv_carrname.
    • 다수의 동적 조건을 지정할때는 인터널테이블을 사용한다.
    REPORT ZA03_09.
    
    DATA : gs_where     TYPE c LENGTH 72,
           gt_where     LIKE TABLE OF gs_where,        " 다수의 동적조건을 위해 인터널테이블 선언
           gv_carrname  TYPE scarr-carrname,
           gv_carrid1   TYPE scarr-carrid VALUE 'AC',
           gv_carrid2   TYPE scarr-carrid VALUE 'AF'.
    
    CONCATENATE 'carrid = ''' gv_carrid1 '''' INTO gs_where.
    APPEND gs_where TO gt_where.            " 1번째 조건 추가
    
    gs_where = 'OR'.
    APPEND gs_where TO gt_where.            " 조건 연산자 추가
    
    CONCATENATE 'carrid = ''' gv_carrid2 '''' INTO gs_where.
    APPEND gs_where TO gt_where.            " 2번째 조건 추가
    
    SELECT carrname
    INTO gv_carrname
    FROM scarr
    WHERE (gt_where).
    WRITE :/ gv_carrname.
    ENDSELECT.

     

    6) FOR ALL ENTRIES 구문

    • SELECT ... FOR ALL ENTRIES IN <itab> WHERE <cond>
    • 인터널테이블과 실제 Database의 테이블을 join하는 개념.
    REPORT ZA03_10.
    
    DATA : gt_spfli      TYPE TABLE OF spfli,
           gt_sflight    TYPE TABLE OF sflight,
           gs_sflight    TYPE sflight.
    
    SELECT * FROM spfli
      INTO TABLE gt_spfli.
    
    * FOR ALL ENTRIES IN 구문의 gt_spfli 인터널테이블의 필드와 
    * 실제 Database내 sflight의 필드를 WHERE구문에서 비교
    SELECT * FROM sflight
      INTO TABLE gt_sflight
      FOR ALL ENTRIES IN gt_spfli
      WHERE carrid = gt_spfli-carrid
        AND connid = gt_spfli-connid.
    
    LOOP AT gt_sflight INTO gs_sflight.
      WRITE :/ gs_sflight-carrid, gs_sflight-connid.
    ENDLOOP.

     

    [GROUP BY 구문]

    • 테이블의 특정 컬럼의 값을 기준으로 데이터를 요약(집계)하여 조회한다.
    • Aggregate(집계) 함수를 사용하기 위해서는 GROUP BY구문이 기술되어야한다.
    • GROUP BY구문에 사용된 컬럼은 반드시 SELECT구문에 같은 컬럼으로 기술되어야 한다.
    AVG COUNT MAX MIN STDDEV SUM VARIANCE
    평균 개수 최대값 최소값 표준편차 합계 분산
    REPORT ZA03_11.
    
    DATA : gv_carrid       TYPE sflight-carrid,
           gv_connid       TYPE sflight-connid,
           gv_paymentsum   TYPE i.
    
    SELECT carrid connid AVG( paymentsum )
      INTO (gv_carrid, gv_connid, gv_paymentsum)
      FROM sflight
      GROUP BY carrid connid.
        WRITE :/ gv_carrid, gv_connid, gv_paymentsum.
    ENDSELECT.
    • Having 구문: GROUPING 조건
      • GROUP BY로 조회한 SELECT 구문에 조건을 추가한다.
      • WHERE 조건처럼 동적 선언이 가능하다.

     

    [ORDER BY 구문]

    • SELECT ... ORDER BY <f1> [ASCENDING | DESCENDING]
    REPORT ZA03_12.
    
    DATA : gv_carrid       TYPE sflight-carrid,
           gv_connid       TYPE sflight-connid,
           gv_paymentsum   TYPE i.
    
    SELECT carrid connid AVG( paymentsum ) as paymentsum
      INTO (gv_carrid, gv_connid, gv_paymentsum)
      FROM sflight
      GROUP BY carrid connid
      ORDER BY paymentsum.
        WRITE :/ gv_carrid, gv_connid, gv_paymentsum.
    ENDSELECT.

     

    [Subquery]

    서브쿼리란, SELECT 문 내부의 WHERE 구문 조건에 또 다른 SELECT 문을 추가하여 조건 비교를 하기위해 사용된다.

    1) Scalar Subquery

    • 서브쿼리의 결과로 하나의 컬럼 또는 집계(Aggregate)함수 값을 반환하는 서브쿼리
    REPORT ZA03_13.
    
    DATA : gv_carrid       TYPE sflight-carrid,
           gv_connid       TYPE sflight-connid,
           gv_paymentsum   TYPE sflight-paymentsum.
    
    SELECT SINGLE carrid connid paymentsum
      INTO (gv_carrid, gv_connid, gv_paymentsum)
      FROM sflight AS a
      WHERE carrid IN ( SELECT carrid
                          FROM spfli
                          WHERE carrid = a~carrid
                            AND connid = a~connid )
      AND a~carrid = 'AZ'.
    WRITE :/ gv_carrid, gv_connid, gv_paymentsum.

     

    2) Non-scalar Subquery

    • 서브쿼리의 결과가 존재하면 TRUE, 존재하지 않으면 FALSE를 반환하는 서브쿼리.
    • 메인쿼리의 WHERE 구문에서 EXISTS를 사용하여 구현한다.
    REPORT ZA03_14.
    
    DATA : gv_carrid       TYPE sflight-carrid,
           gv_connid       TYPE sflight-connid,
           gv_paymentsum   TYPE sflight-paymentsum.
    
    SELECT SINGLE carrid connid paymentsum
      INTO (gv_carrid, gv_connid, gv_paymentsum)
      FROM sflight AS a
      WHERE EXISTS ( SELECT *
                       FROM spfli
                       WHERE carrid = a~carrid
                         AND connid = a~connid )
      AND a~carrid = 'AZ'.
    WRITE :/ gv_carrid, gv_connid, gv_paymentsum.
Designed by Tistory.