43
Tablas internas Tablas internas 1.- Introducción El objeto de la implementación de las tablas internas en SAP es el de guardar datos de cualquier Base de Datos del sistema con la intención de poder operar con ellos sin la necesidad de tener que ir accediendo a la misma con cada consulta que hagamos. Con ello conseguimos guardar una colección de los datos accedidos en memoria. Con anterioridad a la versión 3.0 de SAP, las tablas internas representaban tablas de bases de datos guardadas internamente en memoria, y las líneas de éstas consistían en estructuras planas. No obstante, y tras la citada versión, dicho tipo de línea pasó a ser arbitrario. El espectro de rangos de tablas internas de arrays de campos elementales se amplió llegando hasta objetos de datos dinámicos altamente complejos donde las líneas o los componentes de éstas podían llegar a ser incluso más tablas internas en sí mismos. La característica más reseñable de las tablas internas puede que sea que para cualquier tipo de línea dado, se puede grabar un número ilimitado 1 de líneas en memoria. Dicho número de líneas es determinado en tiempo de ejecución del programa. Por otro lado, las tablas internas están gestionadas implícitamente por el entorno de ejecución del programa ABAP que la utiliza. Este lenguaje de programación implementa una serie de sentencias que permiten al usuario trabajar con ellas y manejar objetos de datos dinámicos complejos. En la siguiente figura podemos ver un ejemplo sencillo de implementación y uso de una tabla interna: DATA: BEGIN OF i_tab OCCURS 0, nombre(20) TYPE c, direccion(20) TYPE c, telefono(10) TYPE i, dni TYPE i. DATA: END OF i_tab. SELECTION-SCREEN: BEGIN OF BLOCK b1. 1 Por supuesto, el número de líneas de una tabla interna vendrá restringido por la propia memoria física instalada en el sistema. En teoría, una tabla interna puede llegar a alcanzar hasta los dos Gigabytes. De todos modos, la memoria no suele estar reservada en su totalidad al uso de una sola tabla interna. De hecho, en una plataforma de 32 bits no podremos tener tablas internas de más de 500 MB. Con tablas hashed el número de líneas está limitado a dos millones. 1

Dlver Sap Tablas Internas (1)

Embed Size (px)

Citation preview

Page 1: Dlver Sap Tablas Internas (1)

Tablas internas

Tablas internas

1.- IntroducciónEl objeto de la implementación de las tablas internas en SAP es el de guardar datos de cualquier Base de Datos del sistema con la intención de poder operar con ellos sin la necesidad de tener que ir accediendo a la misma con cada consulta que hagamos. Con ello conseguimos guardar una colección de los datos accedidos en memoria.Con anterioridad a la versión 3.0 de SAP, las tablas internas representaban tablas de bases de datos guardadas internamente en memoria, y las líneas de éstas consistían en estructuras planas.No obstante, y tras la citada versión, dicho tipo de línea pasó a ser arbitrario. El espectro de rangos de tablas internas de arrays de campos elementales se amplió llegando hasta objetos de datos dinámicos altamente complejos donde las líneas o los componentes de éstas podían llegar a ser incluso más tablas internas en sí mismos.La característica más reseñable de las tablas internas puede que sea que para cualquier tipo de línea dado, se puede grabar un número ilimitado1 de líneas en memoria. Dicho número de líneas es determinado en tiempo de ejecución del programa.Por otro lado, las tablas internas están gestionadas implícitamente por el entorno de ejecución del programa ABAP que la utiliza. Este lenguaje de programación implementa una serie de sentencias que permiten al usuario trabajar con ellas y manejar objetos de datos dinámicos complejos.En la siguiente figura podemos ver un ejemplo sencillo de implementación y uso de una tabla interna:

DATA: BEGIN OF i_tab OCCURS 0, nombre(20) TYPE c, direccion(20) TYPE c, telefono(10) TYPE i, dni TYPE i.DATA: END OF i_tab.

SELECTION-SCREEN: BEGIN OF BLOCK b1.PARAMETERS: p_nombre(20) TYPE c, p_direcc(20) TYPE c, p_telef(10) TYPE i, p_dni(10) TYPE i.SELECTION-SCREEN: END OF BLOCK b1.

START-OF-SELECTION. i_tab-nombre = p_nombre. i_tab-direccion = p_direcc. i_tab-telefono = p_telef. i_tab-dni = p_dni.

Como puede observarse, su manejo en nada difiere de lo que ya conocemos. En el ejemplo que nos ocupa, el programa – bastante rudimentario, por lo demás-, se limita a pedir unos datos por pantalla y a asignarlos a la tabla interna en el comienzo de la selección.

1 Por supuesto, el número de líneas de una tabla interna vendrá restringido por la propia memoria física instalada en el sistema. En teoría, una tabla interna puede llegar a alcanzar hasta los dos Gigabytes. De todos modos, la memoria no suele estar reservada en su totalidad al uso de una sola tabla interna. De hecho, en una plataforma de 32 bits no podremos tener tablas internas de más de 500 MB. Con tablas hashed el número de líneas está limitado a dos millones.

1

Page 2: Dlver Sap Tablas Internas (1)

Tablas internas

2.- Tipos de tablas internasEl tipo de tabla interna determina cómo es gestionada por el sistema internamente, y cómo es accedida en nuestro programa ABAP. El decidir por qué tipo de tabla interna decantarnos depende del tipo de operaciones que queramos hacer con la ella y la frecuencia con que queramos repetirlas.Según esto, tenemos:

2.1.- Tablas estándarPara la definición de tablas estándar usamos la cláusula STANDARD TABLE. Las líneas individuales de una tabla estándar son gestionadas internamente por un índice lógico. Cuando rellenamos una tabla estándar, se van añadiendo nuevas líneas al final de la misma o en ciertas posiciones. Podemos realizar la lectura bien mediante la especificación de una clave o bien mediante un índice. Si accedemos a través de éste último, la lógica del programa debe conocer en todo momento qué líneas pertenecen al índice especificado.

2.2.- Tablas sortedPara la definición de tablas sorted usaremos la cláusula SORTED TABLE. Como en el caso de las tablas estándar, las tablas sorted son gestionadas por un índice lógico. De todos modos, las tablas sorted difieren de las estándar en que sus entradas están siempre dispuestas en orden ascendente de acuerdo con una clave de la tabla. El acceso a tablas sorted se hace de igual modo que para las tablas estándar.

2.3.- Tablas hashedPara la definición de este tipo de tablas hemos de usar la sentencia HASHED TABLE. En este caso, el orden de las entradas no está gestionado por un índice lógico; en lugar de eso, las entradas de la tabla se encuentran alamcenadas en memoria sin orden concreto, y se manejan a través de un algoritmo hash. La posición de una entrada es calculada directamente a través de una función hash. Con tablas hashed el acceso basado en índices no es posible.

2.4.- Jerarquía de tablas

2

Tablas interna

Tablas indexadas

Tablas estándar Tablas

Tablas hashed

Page 3: Dlver Sap Tablas Internas (1)

Tablas internas

2.5.- Acceso a los diferentes tipos de tablas (cuadro resumen)Tablas

estándarTablas sorted Tablas hashed

Acceso indexado Sí Sí NoAcceso mediante clave Sí Sí SíValores de la clave NON-

UNIQUEUNIQUE o NON-

UNIQUEUNIQUE

Acceso preferible Indexado Mediante clave Sólo mediante clave

2.6.- Tablas genéricasEl tipo genérico ANY TABLE significa que un field-symbol o el parámetro de la interfaz de un procedimiento puede ser una tabla interna de cualquier tipo. Además, los únicos modos de acceso que pueden ser programados son aquellos que se permiten para toda clase de tablas. Concretamente, el acceso indexado no es un caso, toda vez que no es posible realizarlo con tablas hashed. De todos modos, el acceso indexado se puede programar para field-symbols y parámetros de interfaz del tipo genérico TABLE INDEX, porque el tipo actual sólo puede ser una tabla con administración indexada.También podemos hacer uso de las tablas genéricas en la sentencia TYPES para crear tipos de tabla genéricos autodefinidos, como por ejemplo:

TYPES itab TYPE INDEX TABLE OF type.

O

TYPES itab TYPE ANY TABLE OF type

WITH KEY key.

3.- Tipo de líneaEl tipo de línea de una tabla interna es cualquier tipo de dato global o local de la jerarquía tipo ABAP que está determinada por la cláusula TYPE o LIKE. El tipo de línea de un clásica tabla en ABAP es de estructura plana, y una aplicación común para esto es una referencia a la estructura de una tabla de la base de datos. De todos modos, es digno de mención el papel clave que juegan los arrays de tipos elementales o variables de referencia. Finalmente, hemos de mencionar que los tipos de línea que contienen en sí mismos más tablas internas son ideales para el manejo de objetos complejos. Un ejemplo de esto último es la estructura cxtab_control, que necesitamos para la gestión de table controls en la impresión de pantalla.

