SAP/ABAP

ABAP SELECT문 동적 WEHRE / RTTI를 활용하여 필드 존재 여부 확인

프라임콩 2025. 2. 27. 14:07
반응형

1. SAP ECC 6.0 기준으로 작성

2. 동적 where조건이 들어가야 하는 필드가 각 테이블 마다 필드명이 다름.

 

[1] SELECT문 동적 WEHRE 사용

*&---------------------------------------------------------------------*
*&      Form  GET_DETAIL
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_LT_RESB  text
*      -->P_LT_DATA  text
*      -->P_I_HISTORY  text
*----------------------------------------------------------------------*
FORM get_detail_resb  TABLES   pt_resb STRUCTURE zcrms0092
                      USING    ps_detail_info TYPE zcrms0095
                               p_history.

  CONSTANTS: c_f_posnr(11) VALUE 'posnr'.

  DATA: lv_where_posnr TYPE string,
        lv_where_matnr TYPE string.

  CLEAR: lv_where_posnr, lv_where_posnr.

  PERFORM get_where_clause USING ps_detail_info-posnr
                                 ps_detail_info-matnr
                                 c_f_posnr
                        CHANGING lv_where_posnr
                                 lv_where_matnr.

*-- Select Data
* p_history = 'X"일 경우 삭제 삭제 이력 테이블에서 조회한다.
  CASE p_history.
    WHEN space.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_resb
        FROM resb
       WHERE aufnr = ps_detail_info-aufnr
         AND (lv_where_matnr)
         AND (lv_where_posnr)
         AND bdmng = ps_detail_info-bdmng
         AND postp = 'N'
         AND xloek = space.

    WHEN 'X'.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_resb
        FROM zsst8073
       WHERE aufnr = ps_detail_info-aufnr
         AND (lv_where_matnr).
*         AND dedat = ps_detail_info-dedat
*         AND dezit = ps_detail_info-dezit
*         AND denam = ps_detail_info-denam.
  ENDCASE.

  IF pt_resb[] IS INITIAL.
    EXIT.
  ENDIF.

  PERFORM get_text_for_field TABLES pt_resb.

  SORT pt_resb BY aufnr posnr.

ENDFORM.                    " GET_DETAIL
*&---------------------------------------------------------------------*
*&      Form  GET_DETAIL_ZCRMS0093
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_LT_ZCRMS0093  text
*      -->P_LT_DATA  text
*      -->P_I_DETAIL_INFO  text
*      -->P_I_HISTORY  text
*----------------------------------------------------------------------*
FORM get_detail_zcrms0093  TABLES   pt_zcrms0093   STRUCTURE zcrms0093
                           USING    ps_detail_info TYPE zcrms0095
                                    p_history.

  CONSTANTS: c_f_posnr(11) VALUE 'qmseq'.

  DATA: lv_qmnum LIKE afih-qmnum.

  DATA: lv_where_posnr TYPE string,
        lv_where_matnr TYPE string.

  CLEAR: lv_qmnum, lv_where_posnr, lv_where_matnr.

  PERFORM get_where_clause USING ps_detail_info-posnr
                                 ps_detail_info-matnr
                                 c_f_posnr
                        CHANGING lv_where_posnr
                                 lv_where_matnr.

  SELECT SINGLE qmnum
    INTO lv_qmnum
    FROM qmel
   WHERE aufnr    = ps_detail_info-aufnr
     AND kzloesch = space.

*-- Select Data
* p_history = 'X"일 경우 삭제 삭제 이력 테이블에서 조회한다.
  CASE p_history.
    WHEN space.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_zcrms0093
        FROM zcst5040
       WHERE qmnum = lv_qmnum
         AND (lv_where_matnr)
         AND (lv_where_posnr)
         AND menge = ps_detail_info-bdmng
         AND lifnr = ps_detail_info-dealer_cd
         AND zsupply = '02'.
    WHEN 'X'.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_zcrms0093
        FROM zsst8074
       WHERE qmnum   = lv_qmnum
         AND (lv_where_matnr)
         AND lifnr   = ps_detail_info-dealer_cd.
*         AND dedat   = ps_detail_info-dedat
*         AND dezit   = ps_detail_info-dezit
*         AND denam   = ps_detail_info-denam.
  ENDCASE.

  IF pt_zcrms0093[] IS INITIAL.
    EXIT.
  ENDIF.

  PERFORM get_text_for_field TABLES pt_zcrms0093.

  SORT pt_zcrms0093 BY qmnum qmseq.

