Как стать автором
Обновить

Использование временных таблиц (GTT) в ABAP-разработках

Уровень сложностиСредний
Время на прочтение5 мин
Количество просмотров695

GTT – global temporary tables, таблицы которые наполняются и очищаются в рамках ABAP-сессии (application session), но находятся при этом на уровне БД (то есть данные не передаются между Database и Application).

В ABAP-разработке их можно перевести как глобально сессионные таблицы или словарно-сессионные таблицы. Появляются Global Temporary Tables (GTT) с версии ABAP 7.50.

Что такое temporary tables?

В базах данных Temporary table – это объект на уровне базы данных, куда могут быть помещены данные после выборки из таблиц БД; при этом данные существуют в рамках сессии приложения и не передаются из базы на application, а остаются в базе. Это дает возможность применять SQL-операторы к «промежуточным» данным для вычислений и не делать дополнительные roundtrip между application и базой. В терминах ABAP-разработки temporary table можно рассматривать как альтернативу «промежуточным» внутренним таблицам или операторам UNION.

Temporary tables реализованы в различных базах: PostgreSQL, ORACLE, HANA ; также поддерживаются в 1С (ссылка здесь и здесь). Назначение их, по сути, одно и то же: в течение сессии сложить данные в таблицу, а по итогу сессии забрать данные и очистить таблицу.

GTT в ABAP представляет собой отдельную прозрачную таблицу, в которую складываются данные в рамках DB LUW и могут быть считаны только в рамках текущей сессии. На начало сессии и на завершение таблица должна быть пустая (очищена принудительной командой через ABAP, если нужно). Цель GTT – это дать возможность разделить сложную выборку на несколько шагов. За счет того, что данные хранятся в рамках одной сессии, то «закулисное администрирование» такой таблицы немного меньше. Можно сказать, что временная таблица работает почти как внутренняя таблица, но остаётся на стороне базы данных.

Демонстрационный пример в ABAP

Как правило, temporary table полезна, когда нужно получить данные из источников, которые имеют разное смысловое назначение, но сводятся к одной и той же структуре данных.

Пример: нужно получить список (MATNR) материалов, которые указаны в заказах на дату DATE1 и указаны в фактурах на дату фактурирования DATE1.

В SAP ERP (и как правило, в других системах тоже) заказы и фактуры находятся в разных таблицах, а также заголовок и позиция этих сущностей также находятся в разных таблицах (и даже не в одной 😊 ). В SAP ERP для заказов используются таблицы: VBAK, VBAP и др.,  а для фактур таблицы: VBRK, VBRP и др.. Однако для целей демонстрации (на стандарте экспериментировать не хорошо), я сделаю упрощённые аналогичные таблицы со структурой (рис.1 и табл.1).

Рис. 1 Упрощенная структура модели заказов и фактур для целей демо
Рис. 1 Упрощенная структура модели заказов и фактур для целей демо

Таблица

Поле

Комментарий

ZTC8A016_ORDH

(заголовок заказа, демо)

VBELN

Номер заказа, первичный ключ

KUNNR

Номер (id) партнера-заказчика

ORDER_DATE

Дата заказа

CRDT

Дата создания заказа

 

ZTC8A016_ORDI

 

(позиции заказа, демо)

VBELN

Номер заказа, являются частью первичного ключа,

связано внешним ключом с
ZTC8A016_ORDH.VBELN

POSNR

Номер позиции заказа, являются частью первичного ключа

MATNR

Номер материала (MATNR)

 

ZTC8A016_INVH

 

(заголовок фактуры, демо)

INV_NUM

Номер фактуры, первичный ключ

PAYER

Номер (id) партнера-плательщика

INVOICE_DATE

Дата фактуры

CRDT

Дата создания фактуры

 

ZTC8A016_INVI

 

(позиции фактуры, демо)

INV_NUM

Номер фактуры, является частью первичного ключа. Связано внешним ключом с ZTC8A016_INVH

. INV_NUM

INV_POSNR

Номер позиции фактуры, является частью первичного ключа.

MATNR

Номер материала

Данная структура является сильным упрощением реальной структуры (например, нет цен и других важнейших атрибутов сущностей), но для целей демонстрации GTT – пусть будет так. Главное, что хотелось подчеркнуть, что данные находятся в разных источниках: группа таблиц заказов и группа таблиц фактур. Наполним таблицы с помощью утилиты.

А теперь укажем, как может быть решена данная задача различными способами.

Способ1. Считываем данные из каждой таблицы (точнее join) и объединяем на стороне application server (этот способ классический и держится уже много десятилетий, поэтому не буду его приводить).

Способ2. Делаем UNION из двух JOIN и возвращаем результат. Одна из возможных реализаций этого способа приведена здесь.

Способ3. Создаём GT-таблицу. Извлекаем данные в неё из JOIN по заказам, при этом не возвращая ничего на application server; затем извлекаем данные из JOIN по фактурам, также ничего не возвращая. А третьим шагом – считываем данные из временной таблицы и очищаем её. Реализация доступна по ссылке.

Создание Global Temporary Table в SAP NetWeaver (GTT в ABAP)

Давайте рассмотрим по шагам, как создать Global Temporary Table в ABAP, и как использовать.