4.- ClavesUna clave tiene por objeto el identificar las columnas de una tabla. Hay dos clases de clave para las tablas internas: las estándar y las definidas por el usuario. Podemos especificar si la clave es UNIQUE o NON-UNIQUE. Caso de que se defina la tabla interna con una clave UNIQUE, dicha tabla no podrá contener entradas duplicadas. En síntesis, el que tenga un tipo de clave u otro depende sólo del método de acceso.Si una línea tiene un tipo de línea estructurado, su clave por defecto consite en todas sus columnas no numéricas que no contienen referencias externas ni son tablas internas.Sin embargo, si una tabla tiene un tipo de línea elemental, la clave por defecto es la línea entera.

3

Page 4: Dlver Sap Tablas Internas (1)

Tablas internas

Y finalmente, si el tipo de línea de la tabla interna es, precisamente, otra tabla interna, la clave por defecto se queda vacía.Por otro lado, las tablas internas con claves definidas por el usuario reciben el nombre de tablas clave. Cuando definimos la clave, hemos de tener cuidado ya que el orden de los campos de la misma tiene importancia. Debemos tener esto presente si, por ejemplo, intentamos ordenar la tabla de acuerdo con la clave.

5.- Definición de tablas internasPor definición, una tabla interna bien puede ser un tipo de dato o un objeto de dato, por lo que la implementación en ABAP bien podría ser de esta forma:

DATA: BEGIN OF <itab> OCCURS <n>, {<f1>,...,<fn> | INCLUDE STRUCTURE <str>}, END OF <itab>.

O bien de estas otras:

1. TYPES itabtype {TYPE tabkind OF linetype LIKE tabkind OF lineobj} [WITH [UNIQUE NON-UNIQUE] keydef] [INITIAL SIZE n]. 2. TYPES itabtype TYPE RANGE OF type. TYPES itabtype LIKE RANGE OF f. 3. TYPES itabtype {TYPE linetype LIKE lineobj} OCCURS n.

Dependiendo de si la definimos como un objeto de dato o un tipo de dato, respectivamente.En la definición de la tabla interna, hemos de tener en cuenta que además se establece una línea de cabecera o área de trabajo.

5.1.- Definición como objeto de datos

5.1.1.- Sentencia OCCURSPara empezar, hemos de considerar que una tabla interna es, en síntesis, una estructura de datos dinámica. Sus requerimientos de memoria están constituidos por bloques. La localización inicial de memoria (desde ahora la llamaremos área OCCURS), se puede controlar mediante la cláusula “OCCURS n” o “INITIAL SIZE n” al final de la definición de la tabla interna dentro del código de nuestro programa. Una vez que el área occurs se ha llenado, el siguiente bloque que se crea es dos veces más grande que el área recién agotada (con tal de que no sea mayor de 8 Kb). Todos los demás bloques que se crean después tienen un tamaño constante de 12 Kb.No obstante todo lo dicho, también tenemos la posibilidad de dejar que sea el propio sistema el que determine el tamaño del área occurs, haciendo n = 0 (como en el ejemplo que veíamos en la introducción). En este caso, el sistema reserva una pequeña porción de memoria tras la primera sentencia insert o append. Más concretamente, el parámetro n se localiza en un valor comprendido entre 16 y 100 (dependiendo ya del tamaño de la línea).Sólo tiene sentido especificar un valor concreto de n mayor que cero en el caso de que sepamos con exactitud el número de entradas que va a tener nuestra tabla interna.

4

Page 5: Dlver Sap Tablas Internas (1)

Tablas internas

En general y para terminar, consideremos que un OCCURS muy grande supone un gran gasto de recursos del sistema, y que otro muy pequeño implica un proceso muy lento, habida cuenta de que necesita de paginación.

5.1.2.- Estructura de la tabla internaLa forma de la tabla interna se puede definir de dos formas posibles: bien describiendo uno por uno los campos de que va a estar compuesta, o bien pasándole una estructura análoga a otra ya existente previamente en nuestro diccionario de datos:

Le definimos los campos uno a uno:{<f1>,...,<fn>}

O referenciamos una estructura ya existente: INCLUDE STRUCTURE <str>

5.2.- Definición como tipo de datos

5.2.1.- Tipo 1

TYPES itabtype {TYPE tabkind OF linetype LIKE tabkind OF lineobj}

[WITH [UNIQUE NON-UNIQUE] keydef] [INITIAL SIZE n].

Define el tipo itabtype para una tabla interna sin línea de cabecera en un programa con un tipo de tabla tabkind y un tipo de línea linetype (siempre que usemos una referencia TYPE) o el tipo lineobj del objeto referido (si usamos la sentencia LIKE). Las tablas internas sin línea de cabecera consisten en un número de líneas de tabla, que tienen un estructura definida por el tipo de línea.También podríamos definir una clave de tabla. Si no lo hacemos, el sistema crea un tipo de tabla genérica con cualquier clave. Podemos usar tipos genéricos para especificar el tipo de parámetros de subrutina genéricos.Las cláusulas UNIQUE y NON-UNIQUE nos permiten especificar si una tabla de tipo itabtype puede contener dos o más registros con la misma clave o no. Más concretamente:

5.2.1.1.- Tablas estándar:La clave es siempre NON_UNIQUE por defecto. No podemos usar la cláusula UNIQUE con este tipo de tablas.5.2.1.2.- Tablas sorted:No hay opciones por defecto para estas tablas. Si no especificamos las cláusulas UNIQUE o NON-UNIQUE, el sistema crea un tipo de tabla genérica sin ningún atributo único en particular. Podemos usar tipos genéricos para especificar los tipos de parámetros de subrutina genéricos.5.2.1.3.- Tablas hashed:Al igual que en el caso de las Sorted, tampoco hay opciones por defecto para este tipo de tablas. De todos modos, hemos de definir una clave UNIQUE. La cláusula NON-UNIQUE no está permitida.

La cláusula opcional INITIAL SIZE sirve para especificar cuánta memoria deseamos reservar para nuestra tabla al crearla.A continuación vemos unos cuantos ejemplos de implementación de cuanto llevamos explicado hasta ahora:

5

Page 6: Dlver Sap Tablas Internas (1)

Tablas internas

Las siguientes definiciones de tipo implementan tablas usando el tipo de línea STRUC y la clave NAME:

TYPES: BEGIN OF struc, name(10) TYPE c, age TYPE i, END OF struc.

TYPES: tab1 TYPE STANDARD TABLE OF struc WITH DEFAULT KEY, tab2 TYPE SORTED TABLE OF struc WITH NON-UNIQUE KEY name, tab3 TYPE HASHED TABLE OF struc WITH UNIQUE KEY name.

A diferencia de los tipos especificados arriba, los que veremos a

continuación son genéricos. Esto significa que podemos usarlos para especificar el tipo de un parámetro de subrutina genérico, pero no para crear una tabla objeto usando la cláusula DATA. La única excepción a esto es que el sistema nos permite usar un tipo de tabla estándar genérico en una cláusula DATA – la descripción del tipo es completada automáticamente por el sistema de acuerdo con las reglas descritas debajo de la línea DATA.

TYPES: gen_tab1 TYPE STANDARD TABLE OF struc, gen_tab2 TYPE SORTED TABLE OF struc WITH KEY name gen_tab3 TYPE HASHED TABLE OF struc.

El siguiente ejemplo muestra la definición de una tabla sorted usando una referencia LIKE a la estructura del diccionario de datos SFLIGHT: TYPES: fltab LIKE SORTED TABLE OF sflight WITH NON-UNIQUE KEY carrid connid fldate.

5.2.2.- Tipo 2

TYPES itabtype TYPE RANGE OF type.TYPES itabtype LIKE RANGE OF f.

A todos los efectos crea un tipo de tabla stándar. El tipo de línea es una estructura, que se configura del siguiente modo:

SIGN(1) TYPE C OPTION(2) TYPE C LOW TYPE type or LIKE fHIGH TYPE type or LIKE f

5.2.3.- Tipo 3

TYPES itabtype {TYPE linetype LIKE lineobj} OCCURS n.

Define el tipo itabtype como el tipo para una tabla estándar sin línea de cabecera. La clave es la que viene por defecto para las tablas internas.Este tipo tiene el mismo efecto que la siguiente definición:

TYPES itabtype {TYPE STANDARD TABLE OF linetype LIKE STANDARD TABLE OF lineobj} WITH DEFAULT KEY INITIAL SIZE n.

Nota: El nombre de un tipo puede tener hasta 30 caracteres, y sólo puede construirse con letras, cifras y el carácter "_". No está permitido que conste sólo de cifras, y los signos especiales como

6

Page 7: Dlver Sap Tablas Internas (1)

Tablas internas

