The DELETE statement for internal tables removes one or more rows from an internal table. There are various variants: delete by index, by key, with WHERE condition or removing duplicates.
Syntax
1. Delete Row by Index
DELETE <internal_table> INDEX <index>.2. Delete Row by Key
DELETE TABLE <internal_table> FROM <work_area>.DELETE TABLE <internal_table> WITH TABLE KEY <key> = <value>.3. Delete Multiple Rows with WHERE
DELETE <internal_table> WHERE <condition>.4. Delete Row in Current LOOP
LOOP AT <internal_table> ... DELETE <internal_table>. " Deletes current rowENDLOOP.5. Remove Duplicates
DELETE ADJACENT DUPLICATES FROM <internal_table> [COMPARING <fields> | ALL FIELDS] [USING KEY <key>].System Fields
After DELETE:
-
sy-subrc:0: At least one row deleted4: No matching row found
-
sy-tabix: Unchanged forDELETE ... INDEX; otherwise undefined
Examples
1. Delete Row by Index
DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Anna` ) ( `Bernd` ) ( `Clara` ) ( `David` ) ).
" Delete second rowDELETE lt_names INDEX 2.
" Result: Anna, Clara, DavidLOOP AT lt_names INTO DATA(lv_name). WRITE: / lv_name.ENDLOOP.2. Delete First and Last Row
DATA: lt_data TYPE TABLE OF i.
lt_data = VALUE #( ( 10 ) ( 20 ) ( 30 ) ( 40 ) ( 50 ) ).
" Delete first rowDELETE lt_data INDEX 1.
" Delete last rowDELETE lt_data INDEX lines( lt_data ).
" Result: 20, 30, 403. Delete Row by Key (FROM)
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, END OF ty_customer.
DATA: lt_customers TYPE HASHED TABLE OF ty_customer WITH UNIQUE KEY id, ls_customer TYPE ty_customer.
lt_customers = VALUE #( ( id = 1 name = 'Miller' ) ( id = 2 name = 'Schmidt' ) ( id = 3 name = 'Weber' )).
" Delete customer with ID 2ls_customer-id = 2.DELETE TABLE lt_customers FROM ls_customer.
IF sy-subrc = 0. WRITE: / 'Customer deleted.'.ELSE. WRITE: / 'Customer not found.'.ENDIF.4. Delete Row by Key (WITH TABLE KEY)
" Direct key accessDELETE TABLE lt_customers WITH TABLE KEY id = 3.
IF sy-subrc = 0. WRITE: / 'Customer 3 deleted.'.ENDIF.5. Delete Multiple Rows with WHERE
TYPES: BEGIN OF ty_order, order_id TYPE i, status TYPE string, amount TYPE p DECIMALS 2, END OF ty_order.
DATA: lt_orders TYPE TABLE OF ty_order.
lt_orders = VALUE #( ( order_id = 1 status = 'OPEN' amount = '100.00' ) ( order_id = 2 status = 'CANCELLED' amount = '200.00' ) ( order_id = 3 status = 'OPEN' amount = '150.00' ) ( order_id = 4 status = 'CANCELLED' amount = '300.00' ) ( order_id = 5 status = 'COMPLETED' amount = '250.00' )).
" Delete all cancelled ordersDELETE lt_orders WHERE status = 'CANCELLED'.
WRITE: / 'Deleted rows:', sy-dbcnt.WRITE: / 'Remaining rows:', lines( lt_orders ).
" Result: order_id 1, 3, 5 remain6. Complex WHERE Condition
" Combine multiple conditionsDELETE lt_orders WHERE status = 'OPEN' AND amount < 120.
" With ORDELETE lt_orders WHERE status = 'CANCELLED' OR amount = 0.
" With INDATA: lt_status TYPE RANGE OF string.lt_status = VALUE #( ( sign = 'I' option = 'EQ' low = 'CANCELLED' ) ( sign = 'I' option = 'EQ' low = 'REJECTED' ) ).
DELETE lt_orders WHERE status IN lt_status.7. Delete Row in LOOP
" NOTE: DELETE in LOOP is allowed, but be careful with field symbols!
DATA: lt_numbers TYPE TABLE OF i.
lt_numbers = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ).
" Delete all even numbersLOOP AT lt_numbers INTO DATA(lv_num). IF lv_num MOD 2 = 0. DELETE lt_numbers. ENDIF.ENDLOOP.
" Result: 1, 3, 58. DELETE in LOOP with ASSIGNING (Caution!)
" With ASSIGNING, DELETE is problematic!LOOP AT lt_numbers ASSIGNING FIELD-SYMBOL(<fs_num>). IF <fs_num> MOD 2 = 0. DELETE lt_numbers. " WARNING: <fs_num> now points to invalid data! " Further access to <fs_num> can cause errors. ENDIF.ENDLOOP.
" BETTER: Use INTO or WHEREDELETE lt_numbers WHERE table_line MOD 2 = 0.9. DELETE ADJACENT DUPLICATES - Remove Duplicates
DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Anna` ) ( `Anna` ) ( `Bernd` ) ( `Clara` ) ( `Clara` ) ( `Clara` ) ( `David` )).
" Remove consecutive duplicatesDELETE ADJACENT DUPLICATES FROM lt_names.
" Result: Anna, Bernd, Clara, DavidLOOP AT lt_names INTO DATA(lv_name). WRITE: / lv_name.ENDLOOP.10. DELETE ADJACENT DUPLICATES after SORT
TYPES: BEGIN OF ty_product, category TYPE string, name TYPE string, price TYPE p DECIMALS 2, END OF ty_product.
DATA: lt_products TYPE TABLE OF ty_product.
lt_products = VALUE #( ( category = 'A' name = 'Prod1' price = 10 ) ( category = 'B' name = 'Prod2' price = 20 ) ( category = 'A' name = 'Prod3' price = 15 ) ( category = 'A' name = 'Prod1' price = 10 ) " Duplicate ( category = 'B' name = 'Prod2' price = 25 ) " Partial duplicate).
" IMPORTANT: Sort first!SORT lt_products BY category name.
" Remove duplicates by category and nameDELETE ADJACENT DUPLICATES FROM lt_products COMPARING category name.
" Result: Only unique category/name combinations11. COMPARING ALL FIELDS
" Remove only exact duplicates (all fields equal)SORT lt_products BY category name price.
DELETE ADJACENT DUPLICATES FROM lt_products COMPARING ALL FIELDS.12. USING KEY for Secondary Key
DATA: lt_data TYPE SORTED TABLE OF ty_product WITH UNIQUE KEY category name WITH NON-UNIQUE SORTED KEY by_price COMPONENTS price.
" Remove duplicates by priceDELETE ADJACENT DUPLICATES FROM lt_data USING KEY by_price.13. Delete Range (FROM … TO)
DATA: lt_nums TYPE TABLE OF i.
lt_nums = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ( 7 ) ( 8 ) ).
" Delete rows 3 to 6DELETE lt_nums FROM 3 TO 6.
" Result: 1, 2, 7, 814. DELETE for Different Table Types
| Table Type | INDEX | FROM wa | WITH TABLE KEY | WHERE |
|---|---|---|---|---|
| STANDARD | Yes | Yes (linear) | Yes | Yes |
| SORTED | Yes | Yes (binary) | Yes | Yes |
| HASHED | No | Yes (hash) | Yes | Yes |
" STANDARD TABLE: All variants possibleDATA: lt_standard TYPE STANDARD TABLE OF ty_customer.DELETE lt_standard INDEX 1.DELETE TABLE lt_standard FROM ls_customer.DELETE lt_standard WHERE name = 'Test'.
" HASHED TABLE: No INDEX!DATA: lt_hashed TYPE HASHED TABLE OF ty_customer WITH UNIQUE KEY id." DELETE lt_hashed INDEX 1. " ERROR!DELETE TABLE lt_hashed WITH TABLE KEY id = 1. " OKDELETE lt_hashed WHERE name = 'Test'. " OKComparison: DELETE vs. CLEAR vs. FREE
| Statement | Effect |
|---|---|
DELETE itab ... | Removes specific rows |
CLEAR itab | Removes all rows, keeps memory |
FREE itab | Removes all rows, releases memory |
" Remove specific rowsDELETE lt_data WHERE status = 'X'.
" Remove all rows (keep memory)CLEAR lt_data.
" Remove all rows and release memoryFREE lt_data.Performance Tips
-
WHERE instead of LOOP with DELETE:
" SLOWLOOP AT lt_data INTO ls_data.IF ls_data-status = 'X'.DELETE lt_data.ENDIF.ENDLOOP." FASTERDELETE lt_data WHERE status = 'X'. -
SORT before ADJACENT DUPLICATES:
DELETE ADJACENT DUPLICATESonly detects consecutive duplicates. Sort first! -
Index-based deletion from the end:
" When deleting multiple rows by index: From end to beginningDO 3 TIMES.DELETE lt_data INDEX lines( lt_data ).ENDDO. -
Efficient mass deletion: For deleting many rows,
DELETE ... WHEREis more efficient than individual deletions.
Important Notes / Best Practice
- Check
sy-subrcafterDELETE ... INDEXorDELETE TABLE. DELETE ... WHEREsetssy-subrc = 0even when no row was deleted (butsy-dbcnt = 0).- Sort before
DELETE ADJACENT DUPLICATES. - Be careful when deleting in
LOOP ATwithASSIGNING– the field symbol becomes invalid! - For
HASHED TABLE,DELETE ... INDEXis not possible. - For database tables use
DELETE FROM dbtab. DELETE ADJACENT DUPLICATESonly removes adjacent duplicates.- Use
SORTin combination withDELETE ADJACENT DUPLICATESfor unique lists.