ENDFORM.                    " GET_DETAIL_ZCRMS0093
*&---------------------------------------------------------------------*
*&      Form  GET_DETAIL_ZCST0040
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_LT_ZCST0040  text
*      -->P_I_DETAIL_INFO  text
*      -->P_I_HISTORY  text
*----------------------------------------------------------------------*
FORM get_detail_zcst0040  TABLES   pt_zcst0040    STRUCTURE zcst0040
                           USING   ps_detail_info TYPE zcrms0095
                                   p_history.

  CONSTANTS: c_f_posnr(11) VALUE 'item_number'.

  DATA: lv_where_posnr TYPE string,
        lv_where_matnr TYPE string.

  CLEAR: lv_where_posnr, lv_where_matnr.

  PERFORM get_where_clause USING ps_detail_info-posnr
                                 ps_detail_info-matnr
                                 c_f_posnr
                        CHANGING lv_where_posnr
                                 lv_where_matnr.

* p_history = 'X"일 경우 삭제 삭제 이력 테이블에서 조회한다.
  CASE p_history.
    WHEN space.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_zcst0040
        FROM zcst0040
       WHERE aufnr = ps_detail_info-aufnr
         AND (lv_where_matnr)
         AND (lv_where_posnr)
         AND pgmng = ps_detail_info-bdmng
         AND item_cat = 'N'.
    WHEN 'X'.
      SELECT *
        INTO CORRESPONDING FIELDS OF TABLE pt_zcst0040
        FROM zsst8075
       WHERE aufnr   = ps_detail_info-aufnr
         AND (lv_where_matnr).
*         AND dedat   = ps_detail_info-dedat
*         AND dezit   = ps_detail_info-dezit
*         AND denam   = ps_detail_info-denam.
  ENDCASE.

  IF pt_zcst0040[] IS INITIAL.
    EXIT.
  ENDIF.

  PERFORM get_text_for_field TABLES pt_zcst0040.

  SORT pt_zcst0040 BY aufnr item_number.

ENDFORM.                    " GET_DETAIL_ZCST0040

 


FORM get_where_clause  USING    ps_detail_info-posnr TYPE resb-posnr
                                ps_detail_info-matnr TYPE resb-matnr
                                pv_f_posnr
                       CHANGING pv_where_posnr
                                pv_where_matnr.

  DATA: lv_posnr(18),
        lv_matnr(28).

  CLEAR: lv_posnr, lv_matnr.

"*** 값이 없으면 전체 조회, 있으면 입력 값만 조건 조회 
  IF ps_detail_info-posnr IS INITIAL.
    CONCATENATE pv_f_posnr 'LIKE ''%''' INTO pv_where_posnr
                                        SEPARATED BY space.
  ELSE.
    CALL FUNCTION 'CONVERSION_EXIT_NUMCV_INPUT'
      EXPORTING
        input  = ps_detail_info-posnr
      IMPORTING
        output = ps_detail_info-posnr.

    CONCATENATE '''' ps_detail_info-posnr '''' INTO lv_posnr
                                               SEPARATED BY space.
    CONDENSE lv_posnr NO-GAPS.
    CONCATENATE pv_f_posnr ' = ' lv_posnr INTO pv_where_posnr
                                          SEPARATED BY space.
  ENDIF.

  IF ps_detail_info-matnr IS INITIAL.
    pv_where_matnr = 'matnr LIKE ''%'''.
  ELSE.
    CONCATENATE '''' ps_detail_info-matnr '''' INTO lv_matnr
                                               SEPARATED BY space.
    CONDENSE lv_matnr NO-GAPS.
    CONCATENATE 'matnr = ' lv_matnr INTO pv_where_matnr
                                    SEPARATED BY space.
  ENDIF.

ENDFORM.                    " GET_WHERE_CLAUSE

 


 

[2] RTTI를 활용하여 필드 존재 여부 확인

🔍 설명

  1. RTTI를 사용하여 현재 구조의 필드 목록을 가져옴
    • cl_abap_structdescr=>describe_by_data(<fs_field>)을 사용하여 구조의 메타데이터를 조회.
    • components 테이블에 필드 목록이 저장됨.
  2. 필드 목록에서 해당 필드가 존재하는지 확인
    • READ TABLE lt_components INTO ls_component WITH KEY name = 'DEALER_CD'
    • sy-subrc = 0 이면 필드가 존재하는 것.
  3. 존재할 때만 ASSIGN COMPONENT 실행
    • 필드가 없으면 ASSIGN을 실행하지 않도록 제어.