la diéresis tampoco deben usarse. Existen, además de éstos, otros caracteres especiales para objetivos internos que no deberían usarse en los programas de aplicaciones. SPACE es un nombre reservado y tampoco puede usarse. Y en una sentencia no debería utilizarse ningún campo cuyo nombre sea idéntico al de uno de los parámetros adicionales de la palabra clave introductoria (Por ejemplo: PERFORM SUB USING CHANGING.). Recomendaciones para nombrar un tipo:

1. Utilicar siempre como primer carácter una letra. 2. El carácter de subrayado resulta útil para estructurar nombres que van juntos (z.B. NEW_PRODUCT).

6.- Trabajando con tablas internasCuando trabajamos con tablas internas podemos distinguir entre el acceso a líneas individuales de la misma o el acceso a toda la tabla. Para empezar, comenzaremos con el tratamiento de acceso a líneas individuales. En este contexto, podemos distinguir, así mismo, entre acceso mediante clave y acceso indexado. En este apartado sólo se pretende presentar los aspectos más importantes de ambos, sin entrar en demasiados detalles; no obstante, y si nos interesa, siempre podemos encontrar mucha más información en la documentación on line que SAP nos ofrece.

6.1.- Acceso indexadoComo su propio nombre indica, este tipo de acceso direcciona líneas mediante un índice interno y sólo es posible para tablas estándar y sorted. Tras ser accedida la tabla, la variable de entorno sy-tabix contiene siempre el valor del índice de la línea accedida.Aunque la indexada, por lo general, resulta ser la forma más rápida de acceder a la línea de una tabla interna, resulta que desde que hay una referencia interna directa, también puede resultar que no sea la más óptima, sobre todo cuando trabajamos con datos de una tabla de la base de datos del diccionario. Cuando trabajamos en esta forma de acceso, el sistema debe saber en todo momento la asignación habida entre el índice y el contenido de la línea de la tabla interna, si bien con el acceso mediante clave primaria el contenido de la línea interna es evaluado previamente. Debido a ello, nos encontramos con que el acceso mediante clave parece ser más recomendable para la mayoría de las aplicaciones que manejan datos de elementos del diccionario ABAP.

6.2.- Acceso mediante clave primaria En el acceso mediante clave a tablas estándar, el sistema realiza una búsqueda

lineal mediante el valor de la clave. El tiempo medio de búsqueda es directamente proporcional al número de líneas de la tabla interna.

En el mismo acceso pero a tablas sorted, el entorno de ejecución del programa realiza una búsqueda binaria para el valor clave. El tiempo medio de búsqueda es

directamente proporcional al log2 del número de líneas. Y finalmente, con el mismo acceso pero a tablas hashed, el sistema calcula la

posición de la línea mediante el valor de la clave aplicando una función hash. En este caso, el tiempo de búsqueda es independiente del número de líneas y se mantiene siempre constante.

En el siguiente gráfico podemos observar la media de tiempos de acceso para el tipo de clave primaria. En abscisas tenemos el número de líneas, mientras que en ordenadas el tiempo de acceso en μs. Llama la atención cómo sube éste en las tablas estándar conforme también lo hace el número de líneas a tratar.

7

Page 8: Dlver Sap Tablas Internas (1)

Tablas internas

Tipo tabla\No.líneas 10 100 1000 10000Tabla estándar 20 μs 64 μs 530 μs 5300 μs

Tabla sorted 18 μs 21 μs 28 μs 31 μs

Tabla hashed 17 μs 17 μs 17 μs 17 μs

6.3.- ConclusiónAsí pues, dependiendo del propósito de la tabla interna dentro de nuestro programa ABAP (número de líneas, frecuencia de acceso, etc.) deberíamos siempre usar el tipo de tabla adecuado. Por ejemplo, para tablas pequeñas con hasta cien líneas, a las que se accede muy esporádicamente mediante clave primaria, la implementación del tipo estándar parece la más adecuada. Sin embargo, tablas grandes sin entradas duplicadas a las que queramos acceder sólo mediante clave primaria, bien podrían estar implementadas como tablas hashed. Si se requiere que la tabla permanezca ordenada durante todo el tiempo de ejecución, se recomienda el uso de tablas sorted2.

7.- Operaciones con tablas internas

7.1.- Sentencia INSERT1. INSERT [wa INTO INITIAL LINE INTO] itab [INDEX idx].2. INSERT [wa INTO INITIAL LINE INTO] TABLE itab. 3. INSERT LINES OF itab1 [FROM idx1] [TO idx2] INTO itab2 [INDEX idx3]. 4. INSERT LINES OF itab1 [FROM idx1] [TO idx2] INTO TABLE itab2.

2 Si ordenamos una tabla estándar con el comando SORT y hacemos una búsqueda binaria con la cláusula BINARY SEARCH en la sentencia READ TABLE, estaremos obteniendo los mismos resultados en tiempo de ejecución que para las tablas sorted.

8

Page 9: Dlver Sap Tablas Internas (1)

Tablas internas

7.1.1.- INSERT [wa INTO INITIAL LINE INTO] itab [INDEX idx].

Esta sentencia inserta un nueva línea en la tabla interna usando una especificación implícita o explícita de índice. Esta variante de la sentencia insert sólo podemos usarla con tablas indexadas (estándar o sorted).Si usamos la cláusula “wa INTO” el contenido del work area “wa” es insertado como una nueva línea. Si los respectivos tipos de wa y de la tabla interna fuesen incompatibles, el contenido del primero se transfieren de acuerdo con la lógica de proceso de la sentencia MOVE.Si usamos la cláusula INITIAL LINE INTO, insertaremos una línea en la tabla, que contendrá valores apropiados de acuerdo con los tipos de que conste dicha tabla.Si no especificamos nada antes de itab, la nueva línea se toma de la línea de cabecera de la tabla interna.Por otro lado, usamos INDEX idx para especificar el índice de la tabla antes del que la nueva línea va a ser insertada.Si estamos insertando líneas en una tabla indexada usando un LOOP, podemos omitir la especificación del índice, ya que la línea a insertar se introducirá antes de la línea activa en ese momento de la sentencia LOOP; es lo que se llama especificación indexada implícita). Hemos de tener en cuenta, así mismo, que la inserción de líneas en una tabla dentro de una sentencia LOOP sólo tiene efecto en la siguiente pasada de la esta instrucción. Si la tabla en la que estamos introduciendo líneas es del tipo SORTED, ésta ha de estar correctamente ordenada después de terminar de insertar líneas, de lo contrario se producirá un error.El código de retorno devuelve los siguientes valores, según el caso:

o SY-SUBRC = 0 La línea se insertó con éxito.o SY-SUBRC = 4 El índice especificado es demasiado grande. La

línea no se insertó.Ahora vamos a ver el siguiente ejemplo en el que insertamos valores dentro de una tabla de números enteros:

DATA: VALUE TYPE I, ITAB TYPE I OCCURS 100 WITH HEADER LINE. ITAB = 5. VALUE = 36. INSERT ITAB INDEX 1. INSERT VALUE INTO ITAB INDEX 2. INSERT INITIAL LINE INTO ITAB INDEX 2.

7.1.2.- INSERT [wa INTO INITIAL LINE INTO] TABLE itab.

Inserta valores en una tabla interna con una clave, que es tomada, precisamente, del work area. Si indicamos explícitamente dicho work area, hemos de asegurarnos de que es compatible con el tipo de línea de la tabla donde queremos insertar.A diferencia de la sentencia anterior, ésta puede usarse con cualquier tipo de tabla.Si la tabla donde pretendemos insetar tiene la cláusula UNIQUE KEY, el sistema ignora cualquier entrada duplicada.La forma en la que el sistema inserta nuevas entradas en la tabla depende del tipo que sea ésta:

Tablas estándar: la nueva entrada es añadida al final de la tabla. La inserción genérica es similar a usar la sentencia APPEND.

Tablas sorted: la nueva entrada es colocada en el lugar apropiado, que es determinado por la clave de la tabla. Como se ha dicho con

9

Page 10: Dlver Sap Tablas Internas (1)

Tablas internas

anterioridad, el valor de la clave es tomado directamente del wa o de la línea de cabecera de la tabla. Si la clave es NON-UNIQUE, la entrada es colocada la primera en la lista de entradas duplicadas. El punto de inserción se determina internamente usando una búsqueda binaria.

Tablas hashed: la nueva entrada es colocada en la administración hash interna de la tabla de acuerdo con la clave de la misma. Como en el anterior caso, los valores de la clave se toman del wa especificado o de la línea de cabecera de la tabla. El tiempo de ejecución requerido permanece constante, debido a que no depende del número de entradas de la tabla. La clave ha de ser única.

Los códigos de retorno devuelven los siguientes valores:o SY-SUBRC = 0 Entrada añadida a la tabla.o SY-SUBRC = 4 La entrada no ha podido ser añadida a la tabla,

debido a que duplica una entrada existente y la tabla está difinida como UNIQUE KEY.

Como ejemplo, vamos a implementar una tabla sorted, ordenada por nombre y edad:

