Welcome file

Struktura i tabela wewnętrzna w SAP ABAP

Artykuł omawia podstawy pracy ze strukturami i tabelami wewnętrznymi w SAP ABAP.

Przydatne linki:

*Ta sama dokumentacja jest też dostępna z systemu SAP przez transakcję ABAPDOCU lub z poziomu Eclipse/ADT (F1 na słowie kluczowym otwiera odpowiedni fragment Help Portal).

Artykuły o naming conventions:

  • ABAP Naming Conventions & Self-Explanatory Code Guide - rozpisane przykłady prefiksów (lv_, ls_, lt_), nazwy klas, interfejsów, testów.​

  • Blog „ABAP Code Naming Conventions” - praktyczne propozycje standardu do zastosowania w projekcie (prefiksy, długości, styl camel_case vs. underscores).

  • Dyskusja „Best practices in internal table naming convention (GT, GS, LT, LS)” na SAP Community: Best practices in Internal table naming convention… - SAP Community

Spis treści

  1. Tworzenie typu (wewnętrznego).
  2. Tworzenie struktury.
  3. Tworzenie tabeli wewnętrznej.

TYPY

Typ - opis „jakiego rodzaju” dane mogą być przechowywane w zmiennej albo obiekcie - np. liczba całkowita, tekst, data, struktura czy tabela wewnętrzna.

Typ sam w sobie nie zajmuje pamięci - to tylko definicja, bowiem pamięć zajmuje dopiero zmienna (data object) zadeklarowana z użyciem tego typu.​

Typy dzielą się m.in. na:

  • elementarne (np. I, P, C, D, T),
  • złożone, czyli struktury i tabele wewnętrzne,
  • referencyjne, które przechowują odwołania do obiektów.
  1. Warto tutaj doprecyzować, że wyróżniamy 2 główne typy danych w języku ABAP:

Typy tzw. ABAP‑owe (wbudowane)

  • To typy takie jak I, F, P, D, T, C, N, STRING, X, XSTRING itd.
  • Używamy ich bezpośrednio w kodzie, np. DATA lv_num TYPE i.
  • Są zdefiniowane w samym języku ABAP.

Typy słownikowe (DDIC)

  • To typy z ABAP Dictionary: CHAR10, NUMC8, CURR, QUAN, domeny, data elements, struktury, typy tabel itp.
  • Występują zarówno w kodzie, jak i w tabelach bazy danych, widokach, interfejsach.
  • Przykład: DATA lv_pernr TYPE pernr_d. - tu pernr_d jest typem słownikowym opartym na NUMC.

Jak o typach myśleć w praktyce?

  • Typ ABAP - prosty "klocek" techniczny, używany głównie wewnątrz logiki (zmienne pomocnicze, liczniki, tymczasowe teksty).

  • Typ DDIC - „biznesowy” typ, powiązany z modelem danych systemu (numery pracowników, kwoty, ilości, kody walut). Dobre praktyki mówią:
    tam, gdzie dane są związane z bazą/systemem, używaj typów DDIC, żeby
    wszystko było spójne.

!!! W projektach produkcyjnych preferuje się typy z DDIC, bo zapewniają spójność z tabelami bazy danych i walidacjami.

  • Zadanie projektowe
    Tworzę tabelę ewidencji czasu pracy, która będzie zbudowana z kolumn: id pracownika, okres (przepracowany miesiąc), liczba przepracowanych godzin.
  1. Utworzenie nowego programu ABAP w Eclipse:

  1. Zaczynam pisać kod:

