ABAP DELETE for Internal Tables: Delete Rows

Category
ABAP-Statements
Published
Author
Johannes

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 row
ENDLOOP.

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 deleted
    • 4: No matching row found
  • sy-tabix: Unchanged for DELETE ... 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 row
DELETE lt_names INDEX 2.
" Result: Anna, Clara, David
LOOP 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 row
DELETE lt_data INDEX 1.
" Delete last row
DELETE lt_data INDEX lines( lt_data ).
" Result: 20, 30, 40

3. 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 2
ls_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 access
DELETE 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 orders
DELETE lt_orders WHERE status = 'CANCELLED'.
WRITE: / 'Deleted rows:', sy-dbcnt.
WRITE: / 'Remaining rows:', lines( lt_orders ).
" Result: order_id 1, 3, 5 remain

6. Complex WHERE Condition

" Combine multiple conditions
DELETE lt_orders WHERE status = 'OPEN'
AND amount < 120.
" With OR
DELETE lt_orders WHERE status = 'CANCELLED'
OR amount = 0.
" With IN
DATA: 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 numbers
LOOP AT lt_numbers INTO DATA(lv_num).
IF lv_num MOD 2 = 0.
DELETE lt_numbers.
ENDIF.
ENDLOOP.
" Result: 1, 3, 5

8. 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 WHERE
DELETE 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 duplicates
DELETE ADJACENT DUPLICATES FROM lt_names.
" Result: Anna, Bernd, Clara, David
LOOP 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 name
DELETE ADJACENT DUPLICATES FROM lt_products
COMPARING category name.
" Result: Only unique category/name combinations

11. 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 price
DELETE 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 6
DELETE lt_nums FROM 3 TO 6.
" Result: 1, 2, 7, 8

14. DELETE for Different Table Types

Table TypeINDEXFROM waWITH TABLE KEYWHERE
STANDARDYesYes (linear)YesYes
SORTEDYesYes (binary)YesYes
HASHEDNoYes (hash)YesYes
" STANDARD TABLE: All variants possible
DATA: 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. " OK
DELETE lt_hashed WHERE name = 'Test'. " OK

Comparison: DELETE vs. CLEAR vs. FREE

StatementEffect
DELETE itab ...Removes specific rows
CLEAR itabRemoves all rows, keeps memory
FREE itabRemoves all rows, releases memory
" Remove specific rows
DELETE lt_data WHERE status = 'X'.
" Remove all rows (keep memory)
CLEAR lt_data.
" Remove all rows and release memory
FREE lt_data.

Performance Tips

  1. WHERE instead of LOOP with DELETE:

    " SLOW
    LOOP AT lt_data INTO ls_data.
    IF ls_data-status = 'X'.
    DELETE lt_data.
    ENDIF.
    ENDLOOP.
    " FASTER
    DELETE lt_data WHERE status = 'X'.
  2. SORT before ADJACENT DUPLICATES: DELETE ADJACENT DUPLICATES only detects consecutive duplicates. Sort first!

  3. Index-based deletion from the end:

    " When deleting multiple rows by index: From end to beginning
    DO 3 TIMES.
    DELETE lt_data INDEX lines( lt_data ).
    ENDDO.
  4. Efficient mass deletion: For deleting many rows, DELETE ... WHERE is more efficient than individual deletions.

Important Notes / Best Practice

  • Check sy-subrc after DELETE ... INDEX or DELETE TABLE.
  • DELETE ... WHERE sets sy-subrc = 0 even when no row was deleted (but sy-dbcnt = 0).
  • Sort before DELETE ADJACENT DUPLICATES.
  • Be careful when deleting in LOOP AT with ASSIGNING – the field symbol becomes invalid!
  • For HASHED TABLE, DELETE ... INDEX is not possible.
  • For database tables use DELETE FROM dbtab.
  • DELETE ADJACENT DUPLICATES only removes adjacent duplicates.
  • Use SORT in combination with DELETE ADJACENT DUPLICATES for unique lists.