TYPES: BEGIN OF PERSON, NAME(10) TYPE C, AGE TYPE I, END OF PERSON. DATA: P TYPE PERSON, PTAB TYPE SORTED TABLE OF PERSON WITH UNIQUE KEY NAME AGE. P-NAME = 'Steve'. P-AGE = 20. INSERT P INTO TABLE PTAB.P-NAME = 'Andy'. P-AGE = 20. INSERT P INTO TABLE PTAB.P-NAME = 'Steve'. P-AGE = 17. INSERT P INTO TABLE PTAB.P-NAME = 'Andy'. P-AGE = 20. INSERT P INTO TABLE PTAB.

7.1.3.- INSERT LINES OF itab1 [FROM idx1] [TO idx2]

INTO itab2 [INDEX idx3]Inserta la tabla interna itab1 o parte de la misma dentro de la tabla interna itab2. Esta sentencia viene a equivaler a insertar línea por línea dentro de un bucle LOOP.En el índice idx3 especificamos la posición del índice de la tabla antes de la cual queremos insertar la entrada en itab2. Este parámetro no puede ser del tipo HASHED o ANY TABLE, debido a que estas tablas no tienen definidas operaciones indexadas.Volvemos a repetir que si estamos insertando en un LOOP, podemos omitir idx3.Podemos restringir el número de líneas tomadas de la tabla fuente usando FROM idx1 TO idx2. Si omitimos el primero (idx1), la selección comienza en la primera línea de la tabla interna; de manera análoga, si lo que omitimos es idx2, la selección terminará en la última línea de la tabla fuente. Esto quiere decir que si omitimos ambos parámetros, será la totalidad de la tabla fuente la que se copie en la tabla destino.Vamos ahora a ver el siguiente ejemplo consistente en la introducción de una tabla de nombres en otra:

TYPES NAME(10) TYPE C. DATA: NAME_TAB_1 TYPE STANDARD TABLE OF NAME WITH NON-UNIQUE DEFAULT KEY INITIAL SIZE 5, NAME_TAB_2 TYPE STANDARD TABLE OF NAME WITH NON-UNIQUE DEFAULT KEY INITIAL SIZE 5.

10

Page 11: Dlver Sap Tablas Internas (1)

Tablas internas

APPEND 'Alice' TO NAME_TAB_1. APPEND 'Martha' TO NAME_TAB_1. APPEND 'Ruth' TO NAME_TAB_1. APPEND 'Harry' TO NAME_TAB_2. APPEND 'Walter' TO NAME_TAB_2. INSERT LINES OF NAME_TAB_1 FROM 2 INTO NAME_TAB_2 INDEX 2.

7.1.4.- INSERT LINES OF itab1 [FROM idx1] [TO idx2]

INTO TABLE itab2.

Inserción genérica de la tabla interna itab1 o parte de la misma dentro de la tabla interna itab2. A diferencia del anterior caso, este tipo de inserción se puede usar con cualquier tipo de tabla origen y destino.

La forma en que las líneas se toman de la tabla origen itab1 y son insertadas en la tabla itab2 depende, fundamentalmente, del tipo de tabla que sea itab2.Recomendaciones para la implementación:

o Hemos de evitar en lo posible asignaciones innecesarias en la línea de cabecera. Cuando podamos, debemos usar sentencias que tengan un wa explícito. Por ejemplo, “APPEND wa TO itab” es mucho más simple y rápido que “itab = wa. APPEND itab.” Podemos hacer análogas observaciones para las cláusulas COLLECT e INSERT.

o Cuando añadimos una línea a un índice de tabla, el mantenimiento de éste va en detrimento del tiempo de acceso e inserción. Por ejemplo, para la inserción de una línea dentro de una tabla interna de 100 bytes de tamaño y 200 entradas, necesitaremos alrededor de 90 msn (microsegundos estándar) .

o A la hora de insertar tablas internas o parte de ellas dentro de otras, la sentencia INSERT LINES OF … resulta mucho más eficiente que ir añadiendo líneas una a una dentro de un bucle LOOP.

7.2.- Sentencia COLLECTCOLLECT <wa> INTO <itab>.

Suma el contenido de la línea de cabecera en la tabla que estemos tratando. La tabla en cuestión ha de tener un tipo de línea plano, y todos los campos que no pertenzcan a la clave de la tabla han de ser tipo numérico – lógicamente-, para poder sumarlos.El sistema, al insertar la nueva línea comprueba si existe en la tabla una entrada que se corresponda con la clave primaria; de no haberla, esta sentencia tiene el mismo efecto que la de insertar líneas nuevas. Si ya hay una entrada que coincida con la clave, COLLECT no realiza el APPEND correspondiente, pero no así suma los contenidos de los campos numéricos habidos en el work area a los campos de idénticos tipos de la entrada existente.En general, esta sentencia se debería usar sólo en el caso de que el usaurio desée realizar sumatorias con los campos de una tabla, debido a que esta instrucción es manifiestamente más lenta que READ, INSERT o MODIFY.Las líneas se suman a las tablas internas tal y como se explica a continuación:

o Tablas estándar :Si la sentencia COLLECT es la primera en empezar a rellenar la tabla, el sistema crea una administración hash temporal para identificar las entradas existentes en la tabla. Dicha administración hash permanece activa hasta que otra sentencia cambia los contenidos de los campos clave o la secuencia de las

11

Page 12: Dlver Sap Tablas Internas (1)

Tablas internas

líneas de la tabla interna. Después, el sistema encuentra entradas existentes mediante una búsqueda lineal. El tiempo de ejecución de esta operación se incrementa linealmente en función del número de entradas exitentes en la tabla. La variable de sistema SY-TABIX contiene el índice de la línea insertada o modificada en la sentencia COLLECT.o Tablas sorted :En este caso, el sistema realiza una búsqueda binaria para localizar las entradas existentes. El tiempo de ejecución de esta operación se incrementa logarítmicamente con el número de líneas existentes. La variable de sistema SY-TABIX contiene el índice de la línea insertada o modificada en la sentencia COLLECT.´o Tablas hashed :El sistema encuentra las líneas existentes utilizando un algoritmo hash de la tabla interna. Tras la sentencia COLLECT, la variable de sistema SY-TABIX contiene el valor 0, debido a que las tablas hashed no tiene índice lineal.

Veamos el siguiente ejemplo:

DATA: BEGIN OF LINE,        COL1(3) TYPE C,        COL2(2) TYPE N,        COL3    TYPE I,      END OF LINE.

DATA ITAB LIKE SORTED TABLE OF LINE           WITH NON-UNIQUE KEY COL1 COL2.

LINE-COL1 = 'abc'. LINE-COL2 = '12'. LINE-COL3 = 3.COLLECT LINE INTO ITAB.WRITE / SY-TABIX.

LINE-COL1 = 'def'. LINE-COL2 = '34'. LINE-COL3 = 5.COLLECT LINE INTO ITAB.WRITE / SY-TABIX.

LINE-COL1 = 'abc'. LINE-COL2 = '12'. LINE-COL3 = 7.COLLECT LINE INTO ITAB.WRITE / SY-TABIX.

LOOP AT ITAB INTO LINE.  WRITE: / LINE-COL1, LINE-COL2, LINE-COL3.ENDLOOP.

Cuya salida sería:

1

         2

         1

abc 12 10

def 34           5

Este ejemplo rellena una tabla sorted. Las primeras dos sentencias COLLECT funcionancomo sentencias INSERT normales y corrientes. En la tercera sentencia

12

Page 13: Dlver Sap Tablas Internas (1)

Tablas internas

COLLECT, la primera línea de ITAB se modifica. Con el siguiente diagrama vemos los tres pasos gráficamente:

7.3.- Lectura de tablas internasPara la lectura de una única línea de una tabla interna, hemos de usar la sentencia:

READ TABLE <itab> <key> <result>.

Para que ducha sentencua sea válida para cualquier tipo de tabla, debemos especificar la entrada usando la calve y no el índice. La parte <result> puede especificar alguna opción más de procesamiento para la línea que se va a leer.Si el sistema encuentra una entrada, pone a cero la variable de sistema SY-SUBRC, de lo contrario, la pone a cuatro. Si la tabla que se está tratando es del tipo indexado, SY-TABIX contiene el índice de la línea leída. Si la tabla tiene la cláusula NON-UNIQUE KEY y tiene entradas duplicadas, sólo se lee la primera línea.

7.3.1.- Especificación de la clave de búsquedaÉsta puede ser, bien la clave de la tabla o bien cualquier otra:

o Clave de la tabla : Para usar la clave primaria de la tabla, hemos de usar la siguiente sentencia:

READ TABLE <itab> FROM <wa> <result>.

o ésta otra:

READ TABLE <itab> WITH TABLE KEY <k1> = <f 1> ... <k n> = <f n> <result>.