TYPES: BEGIN OF ty_emp_worktime

  • TYPES -> mówi kompilatorowi: „za chwilę zdefiniuję nowy typ danych”.
  • BEGIN OF -> zaczyna definicję typu strukturalnego (rekord z kilkoma polami). Definicja typu strukturalnego na początku porządkuje dane i umożliwia wielokrotne ich użycie w programie. Typ struktury jest jak „szablon rekordu” tzn. raz opisujesz pola (np. pracownik, data, godziny), potem możesz tworzyć wiele zmiennych lub tabel wewnętrznych dokładnie tego kształtu.
  • ty_emp_worktime -> to nazwa typu - tutaj: „typ rekordu czasu pracy pracownika”. Klucz jest taki, żeby po ty_ użyć krótkiego, angielskiego opisu tego, co reprezentuje jeden wiersz (rekord) tabeli - wtedy kod jest od razu zrozumiały.

employee_id TYPE char10,
work_date TYPE d,
hours_work TYPE i,
END OF ty_emp_worktime.
  • employee_id –> kolumna z identyfikatorem pracownika.​
  • work_date –> kolumna z datą pracy.​
  • hours_work –> kolumna z liczbą przepracowanych godzin

Co to jest CHAR10?

CHAR10 oznacza po prostu łańcuch znaków o stałej długości 20 znaków - typ „character” z długością 20.
​

Co to jest CHAR?

Bazowy typ to CHAR (character string), a liczba po nim to długość, więc CHAR20 = TYPE c LENGTH 20.
​
Pola tego typu zawsze mają dokładnie 20 znaków, jeśli wpiszemy krótszą wartość, wówczas reszta zostanie wypełniana spacjami.​

Inne często używane typy

Kilka podstawowych wbudowanych typów w ABAP:

  • CHARn - tekst o stałej długości, np. CHAR10, CHAR50.​
  • NUMCn - ciąg cyfrowych znaków o długości n, np. numery dokumentów z zerami wiodącymi.​
  • I - liczba całkowita (integer).​
  • P - liczba zapakowana (packed), używana m.in. dla kwot z miejscami po przecinku.
  • D - data, T - czas.​

W słowniku danych (ABAP Dictionary) są też bardziej „biznesowe” typy zbudowane na tych bazowych, np. ACCP (okres księgowy), CURR (kwota), QUAN (ilość).
​

Gdzie to jest opisane?

Oficjalnie wszystkie wbudowane typy ABAP są opisane w dokumentacji SAP w sekcji Predefined ABAP Types oraz Data Types.
Z kolei typy słownikowe (Dictionary), takie jak CHAR, NUMC, CURR, są zebrane w rozdziale Predefined Data Types in ABAP Dictionary – tam znajdziesz tabelę z listą typów, maksymalnymi długością.

Podstawowe typy tekstowe w ABAP dla stringów

  • c / CHARn – tekst o stałej długości (np. c LENGTH 10, CHAR10), nadaje się na kody, ID, krótkie pola opisowe.​
  • n / NUMCn – „tekst cyfrowy”, tylko cyfry, też o stałej długości (np. numery z zerami wiodącymi).​
  • string – tekst o zmiennej długości (dynamiczny), dobry na dłuższe opisy, komunikaty, JSON itp.​
  • sstring / STRING (w DDIC) - typy słownikowe odpowiadające krótkim/długim tekstom zmiennej długości.​

Wszystkie te typy przechowują ciągi znaków, różnią się głównie
długością (stała vs. dynamiczna) i ograniczeniami (np. tylko cyfry w
NUMC).

Tak wygląda nasz kod dla utworzenia opisu - są to tak naprawdę dopiero ramy dla naszej tabeli:

Konstrukcja BEGIN OF … / END OF …**

Zapis END OF ty_emp_worktime. zamyka definicję tego konkretnego typu struktury i jest wymagany przez składnię ABAP.​

Po co powtarza się nazwę typu?
Konstrukcja BEGIN OF … / END OF … działa jak nawiasy: mówisz kompilatorowi, że wszystkie pola między nimi należą do jednego typu struktury.​
Nazwa po END OF (ty_emp_worktime) mówi dokładnie, którą strukturę kończysz - dzięki temu można w jednym module definiować kilka typów strukturalnych jeden po drugim i kompilator się nie gubi.​

BUDOWA STRUKTURY