В ABAP-справке содержится описание GTT  и пример содержится в программе (DEMO_GTT).

Создадим для нашего примера GTT через SE11; таблица создаётся как прозрачная таблица, но с указанием признака GTT (global temporary table).

Рис. 2 Указываем называние и Delivery Class L
Рис. 2 Указываем называние и Delivery Class L

Затем, как и в прозрачной таблице, указываем структуру таблицы.

Рис. 3 Структура таблицы для примера
Рис. 3 Структура таблицы для примера

Таблица 2 Структура GTT (Global Temporary Table) для демонстрации

Поле

Тип

Комментарий

MANDT

MANDT

 

SRC_TYPE

CHAR1

Ключевое поле,

Содержит либо O – order, либо I – Invoice

MATNR

MATNR

Материал

 Затем переходим по меню

Extras -> Change/Display Table Category

Рис. 4 Путь для указания, что таблица является Global Temporary Table (GTT)
Рис. 4 Путь для указания, что таблица является Global Temporary Table (GTT)
Рис. 5 Выбираем опцию Global Temporary Table
Рис. 5 Выбираем опцию Global Temporary Table

Технические параметры (тип таблицы, размер, буферизация, и т.д.) не ведутся для GTT.

Затем активируем таблицу и на этом создание GTT в словаре выполнено. Ограничения описаны в справке.

Использование и чтение данных из GTT в ABAP

Полная реализация этого способа тут.

GTT позволяет нам разделить чтение на части; поэтому мы можем использовать 2 метода по чтению, а именно: _fill_gtt_from_order и _fill_gtt_from_invoice. Таким образом, нам «удобнее» понимать, из каких шагов состит общая выборка. А также мы можем обращать внимание на переменную SY-DBCNT и, тем самым знать, сколько записей на каждом шаге было выбрано. Обращаю внимание, что мы не извлекаем данные во внутреннюю таблицу, а делаем INSERT во временную (в данном случае ZTC8A016_MAT_TMP, которую создали в предыдущем пункте).

  METHOD _fill_gtt_from_order.
    INSERT ztc8a016_mat_tmp FROM
     (
     SELECT DISTINCT
      'O' AS src_type,
       ordi~matnr AS matnr
        FROM ztc8a016_ordi AS ordi
        JOIN ztc8a016_ordh AS ordh ON ordi~vbeln EQ ordh~vbeln
      WHERE ordh~order_date EQ @mv_trg_date
     ).
  ENDMETHOD.

  METHOD _fill_gtt_from_invoice.
    INSERT ztc8a016_mat_tmp FROM
     (
        SELECT DISTINCT
          'I' AS src_type,
          invi~matnr AS matnr
        FROM ztc8a016_invi AS invi
        JOIN ztc8a016_invh AS invh ON invi~inv_num EQ invh~inv_num
      WHERE invh~invoice_date EQ @mv_trg_date
     ).
  ENDMETHOD.

Если там потребуется прочитать данные еще и из другого документа (например, поставок или закупочных документов), то существующие SELECT править уже не понадобиться, а нужно будет добавить метод, который заполняем temporary table. Таким образом, общая логика становится более наглядной и гибкой.

После того, как заполнение таблицы завершено, извлекаем нужные данные из временной таблицы. При этом мы можем применять «почти» любые ABAP SQL-операторы к этой таблице, включая агрегированные функции, JOIN, наложение условий через WHERE/HAVING и т.д. Однако, после того, как какие-либо данные добавлены в GTT не допускаются COMMIT (в том числе неявные / implicit).

    _fill_gtt_from_order( ).

    _fill_gtt_from_invoice( ).

    """"""""" read
    " допускается "почти" любой AbapSQL
    SELECT DISTINCT matnr
        FROM ztc8a016_mat_tmp
      ORDER BY matnr DESCENDING
      INTO TABLE @et_matnr_list
      UP TO 3 ROWS.

    IF mv_mode EQ '3'.
      " из-за неудаленных данных - будетм RunTime Error (aka красный Dump)
      " неявный коммит
      MESSAGE i000(cl) WITH 'Runtime Error goes here'.
    ENDIF.

    """"""""" delete - MUST EXIST
    DELETE FROM ztc8a016_mat_tmp.

    MESSAGE i000(cl) WITH 'Почистили GTT в сессии'.

Полный пример доступен по ссылке на github.

Подробнее GTT описаны в справке.

Заключение

Основными преимуществами GTT (как в ABAP (SAP NetWeaver), так и в других базах) являются:

  1. Возможность не передавать (не делать лишние database roundtrip) данные между базой и application (для данных более 50000 записей, это может иметь значение).

  2. Разделить логику сбора данных на несколько шагов, что повысит удобочитаемость, а также расширяемость без риска «сломать существующее».

  3. За счет «временности» накладные расходы на такую таблицу меньше, чем на обычную и работа с ней осуществляется немного быстрее.

На всякий случай обращу внимание, что GTT эффективно применимы не во всех возможных случаях, но эту возможность полезно знать.

Теги:
Хабы:
+4
Комментарии3

Публикации

Истории

Работа

ABAP разработчик
6 вакансий

Ближайшие события