Группировка в цикле ABAP - GROUP BY

В версии 7.40 в ABAP появилась возможность группировать значения в цикле и обрабатывать эти группы необходимым образом.

В данной статье на примере простой задачи по суммированию значений и выделению промежуточных итогов мы разберём использование дополнения GROUP BY в цикле. Это дополнение не только уменьшает количество строк кода для реализации задач, но и улучшает производительность.

Задача заглючается в том, чтобы сгруппировать имеющуюся таблицу и получить итоги в нескольких разрезах:

  • - По Сбытовым организациям и Заводам

  • - По материалам

  • - И у нас так же было требование выводить и подробные записи без группировки, поэтому нельзя было организовать группировку раньше, например на уровне БД.

Рассмотрим пример:

DATA(ls_data) - динамически определяем структуру. Задаём поля, по которым мы хотим сгруппировать записи таблицы vkorg и werks. group_ref_werks - Динамически определяем переменную в которую по очереди будут помещаться группы записей с одинаковыми значениями ключей vkorg и werks.

	
		    LOOP AT lt_data INTO DATA(ls_data) 
      			GROUP BY ( vkorg = ls_data-vkorg werks = ls_data-werks ) 
      			REFERENCE INTO DATA(group_ref_werks). 
				CLEAR ls_grp_werks.
									

Используя конструкцию LOOP AT GROUP мы теперь бежим уже по выделенной группе записей group_ref_werks с одинаковыми значениями vkorg и werks. На этом шаге мы могли бы уже обработать данные и не группировать, но нам нужна дополнительная группировка ещё и по материалу. И теперь мы помещаем в эту переменную уже группу с одинаковыми значениями не только vkorg и werks но и одинаковыми значениями matnr.

	
				LOOP AT GROUP group_ref_werks INTO DATA(ls_werks)
        			GROUP BY ( matnr = ls_werks-matnr ) 
        			REFERENCE INTO DATA(group_ref). 
									

На этом же шаге мы уже обрабатываем группу полученную выше и суммируем значения всех записей находящихся в ней

	
					LOOP AT GROUP group_ref REFERENCE INTO DATA(lr_tab).
					" Если это первая запись, из группы, то просто коппируем значения
					  IF ls_grp_matnr IS INITIAL.
						MOVE-CORRESPONDING lr_tab->* TO ls_grp_matnr.
					  ELSE. " Иначе суммируем значение к текущему
						ls_grp_matnr-menge      = ls_grp_matnr-menge + lr_tab->menge.
					  ENDIF.
					ENDLOOP.
									

Выйдя из этого цикла мы обработали всю первую группу с одинаковым набором vkorg и werks и matnr. После этого мы можем произвести расчёт зависимых от суммированых полей.

	
					ls_grp_matnr-menge_free = ls_grp_matnr-menge_to - ls_grp_matnr-menge_r.
					CLEAR ls_val.
									

После чего мы сохраняем полученную запись суммы в таблицу для дальнейшего использование. Далее мы суммируем значения уже для внешенего цикла который проходит по уникальным значениям только vkorg и werks.

	
					MOVE-CORRESPONDING ls_grp_matnr TO ls_val.
					ls_grp_class-menge      = ls_grp_class-menge + ls_grp_matnr-menge.
				ENDLOOP.
									

После выхода из цикла мы так же обрабатываем необходимым образом поля сумм по vkorg и werks. И сохраняем данные по этому проходу цикла в итоговую таблицу.

	
				 CLEAR ls_val.
				 MOVE-CORRESPONDING ls_grp_class TO ls_val.
				 APPEND ls_val TO lt_result.
    		ENDLOOP.