Teraz będę rozbudowywać kod, tak aby na bazie powyższego kodu utworzyć kolejne “byty” tj. elementy, zacznę od struktury. Rozpoczynamy od zdefiniowania zmiennej dla danych:

DATA: ls_hours_work type ty_emp_worktime.
  • DATA -> definiuję zmienną dla danych.
  • ​ls_hours_work -> nazwa zmiennej. W dosłownym tłumaczeniu „lokalna struktura z godzinami pracy”.
  • TYPE ty_emp_worktime –> infromacja, że zmienna ma typ struktury, który wcześniej został zdefiniowany jako ty_emp_worktime.

Nazewnictwo zmiennych zwykle prefiks ls_ oznacza local structure:

  • ls_ -> zazwyczaj rozwija się do local structure - lokalna struktura (jeden rekord),
  • lt_ -> rozwija się do local table - lokalna tabela wewnętrzna (wiele rekordów).
  • lv_ -> lokalna zmienna prosta (variable).

ls i lt są całkowicie umowne - język ABAP ich nie wymaga, ale branżowa konwencja bardzo je poleca. Co więcej stosowanie ls/lt/lv wypełnia zasadę. „self-explanatory / easily readable code”.

Możesz nazwać zmienne jakkolwiek: worktime_rec**, gt_hours, employee_data. W wielu firmach używa się innych liter przed _ (np. gs_/gt_ dla zmiennych globalnych, lv_ dla prostych zmiennych), ale zawsze chodzi o to samo: prefiks opisuje rodzaj i zasięg zmiennej.

Po co prefix ty_ ?

Ułatwia on odróżnienie w kodzie:

  • ty_emp_worktime - typ (szablon struktury),
  • ls_emp_worktime - zmienna (lokalna struktura tego typu).

Dzięki temu, czytając kod, od razu wiesz, czy coś jest „modelem” (typem), czy konkretnymi danymi.

Czy ty_ jest obowiązkowe?

Nie, język ABAP tego nie wymaga - mógłbyś nazwać typ np.
employee_worktime_type. ty_ jest po prostu szeroko stosowaną praktyką
w standardach nazewniczych (obok lv_, ls_, lt_ itd.), która poprawia
czytelność i spójność kodu.

Definicja typu

  • Definicja typu (TYPES ...) to opis kształtu danych, np. że rekord ma pola employee_id, work_date, hours_work.

  • Taki typ nie zajmuje pamięci i nie przechowuje wartości, jest tylko szablonem, którego można używać wiele razy.

Zmienna (obiekt danych)

  • Zmienna (DATA ... TYPE ...) to konkretny egzemplarz danych w pamięci utworzony na podstawie typu.

  • Ma już przydzieloną pamięć i może przechowywać aktualne wartości (np. employee_id = ‘KOWALSKI’).

Podsumowanie:

  • typ = „jaki kształt mają dane”,
  • zmienna = „konkretne dane tego kształtu przechowywane w pamięci”.

Kontynuujemy pisanie kodu: ls_hours_work - cała struktura (rekord z kilkoma polami).
-employee_id - konkretna składowa tej struktury, jedno pole w środku.
= - ustaw temu polu wartość 'KOWALSKI'.

ls_hours_work-employee_id = 'KOWALSKI'.
ls_hours_work-work_date = '20251206'.
ls_hours_work-hours_work = '5'.

Efekt: powstaje pojedynczy „wiersz” z trzema polami: employee_id, work_date, hours_work, który możemy wypełnić wartościami.

