Mesh Expressions enable navigation between linked internal tables through defined associations - similar to SQL joins, but for internal tables. Instead of writing nested LOOPs with WHERE conditions, you define the relationships centrally once and then navigate declaratively.
What are Mesh Expressions?
A mesh is a typed compound of internal tables with defined associations. You define the relationships between tables (1:n, n:1) and can then navigate using path expressions.
| Concept | Description |
|---|---|
TYPES MESH | Defines the mesh type with tables and associations |
ASSOCIATION name TO node | Forward association (e.g., Header → Items) |
ON field = field | Join condition of the association |
mesh-node\assoc[ line ] | Forward navigation: All related rows |
mesh-node\_assoc[ line ] | Backward navigation: Back to parent |
Availability
Mesh Expressions are available since ABAP 7.40 SP05 and fully ABAP Cloud compatible. They can be used without restrictions in BTP ABAP Environment and S/4HANA Cloud.
Practical Example: Order with Items and Conditions
A typical scenario is order processing with three levels:
- Order Header (Order number, customer, date)
- Order Items (Product, quantity, price)
- Conditions (Discounts, surcharges per item)
Classic Approach: Nested LOOPs
Without Mesh Expressions, the code typically looks like this:
CLASS zcl_order_classic DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_order_header, order_id TYPE sysuuid_x16, customer TYPE string, order_date TYPE d, END OF ty_s_order_header.
TYPES: BEGIN OF ty_s_order_item, order_id TYPE sysuuid_x16, item_no TYPE i, product TYPE string, quantity TYPE i, net_price TYPE p DECIMALS 2, END OF ty_s_order_item.
TYPES: BEGIN OF ty_s_condition, order_id TYPE sysuuid_x16, item_no TYPE i, condition_type TYPE c LENGTH 4, amount TYPE p DECIMALS 2, END OF ty_s_condition.
TYPES ty_t_headers TYPE STANDARD TABLE OF ty_s_order_header WITH EMPTY KEY. TYPES ty_t_items TYPE STANDARD TABLE OF ty_s_order_item WITH EMPTY KEY. TYPES ty_t_conditions TYPE STANDARD TABLE OF ty_s_condition WITH EMPTY KEY.
ENDCLASS.
CLASS zcl_order_classic IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. " Test data DATA(lv_order1) = cl_system_uuid=>create_uuid_x16_static( ).
DATA(lt_headers) = VALUE ty_t_headers( ( order_id = lv_order1 customer = 'Mueller GmbH' order_date = sy-datum ) ).
DATA(lt_items) = VALUE ty_t_items( ( order_id = lv_order1 item_no = 10 product = 'Laptop' quantity = 2 net_price = '1200.00' ) ( order_id = lv_order1 item_no = 20 product = 'Monitor' quantity = 3 net_price = '350.00' ) ).
DATA(lt_conditions) = VALUE ty_t_conditions( ( order_id = lv_order1 item_no = 10 condition_type = 'RA01' amount = '-120.00' ) ( order_id = lv_order1 item_no = 10 condition_type = 'ZU01' amount = '50.00' ) ( order_id = lv_order1 item_no = 20 condition_type = 'RA01' amount = '-52.50' ) ).
" Nested LOOPs - hard to read LOOP AT lt_headers INTO DATA(ls_header). out->write( |Order: { ls_header-customer }| ).
LOOP AT lt_items INTO DATA(ls_item) WHERE order_id = ls_header-order_id.
out->write( | Item { ls_item-item_no }: { ls_item-product }| ).
LOOP AT lt_conditions INTO DATA(ls_cond) WHERE order_id = ls_item-order_id AND item_no = ls_item-item_no.
out->write( | Condition { ls_cond-condition_type }: { ls_cond-amount }| ). ENDLOOP. ENDLOOP. ENDLOOP. ENDMETHOD.
ENDCLASS.Problems with Nested LOOPs
| Problem | Impact |
|---|---|
| Redundant WHERE conditions | Error-prone when making changes |
| Poor performance | Linear scan with STANDARD TABLE |
| Unreadable code | Barely maintainable with more levels |
| No reusability | Conditions must be rewritten every time |
Mesh Approach: Declarative Navigation
With Mesh Expressions, you define the relationships once and navigate elegantly:
CLASS zcl_order_mesh DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
" Structures TYPES: BEGIN OF ty_s_order_header, order_id TYPE sysuuid_x16, customer TYPE string, order_date TYPE d, END OF ty_s_order_header.
TYPES: BEGIN OF ty_s_order_item, order_id TYPE sysuuid_x16, item_no TYPE i, product TYPE string, quantity TYPE i, net_price TYPE p DECIMALS 2, END OF ty_s_order_item.
TYPES: BEGIN OF ty_s_condition, order_id TYPE sysuuid_x16, item_no TYPE i, condition_type TYPE c LENGTH 4, amount TYPE p DECIMALS 2, END OF ty_s_condition.
" SORTED tables for optimal performance TYPES ty_t_headers TYPE SORTED TABLE OF ty_s_order_header WITH UNIQUE KEY order_id. TYPES ty_t_items TYPE SORTED TABLE OF ty_s_order_item WITH UNIQUE KEY order_id item_no. TYPES ty_t_conditions TYPE SORTED TABLE OF ty_s_condition WITH NON-UNIQUE KEY order_id item_no condition_type.
" Mesh definition with all associations TYPES: BEGIN OF MESH ty_m_order, headers TYPE ty_t_headers ASSOCIATION items TO items ON order_id = order_id, items TYPE ty_t_items ASSOCIATION header TO headers ON order_id = order_id ASSOCIATION conditions TO conditions ON order_id = order_id AND item_no = item_no, conditions TYPE ty_t_conditions ASSOCIATION item TO items ON order_id = order_id AND item_no = item_no, END OF MESH ty_m_order.
ENDCLASS.
CLASS zcl_order_mesh IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. " Test data DATA(lv_order1) = cl_system_uuid=>create_uuid_x16_static( ). DATA(lv_order2) = cl_system_uuid=>create_uuid_x16_static( ).
DATA(lt_headers) = VALUE ty_t_headers( ( order_id = lv_order1 customer = 'Mueller GmbH' order_date = sy-datum ) ( order_id = lv_order2 customer = 'Schmidt AG' order_date = sy-datum ) ).
DATA(lt_items) = VALUE ty_t_items( ( order_id = lv_order1 item_no = 10 product = 'Laptop' quantity = 2 net_price = '1200.00' ) ( order_id = lv_order1 item_no = 20 product = 'Monitor' quantity = 3 net_price = '350.00' ) ( order_id = lv_order2 item_no = 10 product = 'Keyboard' quantity = 5 net_price = '75.00' ) ).
DATA(lt_conditions) = VALUE ty_t_conditions( ( order_id = lv_order1 item_no = 10 condition_type = 'RA01' amount = '-120.00' ) ( order_id = lv_order1 item_no = 10 condition_type = 'ZU01' amount = '50.00' ) ( order_id = lv_order1 item_no = 20 condition_type = 'RA01' amount = '-52.50' ) ( order_id = lv_order2 item_no = 10 condition_type = 'RA02' amount = '-15.00' ) ).
" Create mesh DATA(ls_order_mesh) = VALUE ty_m_order( headers = lt_headers items = lt_items conditions = lt_conditions ).
" Navigation with mesh paths LOOP AT ls_order_mesh-headers INTO DATA(ls_header). out->write( |Order: { ls_header-customer }| ).
" Forward navigation: Header -> Items LOOP AT ls_order_mesh-headers\items[ ls_header ] INTO DATA(ls_item). out->write( | Item { ls_item-item_no }: { ls_item-product }| ).
" Forward navigation: Item -> Conditions LOOP AT ls_order_mesh-items\conditions[ ls_item ] INTO DATA(ls_cond). out->write( | Condition { ls_cond-condition_type }: { ls_cond-amount }| ). ENDLOOP. ENDLOOP. ENDLOOP. ENDMETHOD.
ENDCLASS.Comparison: Mesh vs. LOOP AT
Syntax Comparison
" CLASSIC: WHERE condition in every LOOPLOOP AT lt_items INTO DATA(ls_item) WHERE order_id = ls_header-order_id. " ...ENDLOOP.
" MESH: Relationship defined once, then navigateLOOP AT ls_mesh-headers\items[ ls_header ] INTO DATA(ls_item). " ...ENDLOOP.Feature Comparison
| Aspect | Classic (LOOP + WHERE) | Mesh Expressions |
|---|---|---|
| Relationship definition | Scattered in code | Once centrally |
| Type safety | Runtime errors possible | Compile-time checking |
| Performance | Depends on table type | Uses keys automatically |
| Readability | WHERE conditions everywhere | Declarative paths |
| Maintainability | Changes in many places | Changes only in mesh |
| Backward navigation | Explicit search required | Built-in with \_assoc |
Backward Navigation: From Detail to Header
With Mesh Expressions, you can also navigate backwards:
CLASS zcl_mesh_backward DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_header, order_id TYPE i, customer TYPE string, END OF ty_s_header.
TYPES: BEGIN OF ty_s_item, order_id TYPE i, item_no TYPE i, product TYPE string, END OF ty_s_item.
TYPES: BEGIN OF ty_s_condition, order_id TYPE i, item_no TYPE i, condition_type TYPE string, amount TYPE p DECIMALS 2, END OF ty_s_condition.
TYPES ty_t_headers TYPE SORTED TABLE OF ty_s_header WITH UNIQUE KEY order_id. TYPES ty_t_items TYPE SORTED TABLE OF ty_s_item WITH UNIQUE KEY order_id item_no. TYPES ty_t_conditions TYPE SORTED TABLE OF ty_s_condition WITH NON-UNIQUE KEY order_id item_no.
TYPES: BEGIN OF MESH ty_m_order, headers TYPE ty_t_headers ASSOCIATION items TO items ON order_id = order_id, items TYPE ty_t_items ASSOCIATION header TO headers ON order_id = order_id ASSOCIATION conditions TO conditions ON order_id = order_id AND item_no = item_no, conditions TYPE ty_t_conditions ASSOCIATION item TO items ON order_id = order_id AND item_no = item_no, END OF MESH ty_m_order.
ENDCLASS.
CLASS zcl_mesh_backward IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_headers) = VALUE ty_t_headers( ( order_id = 1 customer = 'Customer A' ) ( order_id = 2 customer = 'Customer B' ) ).
DATA(lt_items) = VALUE ty_t_items( ( order_id = 1 item_no = 10 product = 'Laptop' ) ( order_id = 2 item_no = 10 product = 'Server' ) ).
DATA(lt_conditions) = VALUE ty_t_conditions( ( order_id = 1 item_no = 10 condition_type = 'Discount 10%' amount = '-100.00' ) ( order_id = 2 item_no = 10 condition_type = 'Volume discount' amount = '-500.00' ) ).
DATA(ls_mesh) = VALUE ty_m_order( headers = lt_headers items = lt_items conditions = lt_conditions ).
out->write( '=== Backward Navigation: Condition -> Item -> Header ===' ).
" Starting from conditions, navigate back to customer LOOP AT ls_mesh-conditions INTO DATA(ls_cond). " Backward: Condition -> Item DATA(ls_parent_item) = ls_mesh-conditions\_item[ ls_cond ].
" Backward: Item -> Header DATA(ls_parent_header) = ls_mesh-items\_header[ ls_parent_item ].
out->write( |{ ls_cond-condition_type } ({ ls_cond-amount }) | && |-> { ls_parent_item-product } | && |-> { ls_parent_header-customer }| ). ENDLOOP. ENDMETHOD.
ENDCLASS.Aggregations with REDUCE and Mesh
Mesh Expressions combined with REDUCE enable elegant calculations:
CLASS zcl_mesh_aggregation DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_order, order_id TYPE i, customer TYPE string, END OF ty_s_order.
TYPES: BEGIN OF ty_s_item, order_id TYPE i, item_no TYPE i, quantity TYPE i, net_price TYPE p DECIMALS 2, END OF ty_s_item.
TYPES: BEGIN OF ty_s_condition, order_id TYPE i, item_no TYPE i, condition_type TYPE c LENGTH 4, amount TYPE p DECIMALS 2, END OF ty_s_condition.
TYPES ty_t_orders TYPE SORTED TABLE OF ty_s_order WITH UNIQUE KEY order_id. TYPES ty_t_items TYPE SORTED TABLE OF ty_s_item WITH UNIQUE KEY order_id item_no. TYPES ty_t_conditions TYPE SORTED TABLE OF ty_s_condition WITH NON-UNIQUE KEY order_id item_no.
TYPES: BEGIN OF MESH ty_m_sales, orders TYPE ty_t_orders ASSOCIATION items TO items ON order_id = order_id, items TYPE ty_t_items ASSOCIATION order TO orders ON order_id = order_id ASSOCIATION conditions TO conditions ON order_id = order_id AND item_no = item_no, conditions TYPE ty_t_conditions ASSOCIATION item TO items ON order_id = order_id AND item_no = item_no, END OF MESH ty_m_sales.
ENDCLASS.
CLASS zcl_mesh_aggregation IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_orders) = VALUE ty_t_orders( ( order_id = 1 customer = 'Customer A' ) ( order_id = 2 customer = 'Customer B' ) ).
DATA(lt_items) = VALUE ty_t_items( ( order_id = 1 item_no = 10 quantity = 2 net_price = '1000.00' ) ( order_id = 1 item_no = 20 quantity = 1 net_price = '500.00' ) ( order_id = 2 item_no = 10 quantity = 5 net_price = '200.00' ) ).
DATA(lt_conditions) = VALUE ty_t_conditions( ( order_id = 1 item_no = 10 condition_type = 'RA01' amount = '-200.00' ) ( order_id = 1 item_no = 20 condition_type = 'RA01' amount = '-50.00' ) ( order_id = 2 item_no = 10 condition_type = 'RA02' amount = '-100.00' ) ).
DATA(ls_mesh) = VALUE ty_m_sales( orders = lt_orders items = lt_items conditions = lt_conditions ).
out->write( '=== Order value per customer (incl. conditions) ===' ).
LOOP AT ls_mesh-orders INTO DATA(ls_order). " Sum of all items DATA(lv_net_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR <item> IN ls_mesh-orders\items[ ls_order ] NEXT sum = sum + ( <item>-quantity * <item>-net_price ) ).
" Sum of all conditions DATA(lv_conditions_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR <item> IN ls_mesh-orders\items[ ls_order ] FOR <cond> IN ls_mesh-items\conditions[ <item> ] NEXT sum = sum + <cond>-amount ).
DATA(lv_grand_total) = lv_net_total + lv_conditions_total.
out->write( |{ ls_order-customer }:| ). out->write( | Net: { lv_net_total } EUR| ). out->write( | Conditions: { lv_conditions_total } EUR| ). out->write( | Total: { lv_grand_total } EUR| ). ENDLOOP. ENDMETHOD.
ENDCLASS.Performance Tips
Choose Table Types
" GOOD: SORTED TABLE with matching keyTYPES ty_t_items TYPE SORTED TABLE OF ty_s_item WITH UNIQUE KEY order_id item_no.
" BAD: STANDARD TABLE - poor performance" TYPES ty_t_items TYPE STANDARD TABLE OF ty_s_item" WITH EMPTY KEY.Save Memory with REF
For large tables, you can use references instead of copies:
" Mesh with references (saves memory)DATA(ls_mesh) = VALUE ty_m_order( headers = lt_headers " Copy items = REF #( lt_items ) " Reference conditions = REF #( lt_conditions )).ABAP Cloud Compatibility
| Aspect | Status |
|---|---|
| BTP ABAP Environment | ✅ Fully supported |
| S/4HANA Cloud | ✅ Fully supported |
| S/4HANA On-Premise | ✅ From 7.40 SP05 |
| Released API Status | ✅ Core language feature |
Mesh Expressions are a core language feature of ABAP and not affected by Released API restrictions. They can be used without limitations in all ABAP Cloud environments.
Best Practices for ABAP Cloud
" DO: SORTED/HASHED tables with meaningful keysTYPES ty_t_items TYPE SORTED TABLE OF ty_s_item WITH UNIQUE KEY order_id item_no.
" DO: Use mesh for complex navigationsLOOP AT ls_mesh-headers\items[ ls_header ] INTO DATA(ls_item). " Clearer than WHERE conditionsENDLOOP.
" DON'T: STANDARD TABLE without key" TYPES ty_t_items TYPE STANDARD TABLE OF ty_s_item" WITH EMPTY KEY.
" DON'T: Mesh for simple 1:1 lookups" For single lookups, READ TABLE is more efficientWhen to Use Mesh?
| Use Case | Recommendation |
|---|---|
| Header-Item structures | ✅ Ideal for Mesh |
| Master-Detail relationships | ✅ Ideal for Mesh |
| Hierarchical data (BOM) | ✅ Ideal for Mesh |
| Simple 1:1 lookup | ❌ READ TABLE is sufficient |
| Database tables directly | ❌ Mesh only for internal tables |
| Dynamic relationships | ❌ Associations must be static |
Summary
Mesh Expressions offer an elegant alternative to nested LOOPs:
- Central Definition: Define relationships once in the MESH type
- Declarative Navigation: Path syntax instead of WHERE conditions
- Type Safety: Compile-time checking of associations
- Bidirectional Navigation: Forward (
\) and Backward (\_) - Performance: Uses table keys automatically
- ABAP Cloud-ready: Fully supported in all cloud environments
Especially for order structures with headers, items, and conditions, Mesh Expressions significantly reduce complexity and make code more maintainable.