Пусть у нас имеется внутренняя таблица, размерность которой может составлять как десяток строк, так и сотни тысяч строк
1 2 3 4 5 6 7 8 9 10 |
DATA: BEGIN OF lt_tab OCCURS 0, bukrs LIKE t001-bukrs, " БЕ bukrs_txt LIKE t001-butxt, " Наименование БЕ werks LIKE t001w-werks, " Завод werks_txt LIKE t001w-name1, " Наименование завода matnr LIKE makt-matnr, " Материал matnr_txt LIKE makt-maktx, " Наименование материала dmbtr TYPE tslxx, " Сумма END OF lt_tab. |
Поля таблицы можно классифицировать на справочные и не справочные. К первой группе относятся: bukrs_txt, werks_txt, matnr_txt. Ко второй остальные. Для каждого справочного поля имеется соответствующий ключ, по которому можно однозначно определить значение справочного поля. Например, ключом поля bukrs_txt будет bukrs, т.к. для определения наименования БЕ необходимо знать код БЕ. Как правило, заполнение справочных полей значениям происходит в последнюю очередь.
Задача: заполнить справочные поля по соответствующим ключам, используя при этом минимальные ресурсные затраты.
Данная задача является типичной для MM и FI. Рассмотрим наиболее популярные способы ее решения.
Способ 1
Самый простой вариант — для каждой строке в цикле вызвать SELECT SINGLE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
FIELD-SYMBOLS: <wa> LIKE LINE OF lt_tab. LOOP AT lt_tab ASSIGNING . SELECT SINGLE butxt INTO <wa>-bukrs_txt FROM t001 WHERE bukrs EQ <wa>-bukrs. SELECT SINGLE name1 INTO <wa>-werks_txt FROM t001w WHERE werks EQ <wa>-werks. SELECT SINGLE maktx INTO <wa>-matnr_txt FROM makt WHERE matnr EQ <wa>-matnr AND spras EQ sy-langu. ENDLOOP. |
На практике данный вариант можно применить в двух случаях:
- Таблица небольшого размера
- Число уникальных ключей равно (или почти равно) числу строк таблицы
В противном случае создается излишняя нагрузка на базу данных, а время построения отчета может увеличиться в десятки раз.
Способ 2
Для каждого ключевого поля выбрать все уникальные значения, затем в базе данных выбрать все справочные значения по данным ключам, далее подставить их в исходную таблицу. Пример реализации для заполнения наименования БЕ.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
DATA: BEGIN OF ls_dict, bukrs LIKE t001-bukrs, " БЕ bukrs_txt LIKE t001-butxt, " Наименование БЕ END OF ls_dict, lt_dict LIKE HASHED TABLE OF ls_dict WITH UNIQUE KEY bukrs. FIELD-SYMBOLS: <wa_dict> LIKE LINE OF lt_dict. SELECT bukrs AS bukrs butxt AS bukrs_txt INTO TABLE lt_dict FROM t001 FOR ALL ENTRIES IN lt_tab WHERE bukrs EQ lt_tab-bukrs. LOOP AT lt_tab ASSIGNING <wa_tab>. READ TABLE lt_dict ASSIGNING <wa_dict> WITH TABLE KEY bukrs = <wa_tab>-bukrs. IF sy-subrc EQ 0. <wa_tab>-bukrs_txt = <wa_dict>-bukrs_txt. ENDIF. ENDLOOP. |
Данный метод хорош и многим программистам он предпочтителен. На habrahabr даже есть статья, описывающая технологию универсализизации данного метода. При использовании данного метода не забывайте проверять таблицу lt_tab на наличие по крайней мере одной записи, иначе программа будет перебирать все записи в БД. Если вы решите использовать универсальный метод по ссылке выше учите, что INSERT REPORT игрушка опасная и бдительный базис не пропустит ваш запрос в продуктив.
Способ 3
Аналогичный предыдущему, однако, отличающийся технологией сбора уникальных значений ключа. А именно, сначала формируется рендж уникальных значений, затем делается запрос в БД с передачей ренджа.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
DATA: BEGIN OF ls_dict, bukrs LIKE t001-bukrs, " БЕ bukrs_txt LIKE t001-butxt, " Наименование БЕ END OF ls_dict, lt_dict LIKE HASHED TABLE OF ls_dict WITH UNIQUE KEY bukrs. FIELD-SYMBOLS: <wa_dict> LIKE LINE OF lt_dict. RANGES: lr_bukrs FOR t001-bukrs. REFRESH lr_bukrs. LOOP AT lt_tab ASSIGNING <wa_tab>. lr_bukrs-sign = 'I'. lr_bukrs-option = 'EQ'. lr_bukrs-low = <wa_tab>-bukrs. COLLECT lr_bukrs. ENDLOOP. SELECT bukrs AS bukrs butxt AS bukrs_txt INTO TABLE lt_dict FROM t001 WHERE bukrs IN lr_bukrs. LOOP AT lt_tab ASSIGNING <wa_tab>. READ TABLE lt_dict ASSIGNING <wa_dict> WITH TABLE KEY bukrs = <wa_tab>-bukrs. IF sy-subrc EQ 0. <wa_tab>-bukrs_txt = <wa_dict>-bukrs_txt. ENDIF. ENDLOOP. |
Данный метод работает немного быстрее предыдущего. Быстрота обуславливается тем, что конструкция FOR ALL ENTRIES IN разбивает запрос на несколько запросов и данные выбираются не все сразу, а частями.
Однако, стоит учитывать, что если рендж уникальных значений будет содержать большое чисто строк (1000+), то вы получите дамп DBIF_RSQL_INVALID_RSQL из-за того, что размер SQL-запроса превысит допустимую границу. Также необходимо проверять что рендж не пустой.
Способ 4
Похож на предыдущие два, отличается тем, что справочник уникальных значений собираем по мере необходимости. На каждую новую запись делаем SELECT SINGLE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
DATA: BEGIN OF ls_dict, bukrs LIKE t001-bukrs, " БЕ bukrs_txt LIKE t001-butxt, " Наименование БЕ END OF ls_dict, lt_dict LIKE HASHED TABLE OF ls_dict WITH UNIQUE KEY bukrs. FIELD-SYMBOLS: <wa_dict> LIKE LINE OF lt_dict. LOOP AT lt_tab ASSIGNING <wa_tab>. READ TABLE lt_dict ASSIGNING <wa_dict> WITH TABLE KEY bukrs = <wa_tab>-bukrs. IF sy-subrc EQ 0. <wa_tab>-bukrs_txt = <wa_dict>-bukrs_txt. ELSE. ls_dict-bukrs = <wa_tab>-bukrs. SELECT SINGLE butxt INTO ls_dict-bukrs_txt FROM t001 WHERE bukrs EQ ls_dict-bukrs. IF sy-subrc NE 0. CLEAR ls_dict-bukrs_txt. ENDIF. INSERT ls_dict INTO TABLE lt_dict. <wa_tab>-bukrs_txt = ls_dict-bukrs_txt. ENDIF. ENDLOOP. |
Быстродействие данного метода сравнимо с предыдущими двумя.
Что использовать на практике?
На практике я использую обертку над последним методом. По скорости, гибкости и универсальности он является самым оптимальным. А справочные данные позволяет брать не только из базы данный, но и на основе локальных переменных программы.
Пример универсальной процедуры.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
*&---------------------------------------------------------------------* *& Form fill_field *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * -->TABLE Таблица * -->PROG Программа, содержащая сопоставляющую процедуру * -->KEY Ключевое поле * -->VAL Справочное поля * -->PROC Процедура, сопоставляющая ключ со значением *----------------------------------------------------------------------* FORM fill_field TABLES table USING prog key val proc. TYPES: BEGIN OF dictionary, key(20), val(50), END OF dictionary. " для генерации структуры dictionary можно использовать CREATE DATA DATA: ls_dict TYPE dictionary, lt_dict TYPE HASHED TABLE OF dictionary WITH UNIQUE KEY key. FIELD-SYMBOLS: <lv_key> TYPE ANY, <lv_val> TYPE ANY, <ls_row> TYPE ANY, <ls_dct> TYPE dictionary. REFRESH lt_dict. LOOP AT table ASSIGNING <ls_row>. ASSIGN COMPONENT key OF STRUCTURE <ls_row> TO <lv_key>. ASSIGN COMPONENT val OF STRUCTURE <ls_row> TO <lv_val>. READ TABLE lt_dict WITH TABLE KEY key = <lv_key> ASSIGNING <ls_dct>. IF sy-subrc EQ 0. <lv_val> = <ls_dct>-val. ELSE. PERFORM (proc) IN PROGRAM (prog) USING <lv_key> CHANGING <lv_val>. ls_dict-key = <lv_key>. ls_dict-val = <lv_val>. INSERT ls_dict INTO TABLE lt_dict. ENDIF. ENDLOOP. FREE lt_dict. ENDFORM. "fill_field |
И пример использования
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
PERFORM fill_field TABLES lt_tab USING sy-cprog: 'BUKRS' 'BUKRS_TXT' 'GET_BUKRS_TXT', 'WERKS' 'WERKS_TXT' 'GET_WERKS_TXT', 'MATNR' 'MATNR_TXT' 'GET_MATNR_TXT'. ... *&---------------------------------------------------------------------* *& Form get_bukrs_txt *&---------------------------------------------------------------------* FORM get_bukrs_txt USING key CHANGING val. SELECT SINGLE butxt INTO val FROM t001 WHERE bukrs EQ key. ENDFORM. "get_bukrs_txt *&---------------------------------------------------------------------* *& Form get_werks_txt *&---------------------------------------------------------------------* FORM get_werks_txt USING key CHANGING val. SELECT SINGLE name1 INTO val FROM t001w WHERE werks EQ key. ENDFORM. "get_werks_txt *&---------------------------------------------------------------------* *& Form get_matnr_txt *&---------------------------------------------------------------------* FORM get_matnr_txt USING key CHANGING val. SELECT SINGLE maktx INTO val FROM makt WHERE matnr EQ key AND spras EQ sy-langu. ENDFORM. "get_matnr_txt |
Присоединиться к обсуждению...