jueves, 28 de julio de 2011

Grabar el resultado de una query en un fichero de texto

En esta entrada veremos como podemos descargar el resultado de una Query a un fichero de texto. En primer lugar deberemos añadir la ampliación SQUE0001 a un proyecto de ampliaciones mediante la transacción CMOD.

Esta user exit hace que en el formato de salida de la Query aparezca una nueva opción llamada "Archivo personal". Cuando marcamos este formato de salida se ejecuta el código de la user exit.

En la exit disponemos de los datos seleccionados por la Query de forma que podemos poner nuestro código para grabar esta tabla en un fichero (local o en el servidor de aplicaciones). Aquí os dejo el código para grabar la tabla en un fichero del servidor de aplicaciones utilizando la función Z_CREAERFICHERO publicada en una entrada anterior.

Los datos de la Query se encuentran en la tabla datatab.

CONSTANTS: c_zhr_contr_ns TYPE string VALUE 'ZHR_CONTR_NS',
c_zhr_contr_supl TYPE string VALUE 'ZHR_CONTR_SUPL',
c_interfaces TYPE string VALUE '/INTERFACES/GESTPRES/SALIDA',
c_extension TYPE string VALUE '.csv'.

IF sy-cprog CS c_zhr_contr_ns OR sy-cprog CS c_zhr_contr_supl.

DATA: ld_directory TYPE dxfile-filename,
ld_filename TYPE dxfile-filename.

* Construimos el nombre del fichero con el nombre de la query.
IF sy-cprog CS c_zhr_contr_ns.
CONCATENATE c_zhr_contr_ns '_' sy-datum c_extension INTO ld_filename.
ELSEIF sy-cprog CS c_zhr_contr_supl.
CONCATENATE c_zhr_contr_supl '_' sy-datum c_extension INTO ld_filename.
ENDIF.

ld_directory = c_interfaces.

* Generamos el fichero
CALL FUNCTION 'ZHR_CREARFICHERO'
EXPORTING
i_directory = ld_directory
i_filename = ld_filename
i_separator = ';'
i_overwrite = 'X'
it_data = datatab[]
EXCEPTIONS
ex_errordirectory = 1
ex_fileexists = 2
OTHERS = 3.

* Escribimos el log
IF sy-subrc NE 0.
* Mensaje de error
ENDIF.

Descargar cualquier tabla a un directorio del servidor de aplicaciones

Con esta función podremos descargar cualquier tabla, sea cual sea su estructura, a un fichero de texto en un directorio del servidor de aplicaciones. Podemos consultar los directorios mediante la transacción AL11.
Cómo parámetros le pasaremos el nombre del directorio, el nombre del fichero y la tabla de datos. Opcionalmente le podemos decir que sobreescriba el fichero en caso de que exista y el separador a utilizar entre los campos de una fila de datos.

FUNCTION z_crearfichero.
*"----------------------------------------------------------------------
*"*"Interfase local
*" IMPORTING
*" REFERENCE(I_DIRECTORY) TYPE DXFILE-FILENAME
*" REFERENCE(I_FILENAME) TYPE DXFILE-FILENAME
*" REFERENCE(I_OVERWRITE) TYPE CHAR1 OPTIONAL
*" REFERENCE(I_SEPARATOR) TYPE CHAR1 DEFAULT ';'
*" REFERENCE(IT_DATA) TYPE TABLE
*" EXCEPTIONS
*" EX_ERRORDIRECTORY
*" EX_FILEEXISTS
*"----------------------------------------------------------------------

* Verificamos la existencia del directorio de destino
DATA: lt_ocs_file LIKE ocs_file OCCURS 0,
ls_ocs_file LIKE ocs_file,
ld_directory LIKE ocs_file-name,
ld_filename LIKE ocs_file-name.

MOVE i_directory TO ld_directory.
MOVE i_filename TO ld_filename.

CALL FUNCTION 'OCS_GET_FILE_INFO'
EXPORTING
dir_name = ld_directory
file_name = '*'
TABLES
dir_list = lt_ocs_file
EXCEPTIONS
no_authority = 1
activity_unknown = 2
not_a_directory = 3
no_media_in_drive = 4
too_many_errors = 5
too_many_files = 6
bracket_error_in_filename = 7
no_such_parameter = 8.

* No podemos acceder al directorio o no existe
IF sy-subrc NE 0.
RAISE ex_errordirectory.
ENDIF.

* Comprobamos si existe.
READ TABLE lt_ocs_file INTO ls_ocs_file WITH KEY name = ld_filename.
IF sy-subrc EQ 0.
IF i_overwrite IS INITIAL.
* Si no podemos sobrescribirlo lanzamos una excepción
RAISE ex_fileexists.
ELSE.
* Si se puede sobreescribir damos una advertencia de ello
MESSAGE s007(zhrx_contratos_bold) WITH ld_filename.
* El fichero & se sobrescribe
ENDIF.
ENDIF.

* Bajamos la tabla al directorio de destino
DATA: ld_filepath TYPE dxfile-filename,
ld_length TYPE i,
ld_outdata TYPE string,
ld_data TYPE string.

FIELD-SYMBOLS: TYPE ANY.
FIELD-SYMBOLS: TYPE ANY.

* Construimos el nombre completo del fichero
CONCATENATE ld_directory ld_filename INTO ld_filepath SEPARATED BY '/'.

* Abrimos el fichero para escitura
OPEN DATASET ld_filepath FOR OUTPUT IN TEXT MODE ENCODING DEFAULT.
IF sy-subrc NE 0.
RAISE ex_errordirectory.
ENDIF.

* Para poder grabar cualquier tipo de tabla utilizamos field-symbols. En primer lugar leemos cada línea
* de la tabla asignandola al field symbols . En segundo lugar accedemos a cada uno de los campos
* de la fila mediante la instrucción ASSIGN COMPONENT. De esta forma podemos pasar a la función cualquier
* tipo de tabla independientemente de su estructura.
LOOP AT it_data ASSIGNING .
CLEAR: sy-subrc, ld_outdata.
* Leemos todos los campos de la estructura y los vamos concatenando para formar una línea del fichero
* de texto.
WHILE sy-subrc = 0.
ASSIGN COMPONENT sy-index OF STRUCTURE TO .
IF sy-subrc NE 0.
EXIT.
ENDIF.
CLEAR ld_data.
MOVE TO ld_data.
* El primer campo lo pasamos directamente a la variable de salida, el resto lo concatenamos mediante
* el separador especificado.
IF ld_outdata IS INITIAL.
MOVE ld_data TO ld_outdata.
ELSE.
CONCATENATE ld_outdata ld_data INTO ld_outdata SEPARATED BY i_separator.
ENDIF.
ENDWHILE.

* Añadimos al fichero destino la línea que acabamos de construir.
TRANSFER ld_outdata TO ld_filepath.
ENDLOOP.

* Cerramos el fichero de destino
CLOSE DATASET ld_filepath.

ENDFUNCTION.