FORM get_text_for_field  TABLES   pt_table.

  FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE,
                 <fs_field> TYPE ANY.

  FIELD-SYMBOLS: <lv_matnr>     TYPE matnr,
                 <lv_maktx>     TYPE maktx,
                 <lv_dealer_cd> TYPE zedealer_cd,
                 <name1>        TYPE name1_gp.

  DATA: lo_structdescr TYPE REF TO cl_abap_structdescr.
  DATA: BEGIN OF ls_component,
    length    TYPE i,
    decimals  TYPE i,
    type_kind TYPE abap_typekind,
    name      TYPE abap_compname,
  END OF ls_component,

  lt_components LIKE STANDARD TABLE OF ls_component WITH KEY name.

  DATA: lr_matnr TYPE RANGE OF matnr,
        ls_matnr LIKE LINE OF lr_matnr,
        lr_dealer_cd TYPE RANGE OF zedealer_cd,
        ls_dealer_cd LIKE LINE OF lr_dealer_cd.

  DATA: BEGIN OF ls_maktx,
    matnr TYPE makt-matnr,
    maktx TYPE makt-maktx,
    spras TYPE spras,
  END OF ls_maktx,

  lt_maktx LIKE TABLE OF ls_maktx.

  DATA: BEGIN OF ls_dealer_nm,
    name1 TYPE kna1-name1,
    kunnr TYPE kna1-kunnr,
  END OF ls_dealer_nm,

  lt_dealer_nm LIKE TABLE OF ls_dealer_nm.

  CLEAR: lo_structdescr, ls_component, ls_maktx, ls_matnr, ls_dealer_cd, ls_dealer_nm.
  REFRESH: lt_components, lt_maktx, lr_matnr, lr_dealer_cd, lt_dealer_nm.

  ASSIGN pt_table[] TO <fs_table>.

  LOOP AT <fs_table> ASSIGNING <fs_field>.
    lo_structdescr ?= cl_abap_typedescr=>describe_by_data( <fs_field> ).
    lt_components[] = lo_structdescr->components[].

    CLEAR ls_component.
    READ TABLE lt_components INTO ls_component WITH KEY name = 'MATNR'.
    IF sy-subrc = 0.
      ASSIGN COMPONENT 'MATNR' OF STRUCTURE <fs_field> TO <lv_matnr>.
      IF <lv_matnr> IS NOT INITIAL.
        _make_range_type2 ls_matnr lr_matnr <lv_matnr>.
      ENDIF.
    ENDIF.

    CLEAR ls_component.
    READ TABLE lt_components INTO ls_component WITH KEY name = 'LIFNR'.
    IF sy-subrc = 0.
      ASSIGN COMPONENT 'LIFNR' OF STRUCTURE <fs_field> TO <lv_dealer_cd>.
      IF <lv_dealer_cd> IS NOT INITIAL.
        _make_range_type2 ls_dealer_cd lr_dealer_cd <lv_dealer_cd>.
      ENDIF.
    ENDIF.
  ENDLOOP.

  "MAKTX
  SELECT DISTINCT matnr maktx spras
    INTO CORRESPONDING FIELDS OF TABLE lt_maktx
    FROM makt
   WHERE matnr IN lr_matnr
     AND spras = sy-langu
   ORDER BY matnr.

  IF lr_dealer_cd[] IS NOT INITIAL.
    SORT lr_dealer_cd BY low.
    DELETE ADJACENT DUPLICATES FROM lr_dealer_cd COMPARING ALL FIELDS.

    "DEALER_NM
    SELECT name1 kunnr
      INTO CORRESPONDING FIELDS OF TABLE lt_dealer_nm
      FROM kna1
     WHERE kunnr IN lr_dealer_cd
     ORDER BY kunnr.
  ENDIF.

  LOOP AT <fs_table> ASSIGNING <fs_field>.
    lo_structdescr ?= cl_abap_typedescr=>describe_by_data( <fs_field> ).
    lt_components[] = lo_structdescr->components[].

    CLEAR ls_component.
    READ TABLE lt_components INTO ls_component WITH KEY name = 'MATNR'.
    IF sy-subrc = 0.
      ASSIGN COMPONENT 'MATNR' OF STRUCTURE <fs_field> TO <lv_matnr>.
      IF <lv_matnr> IS NOT INITIAL.
        CLEAR ls_maktx.
        READ TABLE lt_maktx INTO ls_maktx WITH KEY matnr = <lv_matnr>
                                          BINARY SEARCH.
        IF sy-subrc = 0.
          ASSIGN COMPONENT 'MAKTX' OF STRUCTURE <fs_field> TO <lv_maktx>.
          <lv_maktx> = ls_maktx-maktx.
        ENDIF.
      ENDIF.
    ENDIF.

    CLEAR ls_component.
    READ TABLE lt_components INTO ls_component WITH KEY name = 'LIFNR'.
    IF sy-subrc = 0.
      ASSIGN COMPONENT 'LIFNR' OF STRUCTURE <fs_field> TO <lv_dealer_cd>.
      IF <lv_dealer_cd> IS NOT INITIAL.
        CLEAR ls_dealer_nm.
        READ TABLE lt_dealer_nm INTO ls_dealer_nm WITH KEY kunnr = <lv_dealer_cd>
                                                  BINARY SEARCH.
        IF sy-subrc = 0.
          ASSIGN COMPONENT 'NAME1' OF STRUCTURE <fs_field> TO <name1>.
          <name1> = ls_dealer_nm-name1.
        ENDIF.
      ENDIF.
    ENDIF.
  ENDLOOP.

ENDFORM.                    " GET_TEXT_FOR_FIELD

 

더보기