Chapter 07 ยท Core Classic ABAP
Internal Tables โ The Heart of ABAP
ABAP’s most important data structure. Every real program uses them. Master these and you can build anything.
If you learn only one thing in ABAP, make it internal tables. They are the data structure at the core of every ABAP program that does real work. Reports use them to hold query results. Interfaces use them to pass data between systems. Fiori apps use them to prepare UI data. RAP business objects use them everywhere.
An internal table is a variable that holds multiple rows of data, where each row has the same structure. Think of it as a spreadsheet in memory โ columns are fields, rows are records. It lives only inside your program, but it is where all the real processing happens.
In Chapter 6 you learned how to read data from a database. In this chapter you learn where that data goes, how to work with it, and how to feed it back out. This is the chapter that unlocks everything from here onward.
๐ฏ Who Is This Chapter For?
This chapter is the most universally applicable chapter in the series. Both paths use nearly identical syntax here:
- If you are on the FREE BTP Trial โ you will work with internal tables inside ABAP Cloud classes in Eclipse ADT. You will read from CDS Views into internal tables and process the data.
- If you have PAID SAP access โ you will do everything free learners do, plus read from transparent tables in SE38 reports. The internal table syntax is identical.
- Both paths share the same syntax. This is one of the rare chapters where the two paths almost completely converge. The only difference is where the data comes from.
๐ฏ What You Will Learn in This Chapter
- What an internal table is and why it matters
- The three types: standard, sorted, hashed โ and when to use each
- How to declare internal tables with
TYPESandDATA - The five fundamental operations: APPEND, INSERT, READ, LOOP, DELETE
- How to sort, modify, and empty internal tables
- Work areas vs field symbols โ how to access rows efficiently
- Performance patterns and common mistakes
๐งญ Which Path Should I Choose?
This chapter has the same two learner types as always, but the difference between them is smaller here than anywhere else in the series.
Two learner types โ find yourself
๐ What is an Internal Table?
An internal table is a variable that holds multiple rows, each row having the same structure. It is ABAP’s implementation of what other languages call an array, list, or in-memory table.
An internal table has three components:
| Component | What it is | Example |
|---|---|---|
| Row structure | The shape of each row โ which fields it has | Customer ID, Name, City, Join Date |
| Table type | Standard, sorted, or hashed โ determines access behavior | Standard table |
| Key | Which fields identify a row | Customer ID (unique key) |
Why internal tables matter
Every ABAP program that does real work follows the same pattern:
- Read data from the database into an internal table
- Process the data in memory โ sort, filter, calculate, transform
- Write the result back to the database, or output it to the user
That middle step โ processing โ is entirely done with internal tables. Without them, you would have to re-read from the database for every calculation, which is slow and inefficient.
Internal Tables in Cloud
You use the same internal table syntax inside ABAP Cloud classes. Data comes from CDS Views instead of raw tables.
- Declare with
DATA ... TYPE TABLE OF ... - Read data from CDS Views with SELECT
- Process with LOOP, SORT, DELETE, MODIFY
- Output with cl_demo_output or a RAP result
Internal Tables in Classic
You use identical internal table syntax in SE38 reports. Data comes from transparent tables directly.
- Declare with
DATA ... TYPE TABLE OF ... - Read data from transparent tables with SELECT
- Process with LOOP, SORT, DELETE, MODIFY
- Output with WRITE or ALV (Chapter 9)
๐ฏ The Three Internal Table Types
ABAP has three internal table types, each optimized for different access patterns. Choosing the right one is a mark of a skilled ABAP developer.
| Type | Access by Index | Access by Key | When to use |
|---|---|---|---|
| STANDARD TABLE | Fast (O(1)) | Slow (linear scan) | Default choice. Best when you mostly loop through all rows or access by position. |
| SORTED TABLE | Fast | Fast (binary search) | Best when rows are always sorted and you frequently access by key. |
| HASHED TABLE | Not allowed | Very fast (O(1)) | Best when you only access by unique key and never need order. |
How to declare each type
" Standard table โ the default choice
DATA lt_standard TYPE STANDARD TABLE OF zcustomer.
" Sorted table โ always kept sorted by key
DATA lt_sorted TYPE SORTED TABLE OF zcustomer
WITH UNIQUE KEY customer_id.
" Hashed table โ fastest access by key
DATA lt_hashed TYPE HASHED TABLE OF zcustomer
WITH UNIQUE KEY customer_id.
Notice the lt_ prefix โ that is the naming convention for local tables. Following it makes your code readable at a glance.
๐ฆ Work Areas โ How to Hold One Row
Before you can add rows to an internal table or read from it, you need a work area โ a flat structure that holds one row at a time.
" Work area matching the table structure
DATA ls_customer TYPE zcustomer.
" Internal table of the same structure
DATA lt_customers TYPE STANDARD TABLE OF zcustomer.
The ls_ prefix means “local structure” (work area) and lt_ means “local table”. Together they are the workhorses of ABAP.
Filling the work area and appending
ls_customer-customer_id = 'C001'.
ls_customer-customer_name = 'Rahul Sharma'.
ls_customer-city = 'Pune'.
APPEND ls_customer TO lt_customers.
Inline declaration (modern syntax)
In modern ABAP, you can declare the work area inline when reading:
LOOP AT lt_customers INTO DATA(ls_row).
cl_demo_output=>write( ls_row-customer_name ).
ENDLOOP.
The DATA(ls_row) syntax creates the work area on the fly. It is clean and works in both Classic ABAP (newer releases) and ABAP Cloud.
โ APPEND โ Adding Rows
APPEND adds a row to the end of a standard table. It is the most-used operation for building up a table row by row.
DATA lt_customers TYPE STANDARD TABLE OF zcustomer.
DATA ls_customer TYPE zcustomer.
" Add the first customer
ls_customer-customer_id = 'C001'.
ls_customer-customer_name = 'Rahul Sharma'.
ls_customer-city = 'Pune'.
APPEND ls_customer TO lt_customers.
" Add the second customer
ls_customer-customer_id = 'C002'.
ls_customer-customer_name = 'Priya Patel'.
ls_customer-city = 'Mumbai'.
APPEND ls_customer TO lt_customers.
" Check how many rows are in the table
cl_demo_output=>write( |Total rows: { lines( lt_customers ) }| ).
INSERT.
โ INSERT โ Adding Rows at Specific Positions
INSERT adds a row to a specific position or follows the table’s own ordering rules.
Insert at a specific index (standard table)
INSERT ls_customer INTO lt_customers INDEX 1.
Insert into a sorted table
INSERT ls_customer INTO TABLE lt_sorted.
The sorted table automatically places the row in the correct sorted position based on its key.
Insert into a hashed table
INSERT ls_customer INTO TABLE lt_hashed.
The hashed table places the row wherever the hash algorithm determines. Position is not meaningful.
๐ READ โ Finding Specific Rows
READ TABLE retrieves one specific row without looping through all of them.
Read by index (standard and sorted tables)
READ TABLE lt_customers INTO ls_customer INDEX 2.
IF sy-subrc = 0.
cl_demo_output=>write( |Row 2 is: { ls_customer-customer_name }| ).
ENDIF.
Read by key
READ TABLE lt_customers INTO ls_customer
WITH KEY customer_id = 'C001'.
IF sy-subrc = 0.
cl_demo_output=>write( |Found: { ls_customer-customer_name }| ).
ELSE.
cl_demo_output=>write( 'Customer C001 not found.' ).
ENDIF.
sy-subrc: 0 means found, 4 or 8 means not found or other error. Always check it.
| Table type | By index | By key |
|---|---|---|
| Standard | Fast | Linear scan |
| Sorted | Fast | Binary search |
| Hashed | Not allowed | Fastest |
๐ LOOP โ Processing All Rows
LOOP AT iterates through every row of an internal table. It is the workhorse for processing data.
Basic loop
LOOP AT lt_customers INTO ls_customer.
cl_demo_output=>write( |{ ls_customer-customer_id }: { ls_customer-customer_name }| ).
ENDLOOP.
Modern loop with inline work area
LOOP AT lt_customers INTO DATA(ls_row).
cl_demo_output=>write( ls_row-customer_name ).
ENDLOOP.
Loop with filtering (WHERE clause)
LOOP AT lt_customers INTO ls_customer
WHERE city = 'Pune'.
cl_demo_output=>write( ls_customer-customer_name ).
ENDLOOP.
Accessing the loop index: sy-tabix
LOOP AT lt_customers INTO ls_customer.
cl_demo_output=>write( |Row { sy-tabix }: { ls_customer-customer_name }| ).
ENDLOOP.
sy-tabix holds the index of the current row. This is useful for numbering output or accessing related rows.
LOOP in Cloud
The syntax is identical. Use cl_demo_output for output, or pass the table to a RAP action.
LOOP in Classic
Same syntax. Use WRITE for output, or pass to ALV for a professional report.
๐ค SORT โ Ordering Rows
SORT reorders a standard table. Sorted and hashed tables maintain their own order automatically, so SORT applies mostly to standard tables.
Sort by a single field
SORT lt_customers BY customer_name.
Sort by multiple fields
SORT lt_customers BY city customer_name.
Sort descending
SORT lt_customers BY customer_id DESCENDING.
๐๏ธ DELETE โ Removing Rows
DELETE removes rows from an internal table. Just like database DELETE, always specify what to remove.
Delete by index
DELETE lt_customers INDEX 1.
Delete by condition
DELETE lt_customers WHERE city = 'Mumbai'.
Delete all rows
CLEAR lt_customers.
DELETE removes specific rows. CLEAR empties the entire table. Use CLEAR when you want to reuse the table with fresh data.
โ๏ธ MODIFY โ Changing Existing Rows
MODIFY updates a row that already exists in an internal table. It is the internal-table equivalent of SQL UPDATE.
" Read a row into the work area
READ TABLE lt_customers INTO ls_customer
WITH KEY customer_id = 'C001'.
IF sy-subrc = 0.
" Modify the work area
ls_customer-city = 'Delhi'.
" Write it back to the same row
MODIFY lt_customers FROM ls_customer
TRANSPORTING city
WHERE customer_id = 'C001'.
ENDIF.
TRANSPORTING specifies which fields to write back. If you omit it, the entire work area replaces the row.
Modify inside a LOOP (modern style)
LOOP AT lt_customers INTO ls_customer.
ls_customer-city = 'Delhi'.
MODIFY lt_customers FROM ls_customer.
ENDLOOP.
๐ Full Worked Example
Let’s put everything together. This program reads customers from the database into an internal table, processes them, and outputs the results.
๐ต Paid Path (Classic ABAP in SE38)
REPORT zinttab_ch7_demo.
DATA: lt_customers TYPE STANDARD TABLE OF zcustomer,
ls_customer TYPE zcustomer.
" 1. Read all customers from the database
SELECT * FROM zcustomer
INTO TABLE lt_customers.
IF sy-subrc <> 0.
WRITE: / 'No customers found.'.
RETURN.
ENDIF.
WRITE: / 'Total rows:', lines( lt_customers ).
" 2. Sort by city then name
SORT lt_customers BY city customer_name.
" 3. Loop and display
LOOP AT lt_customers INTO ls_customer.
WRITE: / sy-tabix,
ls_customer-customer_id,
ls_customer-customer_name,
ls_customer-city.
ENDLOOP.
" 4. Count customers in Pune
DATA(lv_pune_count) = 0.
LOOP AT lt_customers INTO ls_customer WHERE city = 'Pune'.
lv_pune_count = lv_pune_count + 1.
ENDLOOP.
WRITE: / 'Customers in Pune:', lv_pune_count.
" 5. Read a specific customer by key
READ TABLE lt_customers INTO ls_customer
WITH KEY customer_id = 'C001'.
IF sy-subrc = 0.
WRITE: / 'Found C001:', ls_customer-customer_name.
ENDIF.
๐ข Free Path (ABAP Cloud in Eclipse ADT)
METHOD run.
" Read from a CDS View into an internal table
SELECT * FROM zi_customer
INTO TABLE @DATA(lt_customers).
IF sy-subrc <> 0.
cl_demo_output=>write( 'No customers found.' ).
cl_demo_output=>display( ).
RETURN.
ENDIF.
cl_demo_output=>write( |Total rows: { lines( lt_customers ) }| ).
" Sort by city then name
SORT lt_customers BY city customer_name.
" Loop and output
LOOP AT lt_customers INTO DATA(ls_customer).
cl_demo_output=>write( |{ sy-tabix }: { ls_customer-customer_name } ({ ls_customer-city })| ).
ENDLOOP.
cl_demo_output=>display( ).
ENDMETHOD.
โก Performance Patterns
Internal tables look simple, but the wrong pattern can be 1000x slower than the right one on large data. Here are the rules that matter.
| Pattern | Slow Version | Fast Version |
|---|---|---|
| Finding a row by key | LOOP with IF check | READ TABLE with key or sorted/hashed table |
| Counting matching rows | LOOP with counter | LOOP with WHERE clause or filtered read |
| Building a table of unknown size | APPEND one at a time in a loop | SELECT … INTO TABLE in one statement |
| Deleting many rows | DELETE INDEX inside a LOOP | DELETE WHERE or DELETE ADJACENT DUPLICATES |
| Checking if a value exists | LOOP with exit | READ TABLE with TRANSPORTING NO FIELDS |
๐ง What Just Happened Under the Hood
Understanding how ABAP manages internal tables in memory helps you write better code.
| Operation | What Happens |
|---|---|
| APPEND | Adds the row at the end and increments the row count |
| INSERT | Shifts rows down to make space (if inserting in the middle) |
| READ by index | Directly accesses the row at that position โ O(1) |
| READ by key (standard) | Scans from top to bottom until found โ O(n) |
| READ by key (sorted) | Binary search โ O(log n) |
| READ by key (hashed) | Hash lookup โ O(1) |
| SORT | Reorders all rows in memory โ O(n log n) |
| DELETE by index | Removes the row and shifts subsequent rows up |
| DELETE WHERE | Scans all rows and removes matching ones in one pass |
This is why choosing the right table type matters. On 10 rows, performance is invisible. On 100,000 rows, using READ on a standard table inside a loop can freeze the program for minutes.
๐ Chapter Summary
- An internal table holds multiple rows of data in memory.
- The three types are STANDARD (default), SORTED (sorted by key), and HASHED (fastest by key).
- A work area holds one row at a time. Its prefix is
ls_. The table’s prefix islt_. - APPEND adds a row at the end of a standard table.
- INSERT adds a row at a specific position or into a sorted/hashed table.
- READ TABLE finds a specific row. Always check
sy-subrc. - LOOP AT iterates over rows. Use
sy-tabixfor the current index. - SORT reorders a standard table. DELETE removes rows. MODIFY changes existing rows.
- Performance matters: use READ with a key on sorted/hashed tables, not LOOP inside LOOP.
- The internal table syntax is nearly identical in Classic ABAP and ABAP Cloud โ one of the most portable skills you will ever learn.
๐ค Interview Questions & Answers
Internal table questions are the most common topic in ABAP interviews. Know these answers cold.
An internal table is a variable that holds multiple rows of data, each row having the same structure. It is ABAP’s in-memory data structure โ it lives only while the program runs and is not stored in the database.
It is important because it is where all real processing happens. Every ABAP program that does meaningful work follows the pattern: read data from the database into an internal table, process it in memory, and write it back. Without internal tables, you would have to re-read from the database for every calculation, which is slow and inefficient.
Standard table โ rows are stored in the order you APPEND them. Access by index is very fast (O(1)), but access by key requires a linear scan (O(n)). This is the default choice for 90% of cases.
Sorted table โ rows are automatically kept sorted by a unique or non-unique key. Both index and key access are fast (O(log n)). Use it when the rows need to always be in order and you frequently access by key.
Hashed table โ rows are stored by a hash of the key. Key access is the fastest possible (O(1)), but you cannot access by index at all. Use it when you only access by unique key and never need order.
A work area is a flat structure that holds one row of an internal table. You use it to read a row from the table, modify it, and write it back. It physically copies the row’s data into a separate memory location.
A field symbol is a pointer โ it does not copy data, it references the row directly in memory. You declare it with FIELD-SYMBOLS and use the angle-bracket syntax <fs>. Modifying a field symbol modifies the row directly, without any copy.
Rule of thumb: use field symbols in tight loops over large tables for performance. Use work areas when you need a copy that you can modify independently.
APPEND adds a row to the end of an internal table. It works only on standard tables.
INSERT adds a row at a specific position (by INDEX) or into a sorted/hashed table (which places the row according to its own rules). INSERT works on all three table types.
Use APPEND when building a standard table row by row and order does not matter. Use INSERT when you need a specific position, or when working with sorted or hashed tables.
sy-tabix is a system field that holds the current row index during a LOOP over an internal table. Inside the loop, it tells you which row you are processing.
Example: WRITE: / sy-tabix, ls_customer-customer_name. would print a numbered list: “1 Rahul Sharma”, “2 Priya Patel”, and so on.
It is also used inside LOOP for DELETE or MODIFY operations that need to reference the current row by index.
They barely differ at all. This is one of the rare areas where the two environments are almost identical. All the operations โ APPEND, INSERT, READ TABLE, LOOP AT, SORT, DELETE, MODIFY โ use the same syntax and behave the same way.
The only differences are:
- Output method: Cloud uses
cl_demo_output, Classic usesWRITEor ALV. - Data source: Cloud reads from CDS Views, Classic reads from transparent tables.
- Inline declarations: Cloud always supports
DATA(...)inline syntax. Classic supports it in newer releases only.
The core skill โ how to process internal tables โ is completely portable between the two environments.
๐ Practice Task for This Chapter
Complete the tasks for your path before moving to Chapter 8.
๐ข Free Path (BTP Trial)
- Create a new class
ZCL_ITAB_CH7in your package. - Add a method
runthat:- Declares a standard table of a CDS View (e.g.,
I_CountryorI_Currency) - Reads 10 rows from the CDS View into the table
- Sorts by a relevant field
- Loops and outputs each row with
sy-tabix - Reads one specific row by key using READ TABLE
- Deletes rows matching a condition
- Declares a standard table of a CDS View (e.g.,
- Save, activate (Ctrl + F3), and run (F9). Take a screenshot.
๐ต Paid Path (SAP System)
- Open SE38 and create a report
ZITAB_PRACTICE_CH7. - Read all records from your
ZCUSTOMERtable into a standard table. - Perform the following in order:
- Count total rows with
lines( ) - Sort by city, then by name
- LOOP and output each row with sy-tabix, id, name, and city
- READ TABLE by customer ID to find one specific customer
- Count how many customers are in each city (hint: use a second internal table with a counter)
- DELETE all customers from a specific city
- MODIFY a customer’s name
- Count total rows with
- Add sy-subrc checks where applicable (SELECT, READ TABLE).
- Run with F8 and screenshot the output.
Test: Kon Banega Crorepati?
5 questions. โน1 Crore. Prove you understood Chapter 7. No pressure โ restart anytime.
Explore Our Instructor-Led SAP & IT Courses
Self-study works. But if you want guided training, real project practice, and placement support โ here are the courses we offer. Book a free demo before you decide.
WhatsApp us