ABAP DELETE para tablas internas: Eliminar filas

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

La sentencia DELETE para tablas internas elimina una o mas filas de una tabla interna. Existen diferentes variantes: eliminar por indice, por clave, con condicion WHERE o eliminar duplicados.

Sintaxis

1. Eliminar fila por indice

DELETE <tabla_interna> INDEX <indice>.

2. Eliminar fila por clave

DELETE TABLE <tabla_interna> FROM <area_trabajo>.
DELETE TABLE <tabla_interna> WITH TABLE KEY <clave> = <valor>.

3. Eliminar multiples filas con WHERE

DELETE <tabla_interna> WHERE <condicion>.

4. Eliminar fila en el LOOP actual

LOOP AT <tabla_interna> ...
DELETE <tabla_interna>. " Elimina fila actual
ENDLOOP.

5. Eliminar duplicados

DELETE ADJACENT DUPLICATES FROM <tabla_interna>
[COMPARING <campos> | ALL FIELDS]
[USING KEY <clave>].

Campos del sistema

Despues de DELETE:

  • sy-subrc:

    • 0: Al menos una fila eliminada
    • 4: No se encontro ninguna fila coincidente
  • sy-tabix: En DELETE ... INDEX sin cambio; de lo contrario indefinido

Ejemplos

1. Eliminar fila por indice

DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Ana` ) ( `Bernardo` ) ( `Clara` ) ( `David` ) ).
" Eliminar segunda fila
DELETE lt_names INDEX 2.
" Resultado: Ana, Clara, David
LOOP AT lt_names INTO DATA(lv_name).
WRITE: / lv_name.
ENDLOOP.

2. Eliminar primera y ultima fila

DATA: lt_data TYPE TABLE OF i.
lt_data = VALUE #( ( 10 ) ( 20 ) ( 30 ) ( 40 ) ( 50 ) ).
" Eliminar primera fila
DELETE lt_data INDEX 1.
" Eliminar ultima fila
DELETE lt_data INDEX lines( lt_data ).
" Resultado: 20, 30, 40

3. Eliminar fila por clave (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 = 'Muller' )
( id = 2 name = 'Schmidt' )
( id = 3 name = 'Weber' )
).
" Eliminar cliente con ID 2
ls_customer-id = 2.
DELETE TABLE lt_customers FROM ls_customer.
IF sy-subrc = 0.
WRITE: / 'Cliente eliminado.'.
ELSE.
WRITE: / 'Cliente no encontrado.'.
ENDIF.

4. Eliminar fila por clave (WITH TABLE KEY)

" Acceso directo por clave
DELETE TABLE lt_customers WITH TABLE KEY id = 3.
IF sy-subrc = 0.
WRITE: / 'Cliente 3 eliminado.'.
ENDIF.

5. Eliminar multiples filas con 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' )
).
" Eliminar todos los pedidos cancelados
DELETE lt_orders WHERE status = 'CANCELLED'.
WRITE: / 'Filas eliminadas:', sy-dbcnt.
WRITE: / 'Filas restantes:', lines( lt_orders ).
" Resultado: order_id 1, 3, 5 quedan

6. Condicion WHERE compleja

" Combinar multiples condiciones
DELETE lt_orders WHERE status = 'OPEN'
AND amount < 120.
" Con OR
DELETE lt_orders WHERE status = 'CANCELLED'
OR amount = 0.
" Con 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. Eliminar fila en LOOP

" ATENCION: DELETE en LOOP esta permitido, pero cuidado con Field-Symbols!
DATA: lt_numbers TYPE TABLE OF i.
lt_numbers = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ).
" Eliminar todos los numeros pares
LOOP AT lt_numbers INTO DATA(lv_num).
IF lv_num MOD 2 = 0.
DELETE lt_numbers.
ENDIF.
ENDLOOP.
" Resultado: 1, 3, 5

8. DELETE en LOOP con ASSIGNING (Cuidado!)

" Con ASSIGNING, DELETE es problematico!
LOOP AT lt_numbers ASSIGNING FIELD-SYMBOL(<fs_num>).
IF <fs_num> MOD 2 = 0.
DELETE lt_numbers.
" ATENCION: <fs_num> ahora apunta a datos invalidos!
" Accesos adicionales a <fs_num> pueden causar errores.
ENDIF.
ENDLOOP.
" MEJOR: Trabajar con INTO o usar WHERE
DELETE lt_numbers WHERE table_line MOD 2 = 0.

9. DELETE ADJACENT DUPLICATES - Eliminar duplicados

DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #(
( `Ana` ) ( `Ana` ) ( `Bernardo` ) ( `Clara` )
( `Clara` ) ( `Clara` ) ( `David` )
).
" Eliminar duplicados consecutivos
DELETE ADJACENT DUPLICATES FROM lt_names.
" Resultado: Ana, Bernardo, Clara, David
LOOP AT lt_names INTO DATA(lv_name).
WRITE: / lv_name.
ENDLOOP.

10. DELETE ADJACENT DUPLICATES despues de 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 ) " Duplicado
( category = 'B' name = 'Prod2' price = 25 ) " Duplicado parcial
).
" IMPORTANTE: Primero ordenar!
SORT lt_products BY category name.
" Eliminar duplicados por category y name
DELETE ADJACENT DUPLICATES FROM lt_products
COMPARING category name.
" Resultado: Solo combinaciones unicas category/name

11. COMPARING ALL FIELDS

" Eliminar solo duplicados exactos (todos los campos iguales)
SORT lt_products BY category name price.
DELETE ADJACENT DUPLICATES FROM lt_products
COMPARING ALL FIELDS.

12. USING KEY para clave secundaria

DATA: lt_data TYPE SORTED TABLE OF ty_product
WITH UNIQUE KEY category name
WITH NON-UNIQUE SORTED KEY by_price COMPONENTS price.
" Eliminar duplicados por precio
DELETE ADJACENT DUPLICATES FROM lt_data
USING KEY by_price.

13. Eliminar rango (FROM … TO)

DATA: lt_nums TYPE TABLE OF i.
lt_nums = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ( 7 ) ( 8 ) ).
" Eliminar filas 3 a 6
DELETE lt_nums FROM 3 TO 6.
" Resultado: 1, 2, 7, 8

14. DELETE para diferentes tipos de tabla

Tipo de tablaINDEXFROM waWITH TABLE KEYWHERE
STANDARDSiSi (lineal)SiSi
SORTEDSiSi (binario)SiSi
HASHEDNoSi (hash)SiSi
" STANDARD TABLE: Todas las variantes posibles
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: Sin 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

Comparacion: DELETE vs. CLEAR vs. FREE

SentenciaEfecto
DELETE itab ...Elimina filas especificas
CLEAR itabElimina todas las filas, mantiene memoria
FREE itabElimina todas las filas, libera memoria
" Eliminar filas especificas
DELETE lt_data WHERE status = 'X'.
" Eliminar todas las filas (mantener memoria)
CLEAR lt_data.
" Eliminar todas las filas y liberar memoria
FREE lt_data.

Consejos de rendimiento

  1. WHERE en lugar de LOOP con DELETE:

    " LENTO
    LOOP AT lt_data INTO ls_data.
    IF ls_data-status = 'X'.
    DELETE lt_data.
    ENDIF.
    ENDLOOP.
    " MAS RAPIDO
    DELETE lt_data WHERE status = 'X'.
  2. SORT antes de ADJACENT DUPLICATES: DELETE ADJACENT DUPLICATES solo reconoce duplicados consecutivos. Ordena primero!

  3. Eliminacion basada en indice desde atras:

    " Al eliminar multiples filas por indice: de atras hacia adelante
    DO 3 TIMES.
    DELETE lt_data INDEX lines( lt_data ).
    ENDDO.
  4. Eliminacion masiva eficiente: Para eliminar muchas filas, DELETE ... WHERE es mas eficiente que eliminaciones individuales.

Notas importantes / Mejores practicas

  • Verifica sy-subrc despues de DELETE ... INDEX o DELETE TABLE.
  • DELETE ... WHERE establece sy-subrc = 0 incluso si no se elimino ninguna fila (pero sy-dbcnt = 0).
  • Ordena antes de DELETE ADJACENT DUPLICATES.
  • Cuidado al eliminar en LOOP AT con ASSIGNING - el Field-Symbol se vuelve invalido!
  • En HASHED TABLE no es posible DELETE ... INDEX.
  • Para tablas de base de datos usa DELETE FROM dbtab.
  • DELETE ADJACENT DUPLICATES solo elimina duplicados adyacentes.
  • Usa SORT en combinacion con DELETE ADJACENT DUPLICATES para listas unicas.