Es posible que al realizar un programa Z para un cliente, uno se encuentre con la problemática que no sabe en tiempo de compilación de qué tipo va a ser la tabla interna que va a necesitar para tratar los datos. En este escenario es dónde resulta útil el conocer cómo se ha de declarar una tabla dinámica, cómo se informa y cómo se acceden a los datos que se han almacenado en su interior.
A la hora de crear una tabla dinámica, lo primero que se debe hacer es declarar las variables que van a servir para su construcción:
DATA: lv_tabla TYPE dd02l-tabname,
generic_table TYPE REF TO data,
generic_line TYPE REF TO data.
La variable lv_tabla contiene el nombre de la tabla de diccionario de datos que se usará como base para la creación de la tabla interna. Las variables generic_table y generic_line son referencias a una tabla y a una linea o área de trabajo genéricas. Estas dos últimas variables no son accesibles realmente, y por lo tanto es necesario declarar FIELD-SYMBOLS que servirán como manejadores a la hora de cargar y acceder a los datos.
FIELD-SYMBOLS: <table> TYPE ANY TABLE,
<wa> TYPE ANY,
<field> TYPE ANY.
Estos FIELD-SYMBOLS representan a la tabla completa, a un registro dentro de la tabla y a un campo concreto dentro de un registro respectivamente. Sin embargo inicialmente estarán sin asignar y si se intenta mostrar su valor u operar con ellos se producirá un error en tiempo de ejecución. Por lo tanto se debe conocer la forma correcta de asignar y manejar un FIELD-SYMBOL en SAP.
Obviamente, al construir una tabla interna se pretende que almacene datos bien obtenidos desde la base de datos o bien calculados por el propio programa Z. En el segundo caso es bastante probable que el programador ya sepa en tiempo de compilación qué datos tiene que calcular y en qué orden debe de almacenarlos en memoria, así que este tutorial se centra en el primer caso: Recuperar datos desde la base de datos a una tabla dinámica.
Para la generación de la tabla dinámica en tiempo de ejecución partimos del supuesto de que en la variable lv_tabla se encuentra el nombre de la tabla o estructura del diccionario de datos a partir de la cual se desea crear la tabla interna. Para su construcción se aplicará el siguiente fragmento de código ABAP
CREATE DATA generic_table TYPE STANDARD TABLE OF (lv_tabla).
ASSIGN generic_table->* TO <table>.
CREATE DATA generic_line TYPE (lv_tabla).
ASSIGN generic_line->* TO <wa>.
En este momento la variable generic_table será una tabla interna con la estructura de lv_tabla y generic_line será un registro de dicha tabla interna. Además los FIELD-SYMBOLS <table> y <wa> se encontrarán inicializados apuntando a la tabla y al área de trabajo respectivamente. En este momento se puede operar con dichos FIELD-SYMBOLS.
En este momento es cuando el programador puede cargar la información en la tabla interna de la forma habitual, teniendo en cuenta de que la selección tendrá una cláusula FROM dinámica, tal y cómo se puede apreciar en el siguiente fragmento de código:
SELECT *
INTO CORRESPONDING FIELDS OF TABLE <table>
FROM (lv_tabla).
Al tratarse de una selección dinámica, es conveniente que el programador trate las excepciones que se pueden producir, en este caso concreto, que no exista la tabla de base de datos indicada en lv_tabla.
A la hora de acceder a los datos de una tabla dinámica creada en tiempo de ejecución puede darse uno de dos casos:
- El programador conoce el nombre de los campos de la tabla interna
- El programador no conoce el nombre de los campos de la tabla interna.
En el primer caso el acceso al campo deseado se realizará de la siguiente forma:
CONSTANTS: lv_nombre_campo(255) TYPE C VALUE 'nombre del campo'.
DATA: lv_valor_campo TYPE tipo_del_campo.
LOOP AT <table> INTO <wa>.
ASSIGN COMPONENT lv_nombre_campo OF STRUCTURE <wa> TO <field>.
MOVE <field> TO lv_valor_campo.
ENDLOOP.
En el segundo caso el acceso será parecido, sólo que en lugar de utilizar el nombre del campo se utilizará un índice para el acceso. Dicho índice representa la posición del campo dentro de un registro de la tabla interna creada.
DATA: lv_indice_campo TYPE I,
lv_valor_campo. TYPE tipo_del_campo
lv_indice_campo = 3. "Cambiar por la posición deseada.
LOOP AT <table> INTO <wa>.
ASSIGN COMPONENT lv_indice_campo OF STRUCTURE <wa> TO <field>.
MOVE <field> TO lv_valor_campo.
ENDLOOP.
En el ejemplo de arriba se accede al tercer campo del registro que se esté tratando actualmente en el interior del bucle de tratamiento de datos. Es posible acceder a cualquier otro campo cambiando el índice, e incluso generalizarlo para que se acceda a todos los campos de un registro.
En ambos casos el programador será el encargado de controlar los errores que se puedan dar durante el proceso, siendo los más habituales:
- Que el nombre del campo no exista y por lo tanto no se asigne nada al
FIELD-SYMBOL <field> - Que el registro no tenga tantos campos como el número que se le pase al índice de acceso y por lo tanto no se asigne nada al
FIELD-SYMBOL <field>.
Es posible, mediante la sentencia CHECK <symbol> IS ASSIGNED. comprobar que el FIELD-SYMBOL se encuentra asignado.