En el primer caso, <wa> debe ser un work area compatible con el tipo de linea de <itab>. Los valores de los campos de la clave se toman de los componentes correspondientes del work area.En el segundo caso, debemos especificar los valores de cada campo de la clave explícitamente. Si no sabemos alguno de los nombres de los campos clave hasta el tiempo de ejecución, podemos especificarlo como el contenido de un campo <n i > utilizando la forma (<n i >) = <f i >. Si el tipo

13

Page 14: Dlver Sap Tablas Internas (1)

Tablas internas

de datos de <f i > no es compatible con los campos de la clave, el sistema los convierte automáticamente.El sistema realiza la búsqueda de la siguiente forma:

Tablas estándar Búsqueda lineal, donde el tiempo de ejecución es directamente proporcional al número de entradas de la tabla.

Tablas sorted Búsqueda binaria, donde el tiempo de ejecución está en proporción logarítmica al número de entradas de la tabla.

Tablas hashed La entrada se encuentra usando un algoritmo hash de la tabla interna. Como ya se ha dicho anteriormente, el tiempo de ejecución en estos casos es indpendiente del número de entradas.

o Uso de otra clave : Para hacer uso de una clave que no sea la de la tabla interna, hemos de introducir el parámetro <key> como se explica:

READ TABLE <itab> WITH KEY = <f> <result>.

o de esta otra forma:

READ TABLE <itab> WITH KEY <k1> = <f1> ... <k n> = <f n> <result>.

En el primer caso, la línea de la tabla interna en su totalidad se usa como calve de búsqueda. Los contenidos de la línea de la tabla entera se comparan con los contenidos del campo <f>. Si <f> no es compatible con el tipo de línea de la tabla, el valor se convierte al tipo de línea de la tabla. La búsqueda por clave nos permite encontrar entradas en tablas internas que no tienen un tipo de línea estructurado, es decir, tienen un tipo de línea que consiste en un único campo o en un tipo de tabla interna. En el segundo caso, la clave de búsqueda puede consistir en cualquier de los campos de la tabla <k 1 >...<k n >. Si no sabemos alguno de los nombres de los campos clave hasta el tiempo de ejecución, podemos especificarlo como el contenido de un campo <n i > utilizando la forma (<n i >) = <f i >. Si el tipo de datos de <f i > no es compatible con los campos de la clave, el sistema los convierte automáticamente. Podemos restringir la búsqueda a campos parciales especificando el desplazamiento y la longitud.La búsqueda es lineal para todo tipo de tablas. El tiempo de ejecución, en este caso, y siendo la búsqueda lineal, va en proporción directa al número de entradas de la tabla.

7.3.2.- Especificación de la opción de procesamientoPodemos especificar una opción que contenga cuanto queremos que el sistema haga con la entrada recién encontrada. Para ello exiten dos maneras:

o Mediante el work area : Podemos escribir la entrada de tabla leída dentro de un work area con la cláusula <result>:

READ TABLE <itab> <key> INTO <wa> [COMPARING <f1> <f 2> ...                          |ALL FIELDS]                          [TRANSPORTING <f1> <f 2> ...                              |ALL FIELDS                              |NO FIELDS].

14

Page 15: Dlver Sap Tablas Internas (1)

Tablas internas

Si no usamos los parámetros COMPARING o TRANSPORTING, los contenidos de la línea de la tabla debe ser convertible al tipo de dato del work area <wa>. Si especificamos dichos parámetros, tanto el tipo de línea como el wa han de ser compatibles. Siempre deberíamos usar un work area que sea compatible con el tipo del línea pertinente de la tabla interna.Si usamos el parámetro COMPARING, los campos de la tabla especificados <fi> del tipo de línea estructurado son comparados con los campos correspondientes del work area antes de ser transportados. Si hacemos uso de la opción ALL FIELDS, el sistema compara todos los componentes. Si el sistema encuentra una entrada con la clave especificada <key> y si los contenidos de los campos comparados son los mismos, SY-SUBRC pasa a contener el valor 0. Si el contenido de los campos comparados no son los mismos, SY-SUBRC devuelve el valor 2. Y por último, si el sistema no encuentra ninguna entrada, esta variable de sistema contiene el valor 4. Si el sistema encuantra una entrada, la copia en el work area sin importar el resultado de la comparación.Si usamos la opción TRANSPORTING, podemos especificar los campos de la tabla del tipo de línea estructurado que queremos transportar al work area. Si definimos ALL FIELDS sin TRANSPORTING, se transportarán todos los contenidos de todos los campos. Si escribimos NO FIELDS, no se transportará ningún campo. Por último, debemos señalar que especificar el work area con TRANSPORTING NO FIELDS es innecesario, y no debería usarse.En ambos casos (COMPARING y TRANSPORTING), podemos definir un campo <f i > dinámicamente como el contenido de un campo <n i > en la forma (<n i >). Si <n i > está vacío cuando se ejecuta la sentencia, éste se ignora. Podemos restringir la búsqueda a campos parciales especificando el desplazamiento y la longitud.

o Mediante un Field-Symbol : Podemos asignar la entrada de tabla leída a un filed-symbol definiendo <result> de la siguiente manera:

READ TABLE <itab> <key> ASSIGNING <FS>.

Después de la sentencia READ, el field-symbol apunta a la línea de la tabla. Si éste es de tipo estructurado, deberíamos declarar el mismo tipo para el field-symbol al declararlo. Esto nos permite direccionar los componentes del field-symbol. Si no especificamos el tipo estáticamente, debemos usar más field-symbols y la técnica de asignación de componentes de estructuras para direccionarlas.Veamos, ahora, los siguientes ejemplos:

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

LINE-COL1 = 2. LINE-COL2 = 3.

15

Page 16: Dlver Sap Tablas Internas (1)

Tablas internas

READ TABLE ITAB FROM LINE INTO LINE COMPARING COL2.

WRITE: 'SY-SUBRC =', SY-SUBRC.SKIP.WRITE: / LINE-COL1, LINE-COL2.

La salida que genera el programa es:

SY-SUBRC =    2

         2        4

El programa rellena una tabla hashed con una lista de números cuadrados.El work area LINE, que es compatible con el tipo de línea, se rellena con los números 2 y 3. La sentencia READ lee la línea de la tabla en la que el campo clave COL1 tiene el mismo valor que en el work area y lo copia en éste. SY-SUBRC toma el valor 2,

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE SORTED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

CLEAR LINE.

READ TABLE ITAB WITH TABLE KEY COL1 = 3                 INTO LINE TRANSPORTING COL2.

WRITE:   'SY-SUBRC =', SY-SUBRC,       / 'SY-TABIX =', SY-TABIX.SKIP.WRITE: / LINE-COL1, LINE-COL2.

Y su salida es:

SY-SUBRC =    0SY-TABIX =    3

         0        9

El programa rellena una tabla ordenada con una lista de números cuadrados también. La sentencia READ lee la línea de la tabla en la que el campo clave COL1 tiene el mismo valor que en el work area y lo copia en éste. Sólo el contenido de COL2 es copiado al work area LINE. SY-SUBRC se pone a cero, y SY-TABIX en 3, porque ITAB es un índice de la tabla.

16

Page 17: Dlver Sap Tablas Internas (1)

Tablas internas

DATA: BEGIN OF LINE,        COL1 TYPE I,        COL2 TYPE I,      END OF LINE.

DATA ITAB LIKE SORTED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.  INSERT LINE INTO TABLE ITAB.ENDDO.

READ TABLE ITAB WITH KEY COL2 = 16  TRANSPORTING NO FIELDS.

WRITE:   'SY-SUBRC =', SY-SUBRC,       / 'SY-TABIX =', SY-TABIX.

Y la salida es:

SY-SUBRC =    0SY-TABIX =       4

El programa rellena una tabla sorted con una lista de números cuadrados. La sentencia READ lee la línea de la tabla en la que el campo clave tiene el valor 16. No usa la clave de la tabla. No se copia ningún campo al work area ni se asigna a ningún field-symbol. En lugar de eso, son las variables de sistema SY-SUBRC (con valor 0, ya que se encontró la línea) y SY-TABIX (con valor 4) los únicos que toman algún valor.

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

FIELD-SYMBOLS <FS> LIKE LINE OF ITAB.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

READ TABLE ITAB WITH TABLE KEY COL1 = 2 ASSIGNING <FS>.

<FS>-COL2 = 100.

LOOP AT ITAB INTO LINE.  WRITE: / LINE-COL1, LINE-COL2.ENDLOOP.

Y la salida de este programa es:

         1        1         2      100         3        9         4       16

17

Page 18: Dlver Sap Tablas Internas (1)

Tablas internas

El programa rellena una tabla hashed con una lista de números cuadrados, como en los casos anteriores. La sentencia READ lee la línea de la tabla en la que el campo clave COL1 tiene el valor 2, y lo asigna al field-symbol <fs>. El programa, entonces, asigna el valor 100 al componente COL2 de <fs>. Esto también cambia el campo de la tabla correspondiente.