cl_demo_output=>display(
EXPORTING
data = ls_hours_work
).
  • display ma w swojej definicji parametr wejściowy o nazwie data.
  • Słowo EXPORTING otwiera sekcję „parametry, które przekazuję do metody jako dane wejściowe” - po nim wymieniasz pary nazwa_parametru = zmienna.
  • data = ls_hours_work` znaczy: do parametru data przekaż zawartość zmiennej ls_hours_work.

Dlaczego przekazanie wartości do parametru metody jest konieczne? EXPORTING

Przekazanie ls_hours_work do metody jest konieczne, bo w ABAP metoda
nic „z góry” nie wie o Twoich zmiennych - widzi tylko swoje
parametry.​

Hermetyzacja metod

  • Metoda display jest zdefiniowana gdzieś w klasie cl_demo_output z parametrem IMPORTING data TYPE any.​
  • Zgodnie z zasadami programowania strukturalnego/obiektowego ABAP, metoda pracuje wyłącznie na tym, co dostanie w parametrach (i ewentualnie na własnych polach), a nie na „globalnych” zmiennych Twojego raportu.​

Dlatego musimy jawnie powiedzieć: „ta metoda ma pracować na strukturze
ls_hours_work” - robimy to przez EXPORTING data = ls_hours_work.

Silne typowanie i jawne interfejsy

  • ABAP jest językiem statycznie typowanym - kompilator musi z góry wiedzieć, jaki typ danych trafia do parametru data.​

  • Interfejs metody (IMPORTING / EXPORTING / CHANGING / RETURNING) opisuje dokładnie, jakie dane i w jakich kierunkach przepływają, bez przekazania wartości parametrów metoda nie ma żadnych „wejść”.​

W skrócie:

  • definicja metody mówi: „przyjmuję coś w parametrze data”;
  • wywołanie z EXPORTING data = ls_hours_work mówi: „tu masz konkretną zmienną, z którą masz pracować”.

Ta konieczność wynika więc z cech ABAP-u jako języka z silnym typowaniem i jawnymi interfejsami metod - metoda nie widzi Twoich zmiennych, dopóki ich do niej nie przekażesz.

Shift F1
CTRL F2
CTRL F3
F8

Struktura stanowi pierwszą linijkę tabeli: KOWALSKI, 2025-12-06, 5

TWORZENIE TABELI WEWNĘTRZNEJ

Tabela wewnętrzna jest potrzebna po to, aby w programie przechowywać i obrabiać wiele wierszy danych tylko w pamięci, bez ciągłego czytania bazy.

Główne powody użycia tabeli wewnętrznych

  • Tymczasowe przechowywanie - pobierasz dane z tabel bazy (np. wynagrodzenia, godziny pracy) jednym lub kilkoma SELECT-ami i trzymasz je w tabeli wewnętrznej podczas działania programu.
  • Przetwarzanie wielu rekordów - możesz po niej robić LOOP, READ TABLE, SORT, DELETE, liczyć sumy, filtrować, łączyć z innymi tabelami itp., tak jakbyś miał mini-bazę tylko dla swojego raportu.
  • Wydajność i wygoda - zamiast strzelać wieloma SELECT-ami do bazy, robisz jedno pobranie, a reszta logiki dzieje się na danych w pamięci, co jest zwykle szybsze i prostsze w kodzie.

Dla mojego zadania projektowego tabela wewnętrzna jest przydatna, ponieważ dzięki niej tworzę „listę” rekordów czasu pracy, mogę do niej dopisywać kolejne struktury ls_hours_work (np. dla różnych dni lub pracowników), a na końcu jednym wywołaniem wyświetlić lub zapisać wszystkie naraz.

Natomiast tabela wewnętrzna nie sprawdza się gdy nie potrzebujesz
listy wielu rekordów ani dalszego przetwarzania w pamięci.

Typowe sytuacje „bez sensu” dla tworzenia tabeli wewnętrznej

  • Masz tylko jeden rekord - jeśli program zawsze operuje na pojedynczym wpisie (np. jedno wynagrodzenie, jedna data), wystarczy jedna struktura, tabela tylko komplikuje kod.​

  • Brak dalszego przetwarzania - gdy od razu wyświetlasz/drukujesz wynik z SELECT-a i nie filtrujesz, nie sortujesz, nie łączysz z innymi danymi, czasem da się obejść bez tabel wewnętrznych (np. prosty WRITE z pojedynczej struktury).​

  • Dane są ogromne, a logika prosta - ładowanie miliona wierszy do tabeli wewnętrznej tylko po to, żeby przejść raz pętlą, może zabić pamięć, wtedy lepiej przetwarzać porcjami (SELECT z UP TO n ROWS, kursory) albo przerzucić logikę bliżej bazy (CDS, SQL) lub specjalne techniki buforowania.​ Przy bardzo dużych wolumenach (setki tysięcy, miliony wierszy) tabela wewnętrzna może zająć dużo pamięci i zwolnić system.

W skrócie: używaj tabel wewnętrznych, gdy potrzebujesz kolekcji
rekordów do obróbki, a gdy masz pojedynczy obiekt lub bardzo prostą
operację, zwykła struktura lub pojedyncza zmienna jest lepszym
wyborem.

Wracając do pisania kodu deklaruję tabelę wewnętrzną lt_hours_work, w której każdy wiersz ma strukturę ty_emp_worktime.

​Dodałam kolejne dane:

Dodaję APPEND i na końcu klasę demo output: APPEND przenosi strukturę ls_hours_work do tabeli lt_hours_work.:

Po aktywacji pojawia się pierwsze okno ze strukturą:

Zamykamy okno i pojawia się nasza tabela z obiema zapisami:

Podsumowując dzięki strukturze mogłam dodać dane do tabeli.
Warto jednak dodać, że są nowsze rozwiązania pozwalające na dodanie danych do tabeli. Mówiąc w skrócie SAP rozwija ABAP Platform razem z kolejnymi wersjami NetWeaver/SAP S/4HANA i ABAP Cloud; każda wersja wnosi nowe elementy języka - nowsze wersje języka (ABAP 7.40, 7.50, 7.52, 7.55, ABAP Cloud), oraz „modern ABAP syntax”.

Dodanie wierszy z nowymi danymi może odbywać się dwoma sposobami:

I. Z zastosowaniem #:
‘#’ pozwala na rozpozanie typu danych znajdujących się w nawiasach z tabeli lt_hours_work, a jak wiemy lt_hours_work jest tego typu:

Efekt po aktywacji:

II. Z zastosowaniem typu tabelarycznego t_ty_emp_worktime (STANDARD TABLE OF) - dodaję kod:

TYPES: t_ty_emp_worktime TYPE STANDARD TABLE OF ty_emp_worktime WITH DEFAULT KEY.
  • t_ty_emp_worktime - nowy lokalny typ tabeli.
  • TYPE STANDARD TABLE OF ty_emp_worktime - tabela standardowa, której każdy wiersz ma typ ty_emp_worktime (Twoja struktura z employee_id, work_date, hours_work).
  • WITH DEFAULT KEY - tabela ma domyślny klucz (wszystkie pola struktury są kluczem).

Z kolei kod:
lt_hours_work = VALUE t_ty_emp_worktime(
( employee_id = ‘JANKOWSKA’ work_date = ‘20250707’ hours_work = 10 )
( employee_id = ‘LUBICZ’ work_date = ‘20250302’ hours_work = 3 )
).

  • VALUE t_ty_emp_worktime( … ) - utwórz nową tabelę typu t_ty_emp_worktime.
  • Każda para nawiasów (…) to jeden wiersz tej tabeli, z przypisaniem pól po nazwie.

Efekt przy zastosowaniu opcji z # lub z zastosowaniem typu tabelarycznego jest ten sam - tj. powstanie dwóch wierszy z nowymi danymi.

Typy lokalne są widoczne tylko w tym programie i dane zawarte tutaj również nie są widoczne poza tym programem - nie można ich użyć poza tym programem.

Dlatego też typy lokalne mają małe zastosowanie, ale sprawdzają się w
małych, jednorazowych strukturach pomocniczych, tymczasowe typy do
raportu, których nie chcemy upubliczniać w całym systemie.