Структури
Структура (structure) — складний обʼєкт даних, що групує кілька компонентів різних типів під одним іменем. Типовий приклад — адреса: name, street, city належать разом. Структура — базова цегла для роботи з табличними даними: рядок бази даних, рядок внутрішньої таблиці, work area у SELECT — всюди структури.
Складність структури зростає від flat (тільки елементарні компоненти) до nested (є підструктури) до deep (містить внутрішні таблиці, strings або references). Від цієї класифікації залежить, як поводяться присвоєння, порівняння і робота з базою даних.
Оголошення
Section titled “Оголошення”Локально — через BEGIN OF ... END OF з TYPES (для типу) або DATA (для обʼєкта):
" Оголошення типуTYPES: BEGIN OF t_addr, name TYPE string, street TYPE string, city TYPE string, END OF t_addr.
" Обʼєкт на основі типуDATA addr TYPE t_addr.
" Обʼєкт з одночасним заданням полів і початкових значеньDATA: BEGIN OF person, name TYPE string VALUE `John`, age TYPE i VALUE 30, END OF person.Компоненти можуть бути будь-якого типу — елементарні, структурні, внутрішні таблиці, data references:
TYPES: BEGIN OF t_order, id TYPE i, customer TYPE t_addr, " вкладена структура items TYPE TABLE OF t_item WITH EMPTY KEY, " внутрішня таблиця ref TYPE REF TO data, " reference END OF t_order.Глобальні структурні типи
Section titled “Глобальні структурні типи”DDIC дає готові типи — database tables, DDIC structures, CDS view entities. Всі використовуються однаково:
DATA fli TYPE zdemo_abap_fli. " database table як типDATA fli_ve TYPE zdemo_abap_fli_ve. " CDS view entityDATA struc TYPE cl_some_class=>ty_struc. " структура з public-секції класуInline-оголошення
Section titled “Inline-оголошення”Найкоротший шлях — вивести тип з контексту:
DATA(addr1) = VALUE t_addr( name = `John` city = `Kyiv` ).SELECT SINGLE * FROM zdemo_abap_fli INTO @DATA(fli).LOOP AT itab INTO DATA(wa). ENDLOOP.FINAL(...) створює immutable-структуру — після присвоєння компоненти не змінюються:
LOOP AT itab INTO FINAL(wa). " wa доступна для читання, wa-comp = value заблокованоENDLOOP.Варіанти структур
Section titled “Варіанти структур”Flat — тільки фіксованої довжини елементарні типи. Nested structure теж flat, поки жоден компонент не є deep:
DATA: BEGIN OF flat_s, num TYPE i, code TYPE c LENGTH 5, pr TYPE p LENGTH 8 DECIMALS 2, END OF flat_s.Nested — один або більше компонентів — самі структури:
DATA: BEGIN OF addr_n, BEGIN OF name, prename TYPE string, surname TYPE string, END OF name, BEGIN OF city, zip TYPE string, name TYPE string, END OF city, END OF addr_n.
" Доступ: addr_n-name-prename, addr_n-city-zipDeep — містить внутрішню таблицю, string, xstring або reference. Увага: навіть одна string-компонента робить структуру deep:
DATA: BEGIN OF addr_d, name TYPE string, " <-- string робить структуру deep city TYPE string, END OF addr_d.Доступ до компонентів
Section titled “Доступ до компонентів”Через selector -:
addr-name = `John`.DATA(city) = addr-city.IF addr IS INITIAL. ENDIF.
" Nestedaddr_n-name-prename = `John`.
" Через data reference — оператор ->dref->name = `John`. " звичайний синтаксисdref->*-name = `John`. " повний: спершу розіменувати, потім компонентДинамічний доступ через ASSIGN
Section titled “Динамічний доступ через ASSIGN”Компонент може бути вказаний рядком або номером — корисно для generic-обробки:
DATA(comp_name) = `CITY`.
ASSIGN addr-(comp_name) TO FIELD-SYMBOL(<c>). " за іменем (змінною або літералом)ASSIGN addr-('NAME') TO <c>. " за іменем-літераломASSIGN addr-(2) TO <c>. " за номеромASSIGN addr-(0) TO <c>. " 0 = вся структура
IF sy-subrc <> 0. " компонент не існуєENDIF.
" Ітерація по всіх компонентахDO. ASSIGN addr-(sy-index) TO <c>. IF sy-subrc <> 0. EXIT. ENDIF. " <c> — черговий компонентENDDO.Наповнення
Section titled “Наповнення”Оператор присвоєння
Section titled “Оператор присвоєння”Для сумісних типів — пряме копіювання:
addr = another_addr.DATA(copy) = addr. " inline з тим самим типомVALUE-оператор
Section titled “VALUE-оператор”Основний спосіб побудувати структуру значень:
addr = VALUE #( name = `John` street = `Main 1` city = `Kyiv` ).
" З inline-оголошенням і явним типомDATA(a) = VALUE t_addr( name = `John` city = `Kyiv` ).
" BASE — зберегти наявні значення, перезаписати вказаніaddr = VALUE #( BASE addr street = `New Street` ).
" Без BASE — вказані поля присвоєні, решта initial (поточний вміст втрачається!)addr = VALUE #( street = `Only Street` ).Для nested-структур — вкладені VALUE:
addr_n = VALUE #( name = VALUE #( prename = `John` surname = `Pea` ) city = VALUE #( zip = `12345` name = `Kyiv` ) ).CORRESPONDING і MOVE-CORRESPONDING
Section titled “CORRESPONDING і MOVE-CORRESPONDING”Коли структури різних типів, але з однаково названими компонентами — CORRESPONDING копіює за іменами:
" Initialize + copy matching componentstarget = CORRESPONDING #( source ).
" BASE — зберегти наявний вміст target, перезаписати однойменніtarget = CORRESPONDING #( BASE ( target ) source ).
" MAPPING — явне мапування імен (коли поля називаються по-різному)target = CORRESPONDING #( source MAPPING new_name = old_name ).
" EXCEPT — виключити компоненти зі зіставленняtarget = CORRESPONDING #( source EXCEPT some_field ).MOVE-CORRESPONDING — statement-еквівалент без ініціалізації цілі (тотожній CORRESPONDING ... BASE):
MOVE-CORRESPONDING source TO target.Для deep-структур є додаткові модифікатори (EXPANDING NESTED TABLES, KEEPING TARGET LINES, DEEP, APPENDING BASE) — керують обробкою внутрішніх таблиць-компонентів. Деталі — в оригіналі.
Очищення
Section titled “Очищення”CLEAR addr. " всі компоненти у initialCLEAR addr-name. " один компонентFREE addr. " CLEAR + звільнити памʼять deep-компонентівaddr = VALUE #( ). " еквівалент CLEAR через VALUEСтруктури і ABAP SQL
Section titled “Структури і ABAP SQL”" SELECT SINGLE — один рядок у flat-структуруSELECT SINGLE * FROM zdemo_abap_fli WHERE carrid = 'LH' INTO @DATA(fli).
" INTO CORRESPONDING FIELDS — коли типи несумісніSELECT SINGLE * FROM zdemo_abap_fli WHERE carrid = 'AA' INTO CORRESPONDING FIELDS OF @my_struc.
" INSERT / UPDATE / MODIFY / DELETE зі структуриINSERT INTO dbtab VALUES @struc.INSERT dbtab FROM @struc.UPDATE dbtab FROM @struc.MODIFY dbtab FROM @struc. " INSERT або UPDATE залежно від ключаDELETE dbtab FROM @struc.
" Inline конструктор — без наперед оголошеної структуриINSERT dbtab FROM @( VALUE #( comp1 = ... comp2 = ... ) ).INCLUDE TYPE і INCLUDE STRUCTURE
Section titled “INCLUDE TYPE і INCLUDE STRUCTURE”Дозволяють “склеїти” компоненти з іншої структури без створення підструктури:
TYPES: BEGIN OF name_t, prename TYPE string, surname TYPE string, END OF name_t, BEGIN OF addr_t, street TYPE string, city TYPE string, END OF addr_t.
TYPES BEGIN OF person_t. INCLUDE TYPE name_t. INCLUDE TYPE addr_t AS location RENAMING WITH SUFFIX _loc.TYPES END OF person_t.
" person_t містить: prename, surname, street_loc, city_loc" street_loc і city_loc доступні також як person-location-street_loc при ASINCLUDE TYPE— включає тип (результатTYPES).INCLUDE STRUCTURE— включає реально існуючий обʼєкт (рідко потрібно).AS name— дає доступ як до “віртуальної” підструктури.RENAMING WITH SUFFIX _x— додає суфікс до імен компонентів, щоб уникнути колізій.
Корисно для DDIC-структур, де кілька глобальних структур мають спільні секції (напр., адреса, аудит-поля) — включаєш замість копіювання.
Excursions
Section titled “Excursions”Структура sy
Section titled “Структура sy”Вбудована системна структура, заповнюється runtime-ом. Найчастіше вживані компоненти:
sy-subrc— return code після багатьох операторів (0 = ОК).sy-tabix— номер рядка внутрішньої таблиці (післяREAD TABLE,LOOP AT).sy-index— номер ітерації уDO/WHILE.sy-datum/sy-uzeit— поточна дата/час.sy-mandt/sy-langu— мандант і мова сесії.
У ABAP Cloud більшість інших компонентів заборонена — посилаються на legacy-контексти (dynpro, список).
RTTI для структур
Section titled “RTTI для структур”Отримати метадані типу у runtime:
DATA(td) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( struc ) ).
LOOP AT td->components INTO DATA(comp). out->write( |{ comp-name } : { comp-type_kind }| ).ENDLOOP.Boxed components
Section titled “Boxed components”Компонент структури, що сам є структурою, можна оголосити BOXED — ABAP тримає його по reference, економлячи памʼять у випадках, коли такий компонент часто пустий:
TYPES: BEGIN OF t, id TYPE i, details TYPE big_struc BOXED, END OF t.Семантика доступу не змінюється — struc-details-field працює як звичайно. Особливість — памʼять виділяється лише коли компонент заповнений.
Адаптовано з 02_Structures.md (Apache 2.0). Повний перелік нюансів — в оригіналі.