7.4.- Modificación de líneasPara cambiar una única línea de una tabla interna, debemos usar la sentencia MODIFY. También podemos hacer uso de la clave de la tabla para encontrar y cambiar una línea usando su clave, o encontrar y cambiar un conjunto de líneas que satisfagan cierta condición. Si la tabla está definida con la cláusula NON-UNIQUE KEY y hay entradas duplicadas, sólo se modificará la primera entrada.

7.4.1.- Cambio de una línea mediante la clave de la tablaPara modificar una línea, hemos de usar la siguiente sentencia:

MODIFY TABLE <itab> FROM <wa> [TRANSPORTING <f1> <f 2> ...].

El work area <wa>, que debe ser compatible con el tipo de línea de la tabla interna, juega un doble papel en esta sentencia. No sólo se utiliza para cambiar la línea que se desea cambiar, sino que también contine los nuevos valores. El sistema busca en la tabla interna la línea cuya clave de tabla coincida con los campos clave de <wa>.Las búsquedas en los diferentes tipos de tabla son de la mísma índole que las explicadas hasta ahora; a saber: búsqueda lineal, binaria y algoritmo hash para tablas estándar, sorted y hashed, respectivamente, con las características anteriormente descritas.De igual forma, las variables de sistema cambian de valor de manera idéntica a la descrita hasta ahora.

7.4.2.- Cambiar varias líneas mediante una condiciónPara cambiar una o más líneas mediante una condición, hemos de utilizar la siguiente sentencia:

MODIFY <itab> FROM <wa> TRANSPORTING <f1> <f 2> ... WHERE <cond>.

Esto procesa todas las líneas que satisfagan la condición lógica <cond>. Ésta puede consistir en más de una comparación. En cada una de ellas, el primer operando debe ser un componente de la estructura de la línea. Si las líneas de la tabla no están estructuradas, el primer operando también puede ser la expresión TABLE LINE. La comparación entonces se aplica a la línea entera.El work area <wa>, que ha de ser compatible con el tipo de línea de la tabla interna, contiene ahora los nuevos valores, que se asignarán a la línea pertinente de la tabla mediante el parámetro TRANSPORTING. A diferencia de la sentencia MODIFY de arriba, en este caso TRANSPORTING no es opcional. Además, sólo podemos modificar los campos clave de la tabla interna si ésta es estándar. Con tal de que una sola línea sea cambiada, SY-SUBRC devuelve el valor 0, en caso contrario, 4.Veamos los siguientes ejemplos:

18

Page 19: Dlver Sap Tablas Internas (1)

Tablas internas

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

LINE-COL1 = 2. LINE-COL2 = 100.

MODIFY TABLE ITAB FROM LINE.

LOOP AT ITAB INTO LINE.  WRITE: / LINE-COL1, LINE-COL2.ENDLOOP.

Que genera la siguiente salida:

         1        1         2      100         3        9         4       16

Como podemos comprobar, el programa rellena una tabla hashed, y modifica el valor pertinente en la sentencia MODIFY (en este caso el 2).Aquí tenemos otro programa:

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.LINE-COL1 = SY-INDEX.LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

LINE-COL2 = 100.

MODIFY ITAB FROM LINE TRANSPORTING COL2WHERE ( COL2 > 1 ) AND ( COL1 < 4 ).

LOOP AT ITAB INTO LINE.WRITE: / LINE-COL1, LINE-COL2.ENDLOOP.

Cuya salida es:

         1        1         2      100         3      100         4       16

19

Page 20: Dlver Sap Tablas Internas (1)

Tablas internas

Este último rellena la tabla hashed, en primer término, para después modificarla según la condición ( COL2 > 1 ) AND ( COL1 < 4 ).

7.5.- Borrado de líneasDeberemos usar la sentencia DELETE para borrar una línea de una tabla interna. También podemos hacer uso de la clave de la tabla para encontrar y borrar la línea que nos interese, o un conjunto de ellas que satisfagan una condición, o un conjunto de entradas duplicadas. Si la tabla está definida con la cláusula NON-UNIQUE KEY y hay entradas duplicadas, sólo se borrará la primera.

7.5.1.- Borrar una línea mediante la clave de tablaDebemos usar la siguiente sentencia:

DELETE TABLE <itab> FROM <wa>.

O:

DELETE TABLE <itab> WITH TABLE KEY <k1> = <f 1> ... <k n> = <f n>.

En el primer caso, <wa> debe ser compatible con el tipo de línea de <itab>. Los calores de los campos de la clave se toman de los componentes correspondientes del work area.En el segundo caso, hemos de señalar los valores de cada campo explícitamente. Si no sabemos alguno de los nombres de los campos clave hasta el tiempo de ejecución, podemos especificarlo como el contenido de un campo <n i > utilizando la forma (<n i >) = <f i >. Si los tipos de datos de <fi> no son compatibles con los campos de la clave, el sistema los convierte automáticamente.La búsqueda en los diferentes tipos de tablas se realizan como ya se ha comentado en apartados anteriores y los valores de las variables de sistema se establecen conforme a lo anteriormente descrito, también.

7.5.2.- Borrar varias líneas mediante una condiciónPara borrar varias líneas de una tabla bastará usar la siguiente sentencia:

DELETE <itab> WHERE <cond>.

<cond> puede ser, bien una sola condición, o bien varias.

7.5.3.- Borrar entradas duplicadas adyacentesUsaremos la siguiente sentencia:

DELETE ADJACENT DUPLICATE FROM <itab>                                   [COMPARING <f1> <f 2> ...                                              |ALL FIELDS].

Las entradas están duplicadas si satisfacen uno de los siguientes criterios de comparación:

o Sin el parámetro COMPARING, los contenidos de los campos de la clave de la tabla deben ser idénticos en ambas líneas.

20

Page 21: Dlver Sap Tablas Internas (1)

Tablas internas

o Si usamos el parámetro COMPARING <f1> <f 2> ... los contenidos de los campos especificados <f 1 > <f 2 > ... deben ser idénticos, también, para ambas líneas.

o Y si usamos el parámetro COMPARING ALL FIELDS los contenidos de todos los campos de ambas líneas deben ser iguales.

Podemos usar esta sentencia para borrar todas las entradas duplicadas de la tabla interna si ésta se encuentra ordenada por el criterio de comparación especificado.La variable de sistema SY-SUBRC pasa a tener el valor 0 con tal de que una sola línea haya sido borrada.Veamos ahora algunos ejemplos:

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.LINE-COL1 = SY-INDEX.LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

LINE-COL1 = 1.

DELETE TABLE ITAB: FROM LINE,WITH TABLE KEY COL1 = 3.

LOOP AT ITAB INTO LINE.WRITE: / LINE-COL1, LINE-COL2.ENDLOOP.

Que genera esta salida:

         2        4         4       16

El programa, primero, rellena una tabla interna con una lista de número cuadrados. Posteriormente, la sentencia DELETE borra las líneas de la tabla interna que contienen en COL1 el valor 1 o 3.

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE I,END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1.

DO 4 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

DELETE ITAB WHERE ( COL2 > 1 ) AND ( COL1 < 4 ).

21

Page 22: Dlver Sap Tablas Internas (1)

Tablas internas

LOOP AT ITAB INTO LINE.  WRITE: / LINE-COL1, LINE-COL2.ENDLOOP.

Cuya salida es:

         1        1         4       16

En este otro, vemos otra sentencia DELETE con otra condición lógica.

DATA OFF TYPE I.

DATA: BEGIN OF LINE,COL1 TYPE I,COL2 TYPE C,END OF LINE.

DATA ITAB LIKE STANDARD TABLE OF LINE           WITH NON-UNIQUE KEY COL2.

LINE-COL1 = 1. LINE-COL2 = 'A'. APPEND LINE TO ITAB.LINE-COL1 = 1. LINE-COL2 = 'A'. APPEND LINE TO ITAB.LINE-COL1 = 1. LINE-COL2 = 'B'. APPEND LINE TO ITAB.LINE-COL1 = 2. LINE-COL2 = 'B'. APPEND LINE TO ITAB.LINE-COL1 = 3. LINE-COL2 = 'B'. APPEND LINE TO ITAB.LINE-COL1 = 4. LINE-COL2 = 'B'. APPEND LINE TO ITAB.LINE-COL1 = 5. LINE-COL2 = 'A'. APPEND LINE TO ITAB.

OFF = 0. PERFORM LIST.

DELETE ADJACENT DUPLICATES FROM ITAB COMPARING ALL FIELDS.

OFF = 14. PERFORM LIST.

DELETE ADJACENT DUPLICATES FROM ITAB COMPARING COL1.

OFF = 28. PERFORM LIST.

DELETE ADJACENT DUPLICATES FROM ITAB.

OFF = 42. PERFORM LIST.

FORM LIST.  SKIP TO LINE 3.  LOOP AT ITAB INTO LINE.     WRITE: AT /OFF  LINE-COL1, LINE-COL2.  ENDLOOP.ENDFORM.

Que genera esta otra salida:

         1 A          1 A          1 A          1 A

         1 A          1 B          2 B          2 B

         1 B 2 B 3 B 5 A

22

Page 23: Dlver Sap Tablas Internas (1)

Tablas internas

         2 B          3 B          4 B

         3 B          4 B          5 A

         4 B 5 A

         5 A

Este último ejemplo crea y rellena una tabla estándar. La primera sentencia DELETE borra la segunda línea de ITAB ya que tiene los mismos contenidos que la primera. La segunda sentencia DELETE borra la segunda línea de la tabla resultante de la primera oparación porque los contenidos del campo COL1 son idénticos que los de la primera línea. El tercer DELETE borra la tercera y cuarta línea porque los contenidos del campo clave por defecto COL2 son los mismos que la segunda línea. Aunque los contenidos de las claves por defecto son los mismos para las líneas primera y quinta, ésta última no se borra al no ser adyacente a la primera.

7.6.- Prodcesamiento de tablas en sentencias LOOPPodemos usar la sentencia LOOP para el procesamiento y recorrido de cualquier tabla interna:

LOOP AT <itab> <result> <condition>.  <statement block>ENDLOOP.

Esta instrucción lee las líneas de la tabla una a una tal y como se especificaría en <result>. Además, podemos realizar el LOOP para todas las entradas de la tabla, o bien restringir el recorrido sólo para parte de ella, especificando una condición (<condition>). Se permite cierto control del nivel de procesamiento dentro del LOOP.La secuencia en la que las líneas se procesan depende del tipo de tabla:

o Tablas estándar y sorted: Las líneas se procesan de acuerdo con un índice lineal. Dentro del bloque de procesamiento, la variable de sistema SY-TABIX contiene el índice de la línea actual de procesamiento.o Tablas hashed: Mientras la tabla no esté ordenada, las líneas se procesan en el orden en que han sido añadidas a la tabla. Dentro del bloque de procesamiento, SY-TABIX se mantiene constante a 0.

Así mismo, podemos anidar bloques LOOP. Cuando abandonamos un buqle LOOP, SY-TABIX recupera el valor que tenía justo antes de entrar en él. Además, SY-SUBRC toma el valor 0 con tal de que al menos una entrada de la tabla haya sido procesada.Dentro de un bucle LOOP no se permite realizar operaciones a nivel global de la tabla, sino de línea a línea individualmente.

7.6.1.- Definiendo una opción de procesamiento extraLa opción de procesamiento especifica cómo se puede disponer de una línea dentro de la línea de procesamiento.

7.6.1.1.- Mediante el work areaPara colocar la línea actual del LOOP en un work area, hemos de definir <result> de la siguiente forma:

23

Page 24: Dlver Sap Tablas Internas (1)

Tablas internas

LOOP AT <itab> INTO <wa> <condition>.

Los contenidos de las líneas de la tabla han de poder ser convertibles al tipo del wa. En cada pasada del LOOP, una línea de la tabla se copia en el wa. El final del LOOP no afecta al wa, es decir, los contenidos del wa son los mismos después de la sentencia ENDLOOP ya que fueron copiados en la última pasada del bucle.

7.6.1.2.- Mediante un field-symbolPara asignar el contenido de la línea actual del LOOP a un field-symbol, debemos especificar <result> de la siguiente manera:

LOOP AT <itab> ASSIGNING <FS> <conditions>.

En cada pasada del LOOP, el field symbol <fs> apunta a la línea de la tabla leída. Si el tipo de línea es estructurado, deberíamos especificar el mismo tipo para el field symbol al declararlo. Esto nos permite direccionar los componentes del field symbol. Como en el caso del work area, el final del bucle LOOP no afecta al field-symbol, debido a que éste se queda apuntando a la última línea de la tabla tras la última pasada del bucle.

7.6.1.3.- Suprimiendo la asignación de líneasSi no necesitamos transferir los contenidos de la línea de la tabla actual a un work area ni a un field-symbol, podemos usar la siguiente sentencia:

LOOP AT <itab> TRANSPORTING NO FIELDS <condition>.

Esta modalidad de LOOP es especialmente útil si queremos encontrar el índice de una tabla interna particular, o el número de líneas de una tabla que satisfagan una cierta condición.

7.6.2.- Especificación de condicionesPara evitar el tener que leer la totalidad de las líneas de una tabla interna, podemos especificar una condición de selección de la siguiente manera:

LOOP AT <itab> <result> WHERE <cond>.

Aquí accederemos secuencialmente a las líneas que sólo satisfagan ciertas condiciones. Si las líneas de la tabla no son estructuradas, el primer operando de la condición puede ser TABLE LINE. La comparación entonces se aplica a toda la línea.

7.6.3.- Control del nivel de procesamientoEste control consiste en que podemos dividir secuencias de entradas en grupos basándonos en el contenido de ciertos campos.Las tablas internas están divididas en grupos de acuerdo con la secuencia de los campos en la línea estructurada. Dicho de otro modo, nos es posible estructurar el desarrollo del LOOP en función de los valores de los campos, según las siguientes variantes:

24

Page 25: Dlver Sap Tablas Internas (1)

Tablas internas

<level> Meaning

FIRST Primera línea de la tabla interna

LAST Última línea de la tabla interna

NEW <f> Comienzo de un grupo de líneas con contenidos idénticos en el campo <f>

END Of <f> Final de un grupo de líneas con contenidos idénticos en el campo <f>

El siguiente diagrama ilustra el control de nivel de procesamiento en una tabla ordenada, donde los diferentes contenidos de cada campo se diferencian por el color:

Con la sentencia AT se nos permite gestionar la sentencia LOOP en función de esos cambios en los contenidos de los campos que aquí referenciamos mediante un cambio de color.En general, la sentencia AT tiene el siguiente aspecto:

LOOP AT <itab>.  AT FIRST. ... ENDAT.

25

Page 26: Dlver Sap Tablas Internas (1)

Tablas internas

    AT NEW <f1>. ...... ENDAT.      AT NEW <f2 >. ...... ENDAT.        .......           <single line processing>.......       AT END OF <f2>. ... ENDAT.    AT END OF <f1>. ... ENDAT.  AT LAST. .... ENDAT.ENDLOOP.

Si estamos trabajando con un wa, éste no contiene la línea actual en el bloque AT… ENDAT. Todos los caracteres a la derecha de la actual clave de grupo son rellenados con asteriscos. Todos los demás campos a la derecha de la clave de grupo actual contienen su valor inicial.Dentro de un bloque AT… ENDAT, podemos calcular los contenidos de los campos numéricos correspondientes al nivel actual mediante la sentencia SUM.Si la tabla contiene otra tabla anidada, no podremos usar la sentencia SUM. Veamos los siuientes ejemplos:

DATA: BEGIN OF LINE,         COL1 TYPE C,         COL2 TYPE I,         COL3 TYPE I,      END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE          WITH UNIQUE KEY COL1 COL2.

LINE-COL1 = 'A'.DO 3 TIMES.  LINE-COL2 = SY-INDEX.  LINE-COL3 = SY-INDEX ** 2.  INSERT LINE INTO TABLE ITAB.ENDDO.

LINE-COL1 = 'B'.DO 3 TIMES.  LINE-COL2 = 2 * SY-INDEX.  LINE-COL3 = ( 2 * SY-INDEX ) ** 2.  INSERT LINE INTO TABLE ITAB.ENDDO.

SORT ITAB.

LOOP AT ITAB INTO LINE.  WRITE: / LINE-COL1, LINE-COL2, LINE-COL3.  AT END OF COL1.    SUM.    ULINE.    WRITE: / LINE-COL1, LINE-COL2, LINE-COL3.    SKIP.  ENDAT.  AT LAST.    SUM.    ULINE.    WRITE: / LINE-COL1, LINE-COL2, LINE-COL3.  ENDAT.ENDLOOP.

26

Page 27: Dlver Sap Tablas Internas (1)

Tablas internas

Que genera la siguiente salida:

A 1 1

A 2 4

A          3          9________________________________

A          6         14

B          2          4

B 4 16

B 6 36________________________________

B         12         56

________________________________

*         18         70

El programa crea una tabla hashed ITAB, la rellena con seis líneas y la ordena. En el bloque LOOP-ENDLOOP, el work area LINE es presentado por pantalla en cada pasada del LOOP. El primer campo de la clave de la tabla, COL1, se usa para el control del nivel de procesamiento. El total para todos los campos numéricos siempre se calcula cuando el contenido de COL1 cambia y el sistema se encuentra en la última pasada del LOOP.

DATA: BEGIN OF LINE,        CARRID   TYPE SBOOK-CARRID,        CONNID   TYPE SBOOK-CONNID,        FLDATE   TYPE SBOOK-FLDATE,        CUSTTYPE TYPE SBOOK-CUSTTYPE,        CLASS    TYPE SBOOK-CLASS,        BOOKID   TYPE SBOOK-BOOKID,      END OF LINE.

DATA ITAB LIKE SORTED TABLE OF LINE WITH UNIQUE KEY TABLE LINE.

SELECT CARRID CONNID FLDATE CUSTTYPE CLASS BOOKID       FROM SBOOK INTO CORRESPONDING FIELDS OF TABLE ITAB.

LOOP AT ITAB INTO LINE.

  AT FIRST.    WRITE / 'List of Bookings'.    ULINE.  ENDAT.

    AT NEW CARRID.      WRITE: / 'Carrid:', LINE-CARRID.    ENDAT.

      AT NEW CONNID.        WRITE: / 'Connid:', LINE-CONNID.      ENDAT.

27

Page 28: Dlver Sap Tablas Internas (1)

Tablas internas

        AT NEW FLDATE.          WRITE: / 'Fldate:', LINE-FLDATE.        ENDAT.

          AT NEW CUSTTYPE.            WRITE: / 'Custtype:', LINE-CUSTTYPE.          ENDAT.

               WRITE: / LINE-BOOKID, LINE-CLASS.

            AT END OF CLASS.              ULINE.            ENDAT.

ENDLOOP.

En este ejemplo, la tabla sorted interna es rellenada con datos de la tabla de la base de datos SBOOK mediante la sentencia SELECT. La secuencia de las columnas en la tabla interna define la jerarquía del nivel de control. Debido a que la clave de la tabla es la línea entera, la sequencia de ordenación y la jerarquía del nivel de control son las mismas. El programa genera la siguiente salida:

List of BookingsCarrid: AAConnid: 0017Fldate: 1998/11/22Custtype: B00063509 C00063517 C...______________________________________________00063532 F00063535 F...______________________________________________Custtype: P00063653 C00063654 C...______________________________________________00063668 F00063670 F...______________________________________________Fldate: 1998/29/11Custtype: B00064120 C00064121 C...

Y continúa.

7.7.- Inicializar tablasComo cualquier otro objeto de datos, las tablas internas pueden ser inicializadas con esta sentencia:

CLEAR <itab>.

28

Page 29: Dlver Sap Tablas Internas (1)

Tablas internas

Este sentencia reestablece una tabla interna al estado en el que se encontraba inmediatamente despues de haber sido declarada. Esto significa que a partir de entonces la tabnla interna no contiene ninguna línea. Sin embargo, la memoria ya ocupada por la tabla interna hasta que la reinicializamos con CLEAR permanece localizada y reservada.Si estamos usando tablas internas con líneas de cabecera, hemos de recordar que tanto las tablas como sus líneas de cabecera tienen el mismo nombre. Si lo que queremos es referenciar el cuerpo de la tabla, habremos de invocar el nombre de la misma seguido con un par de corchetes ([ ]):

CLEAR <itab>[].

Para asegurarnos de que la tabla se ha inicializado, podemos usar la sentencia siguiente:

REFRESH <itab>.

Ésta siempre se aplica al cuerpo de la tabla. Así como en la sentencia CLEAR, ésta última deja reservado el espacio de memoria que tenía la tabla.No obstante, si lo que queremos es liberar dicho espacio en memoria, usaremos la siguiente sentencia:

FREE <itab>.

Hemos de recordar que esta sentencia tiene efecto sobre el cuerpo de la tabla y no sobre el work area.

DATA: BEGIN OF LINE,COL1,COL2,END OF LINE.

DATA ITAB LIKE TABLE OF LINE.

LINE-COL1 = 'A'. LINE-COL2 = 'B'.

APPEND LINE TO ITAB.

REFRESH ITAB.

IF ITAB IS INITIAL.WRITE 'ITAB is empty'.FREE ITAB.ENDIF.

Y la salida del programa es:

ITAB is empty.

En este programa, una tabla interna ITAB se rellena primero, y se inicializa con REFRESH, después. La sentencia IF utiliza la expresión ITAB IS INITIAL para averiguar si ITAB está vacía o no. De estarlo, la memoria es borrada.

7.8.- Ordenación de tablas internasEn ABAP podemos ordenar una tabla estándar o hashed, para lo que usaremos la sieguiente sentencia:

29

Page 30: Dlver Sap Tablas Internas (1)

Tablas internas

SORT <itab> [ASCENDING|DESCENDING] [AS TEXT] [STABLE].

Esta sentencia se aplica a la tabla en sí misma, nunca a la línea de cabecera.El modo de ordenación se especifca mediante el parámetro ASCENDING o DESCENDING, siendo el primero el que se realiza por defecto. En general, el sentido de la ordenación depende de los campos de la clave de la tabla interna. La clave de ordenación por defecto se hace con los campos no numéricos de la línea de la tabla en el orden en el que están dispuestos.Cuanto más grande sea la clave de ordenación, más tiempo necesitará el sistema para ordenar la tabla. Si ésta además contiene una tabla interna, el proceso de ordenación puede ser considerablemente más lento.Por otro lado, no nos es posible la ordenación de tablas sorted, debido a que el sistema las mantiene ya ordenadas automáticamente. Si aplicamos la sentencia SORT a una tabla sorted, aquélla causará un error de sintaxis.

7.8.1.- Ordenación con otra claveSi tenemos una tabla interna con un tipo de línea estructutrado que queramos ordenar con una clave diferente de la de por defecto, podemos especifcarlo en la sentencia SORT:

SORT <itab> [ASCENDING|DESCENDING] [AS TEXT] [STABLE]             BY <f1> [ASCENDING|DESCENDING] [AS TEXT]                ...                <fn> [ASCENDING|DESCENDING] [AS TEXT].

La tabla está ahora ordenada por los componentes especificados <f 1 > ... <f n > en lugar de estarlo por la clave de la tabla. El número de campos de ordenación se limita a 250. Como en el anterior caso, el modo de ordenación depende de la secuencia de los campos <f i >. La secuencia de ordenación especificada antes de BY se aplica a todos los campos. La secuencia de ordenación después de un campo se aplica sólo a esa columna de la tabla.

7.8.2.- Ordenación alfabéticaAdemás de los casos de ordenación ascendente o descendente, ésta puede ser alfabética:

SORT <itab> ... AS TEXT ... .

Esta sentencia afecta a la ordenación de cadenas de caracteres. Sin ella, dichas cedenas se ordenan de acuerdo con la secuencia especificada por la plataforma hardware del sistema. Con la opción AS TEXT, el sistema ordena campos de caracteres alfabéticamente de acuerdo con el entorno textual actual. Por defecto, dicho entorno textual se establece en el registro maestro del usuario. Sin embargo, también podemos especificarlo explícitamente usando la sentencia:

SET LOCALE LANGUAGE

La cláusula AS TEXT nos ahorrará el tener que converitr cadenas a un formato de ordenación compatible. Si AS TEXT se aplica a toda la ordenación entera, ésta sólo afecta a los campos de tipo C. De ser aplicada a un campo concreto, éste ha de ser de tipo C, igualmente.

30

Page 31: Dlver Sap Tablas Internas (1)

Tablas internas

7.9.- Determinación de los atributos de una tabla internaPara averiguar los atributos de una tabla interna en tiempo de ejecución que no están disponibles estáticamente, debemos usar la sentencia:

DESCRIBE TABLE <itab> [LINES <l>] [OCCURS <n>] [KIND <k>].

Si usamos el parámetro LINES, el número de líneas rellenas se escribirá en la variable <l>. Si usamos el parámetro OCCURS, el valor del tamaño inicial de la tabla se escribirá en la variable <n>. Si usamos el parámetro KIND, el tipo de tabla interna se devolverá mediante la variable <k>: ‘T’ para tablas estándar, ‘S’ para tablas estándar y ‘H’ para las hashed.

DATA: BEGIN OF LINE,         COL1 TYPE I,         COL2 TYPE I,      END OF LINE.

DATA ITAB LIKE HASHED TABLE OF LINE WITH UNIQUE KEY COL1                                    INITIAL SIZE 10.

DATA: LIN TYPE I,      INI TYPE I,      KND TYPE C.

DESCRIBE TABLE ITAB LINES LIN OCCURS INI KIND KND.WRITE: / LIN, INI, KND.

DO 1000 TIMES.  LINE-COL1 = SY-INDEX.  LINE-COL2 = SY-INDEX ** 2.INSERT LINE INTO TABLE ITAB.ENDDO.

DESCRIBE TABLE ITAB LINES LIN OCCURS INI KIND KND.WRITE: / LIN, INI, KND.

La salida sería:

0         10  H

     1,000         10  H

Aquí, se crea una tabla hashed que se rellena posteriormente. La sentencia DESCRIBE TABLE de procesa antes y después del llenado de la tabla. El número de líneas actual cambia, no así el número de líneas inicial.

31