Hola, en mis tiempos de disponibilidad en la empresa en que trabajo, me puse a realizar un programa que muestra por medio un ALV los registros que tienen en común dos tablas. Trabaja todo de forma dinámica. El objetivo principal de esta creación es obtener datos en común entre dos tablas, como si fuera una vista, pero sin crear un vista, sino realizar todo el proceso por medio de un programa.
Por el momento uno debe:
- Ingresar los nombres de las tablas.
- Ingresar los campos de unión de ambas tablas (respetando que el primero se unirá con el primero de la otra, el segundo campo ingresado con el segundo de la otra, así sucesivamente).
- Ingresar los campos de visualización, uno puede elegir que campos de la tabla 1 y de la tabla 2 quiere visualizar.
- Ingresar la cantidad de registros.
Pantalla de selección
- El ingreso de los campos de unión y visualización se ingresar uno seguido al otro.
He ingresado validaciones para los posibles errores:
- Si se ingresa mas de un espacio entre los campos
- Si los campos de unión contienen distinto tipos de elemento y longitud.
- Si los campos ingresados pertenecen a la tabla ingresada
- Etc.
Aun que el programa podría haberlo hecho en un solo objeto, para no perder la costumbre he creado TOP/SEL/F01.
zrda_select_dinamic (principal)
Description:
*&---------------------------------------------------------------------*
*& Report ZRDA_SELECT_DINAMIC
*&---------------------------------------------------------------------*
*& Obtención de unión de datos en tablas de forma dinámica.
*&---------------------------------------------------------------------*
REPORT zrda_select_dinamic.
include zrda_select_dinamic_top,.
zrda_select_dinamic_s01,
zrda_select_dinamic_f01.
START-OF-SELECTION.
PERFORM: f_proceso.
zrda_select_dinamic_f01
*&---------------------------------------------------------------------*
*& Include ZRDA_SELECT_DINAMIC_F01
*&---------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form F_PROCESO
*&---------------------------------------------------------------------*
* Proceso principal
*----------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*& Form f_proceso
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
FORM f_proceso.
DATA: lv_fields TYPE string,
lt_xtable_1 TYPE REF TO data,
lt_xtable_2 TYPE REF TO data,
lt_xtable_3 TYPE REF TO data,
lt_componentes TYPE tyt_dfies,
lv_error TYPE p VALUE 0,
lt_union_1 TYPE tyt_campos,
lt_union_2 TYPE tyt_campos,
lt_campos_1 TYPE tyt_campos,
lt_campos_2 TYPE tyt_campos,
lt_campos TYPE tyt_campos.
* Validamos los campos de visualización y unión ingresados
PERFORM f_validacion_campos USING p_t_1
p_t_2
p_camp_1
p_camp_2
p_uni_1
p_uni_2
CHANGING lt_union_1
lt_union_2
lt_campos_1
lt_campos_2
lt_campos
lv_error.
IF lv_error EQ 0.
PERFORM f_datos_previos USING lt_campos
CHANGING lt_componentes
lt_xtable_3.
PERFORM f_seleccion_datos USING lt_union_1
lt_union_2
lt_campos_1
lt_campos_2
CHANGING lt_xtable_3.
PERFORM f_mostrar_datos USING lt_componentes
lt_campos
lt_xtable_3.
ELSE.
* Mostramos el correspondiente mensaje, se prioriza el primer error encontrado
PERFORM f_manejar_error USING lv_error.
ENDIF.
ENDFORM. " F_PROCESO
*&---------------------------------------------------------------------*
*& Form F_VALIDACION_CAMPOS
*&---------------------------------------------------------------------*
* Validación de campos de tablas
*----------------------------------------------------------------------*
* -->P_T_1 Nombre de tabla 1
* -->P_T_2 Nombre de tabla 2
* -->P_CAMP_1 Campos de la tabla 1
* -->P_CAMP_2 Campos de la tabla 2
* -->P_UNI_1 Campos de unión de tabla 1
* -->P_UNI_2 Campos de unión de tabla 2
* <--P_LT_UNION_1 Tabla con campos de unión tabla 1
* <--P_LT_UNION_" Tabla con campos de unión tabla 2
* <--P_LT_CAMPOS_1 Tabla con campos de tabla 1
* <--P_LT_CAMPOS_2 Tabla con campos de tabla 2
* <--P_LT_CAMPOS Tabla con campos de ambas tablas
* <--P_LV_ERROR Variable con número de error
*----------------------------------------------------------------------*
FORM f_validacion_campos USING p_t_1 TYPE tabname
p_t_2 TYPE tabname
p_camp_1 TYPE string
p_camp_2 TYPE string
p_uni_1 TYPE string
p_uni_2 TYPE string
CHANGING p_lt_union_1 TYPE tyt_campos
p_lt_union_2 TYPE tyt_campos
p_lt_campos_1 TYPE tyt_campos
p_lt_campos_2 TYPE tyt_campos
p_lt_campos TYPE tyt_campos
p_lv_error TYPE p.
DATA: ls_campos TYPE tys_campos,
ls_union TYPE tys_campos,
lt_campos_t_1 TYPE tyt_fieldname, " Campos de tabla 1
lr_campos_t_1 TYPE RANGE OF fieldname," Rango de campos tabla 1
ls_campos_t_1 LIKE LINE OF lr_campos_t_1,
ls_fieldname TYPE tys_fieldname,
lt_campos_t_2 TYPE tyt_fieldname, " Campos de tabla 2
lr_campos_t_2 TYPE RANGE OF fieldname," Rango de campos tabla 2
ls_campos_t_2 LIKE LINE OF lr_campos_t_2,
lt_dd03l_2 TYPE tyt_dd03l,
lt_dd03l_1 TYPE tyt_dd03l.
DATA: lv_campos_total TYPE string,
lt_borrado TYPE tyt_campos.
* Creamos tablas de campos de unión
* Campos de unión de tabla 1
SPLIT p_uni_1 AT space INTO TABLE p_lt_union_1.
DELETE p_lt_union_1 WHERE campo = space.
* Verificamos duplicados
lt_borrado[] = p_lt_union_1[].
SORT lt_borrado BY campo.
DELETE ADJACENT DUPLICATES FROM lt_borrado COMPARING campo.
IF sy-subrc EQ 0.
p_lv_error = 7.
EXIT.
ENDIF.
* Campos de unión de tabla 2
SPLIT p_uni_2 AT space INTO TABLE p_lt_union_2.
DELETE p_lt_union_2 WHERE campo = space.
* Verificamos duplicados
lt_borrado[] = p_lt_union_2[].
SORT lt_borrado BY campo.
DELETE ADJACENT DUPLICATES FROM lt_borrado COMPARING campo.
IF sy-subrc EQ 0.
p_lv_error = 7.
EXIT.
ENDIF.
IF lines( p_lt_union_1 ) NE lines( p_lt_union_2 ).
p_lv_error = 10.
EXIT.
ENDIF.
* Verificamos que los campos de unión contengan el mismo tipo de elemento
* Obtenemos el tipo de dato y longitud de los campos de union de tabla 1
SELECT datatype leng
FROM dd03l
INTO TABLE lt_dd03l_1
FOR ALL ENTRIES IN p_lt_union_1
WHERE tabname EQ p_t_1 AND
fieldname EQ p_lt_union_1-campo.
* Obtenemos el tipo de dato y longitud de los campos de union de tabla 2
SELECT datatype leng
FROM dd03l
INTO TABLE lt_dd03l_2
FOR ALL ENTRIES IN p_lt_union_2
WHERE tabname EQ p_t_2 AND
fieldname EQ p_lt_union_2-campo.
* Verificamos ambas tablas, las cuales deben ser iguales
IF lt_dd03l_1[] NE lt_dd03l_2[].
p_lv_error = 11.
EXIT.
ENDIF.
* Creamos tabla de campos de visualización (por separado)
* Tabla 1
SPLIT p_camp_1 AT space INTO TABLE p_lt_campos_1.
DELETE p_lt_campos_1 WHERE campo = space.
* Verificamos duplicados
lt_borrado[] = p_lt_campos_1[].
SORT lt_borrado BY campo.
DELETE ADJACENT DUPLICATES FROM lt_borrado COMPARING campo.
IF sy-subrc EQ 0.
p_lv_error = 7.
EXIT.
ENDIF.
* Tabla 2
SPLIT p_camp_2 AT space INTO TABLE p_lt_campos_2.
DELETE p_lt_campos_2 WHERE campo = space.
* Verificamos duplicados
CLEAR: lt_borrado[], lt_borrado.
lt_borrado[] = p_lt_campos_2[].
SORT lt_borrado BY campo.
DELETE ADJACENT DUPLICATES FROM lt_borrado COMPARING campo.
IF sy-subrc EQ 0.
p_lv_error = 8.
EXIT.
ENDIF.
* Creamos tabla con todos los campos de visualización
CONCATENATE p_camp_1 p_camp_2 INTO lv_campos_total SEPARATED BY space.
SPLIT lv_campos_total AT space INTO TABLE p_lt_campos.
DELETE p_lt_campos WHERE campo = space.
* Obtenemos los campos de la tabla 1
SELECT fieldname
FROM dd03l
INTO TABLE lt_campos_t_1
WHERE tabname EQ p_t_1.
IF sy-subrc NE 0.
p_lv_error = 1.
EXIT.
ELSE.
* Creamos rango de campos tabla 1
ls_campos_t_1-sign = 'I'.
ls_campos_t_1-option = 'EQ'.
LOOP AT lt_campos_t_1 INTO ls_fieldname.
ls_campos_t_1-low = ls_fieldname-fieldname.
APPEND ls_campos_t_1 TO lr_campos_t_1.
ENDLOOP.
ENDIF.
* Obtenemos los campos de la tabla 2
SELECT fieldname
FROM dd03l
INTO TABLE lt_campos_t_2
WHERE tabname EQ p_t_2.
IF sy-subrc NE 0.
p_lv_error = 2.
EXIT.
ELSE.
* Creamos rango de campos tabla 2
ls_campos_t_2-sign = 'I'.
ls_campos_t_2-option = 'EQ'.
LOOP AT lt_campos_t_2 INTO ls_fieldname.
ls_campos_t_2-low = ls_fieldname-fieldname.
APPEND ls_campos_t_2 TO lr_campos_t_2.
ENDLOOP.
ENDIF.
* Validamos campos de unión
LOOP AT p_lt_union_1 INTO ls_union.
IF ls_union-campo NOT IN lr_campos_t_1.
p_lv_error = 3.
EXIT.
ENDIF.
ENDLOOP.
CLEAR ls_union.
LOOP AT p_lt_union_2 INTO ls_union.
IF ls_union-campo NOT IN lr_campos_t_2.
p_lv_error = 4.
EXIT.
ENDIF.
ENDLOOP.
* Validamos campos de visualización
IF p_camp_1 IS NOT INITIAL.
LOOP AT p_lt_campos_1 INTO ls_campos WHERE campo NOT IN lr_campos_t_1.
p_lv_error = 5.
EXIT.
ENDLOOP.
ENDIF.
IF p_camp_2 IS NOT INITIAL.
LOOP AT p_lt_campos_2 INTO ls_campos WHERE campo NOT IN lr_campos_t_2.
p_lv_error = 6.
EXIT.
ENDLOOP.
ENDIF.
ENDFORM. " F_VALIDACION_CAMPOS
*&---------------------------------------------------------------------*
*& Form F_DATOS_PREVIOS
*&---------------------------------------------------------------------*
* Obtención de tabla internar dinámicamente
*----------------------------------------------------------------------*
FORM f_datos_previos USING p_lt_campos TYPE tyt_campos
CHANGING p_lt_componentes TYPE tyt_dfies
p_lt_xtable_3 TYPE REF TO data.
* Obtenemos tabla para los datos finales
PERFORM f_tabla_interna CHANGING p_lt_componentes
p_lt_campos
p_lt_xtable_3
p_t_1
p_t_2.
ENDFORM. " F_DATOS_PREVIOS
*&---------------------------------------------------------------------*
*& Form F_ALL_CAMPOS
*&---------------------------------------------------------------------*
* Obtención de todos los campos de la tabla
*----------------------------------------------------------------------*
* --> P_INTERNAL_TABLE Tabla
* <-- P_FIELDS Campos concadenados en un string
*----------------------------------------------------------------------*
FORM f_all_campos USING p_internal_table TYPE ANY TABLE
CHANGING p_fields TYPE string.
DATA: wa_ref TYPE REF TO data,
desc_table TYPE REF TO cl_abap_tabledescr,
desc_struc TYPE REF TO cl_abap_structdescr.
FIELD-SYMBOLS: <p_data> TYPE any,
<p_component> TYPE abap_compdescr.
CLEAR p_fields.
CREATE DATA wa_ref LIKE LINE OF p_internal_table.
ASSIGN wa_ref->* TO <p_data>.
desc_table ?= cl_abap_tabledescr=>describe_by_data( p_internal_table ).
desc_struc ?= desc_table->get_table_line_type( ).
LOOP AT desc_struc->components ASSIGNING <p_component>.
CONCATENATE p_fields <p_component>-name INTO p_fields SEPARATED BY space .
ENDLOOP.
ENDFORM. " F_ALL_CAMPOS
*&---------------------------------------------------------------------*
*& Form F_TABLA_INTERNA
*&---------------------------------------------------------------------*
* Obtención de tabla internar dinámicamente
*----------------------------------------------------------------------*
FORM f_tabla_interna CHANGING p_lt_componentes TYPE tyt_dfies
p_lt_campos TYPE tyt_campos
p_xtable TYPE REF TO data
p_t_1 TYPE tabname
p_t_2 TYPE tabname.
DATA: lt_dyn_fcat TYPE lvc_t_fcat,
lt_campos TYPE tyt_campos,
ls_campos TYPE tys_campos,
lr_campos TYPE RANGE OF fieldname,
lt_componentes_1 TYPE tyt_dfies,
lt_componentes_2 TYPE tyt_dfies,
lr_s_campos LIKE LINE OF lr_campos.
FIELD-SYMBOLS: <fs_t_bseg> TYPE dfies,
<fs_campo> TYPE tys_campos,
<fs_dyn_cat> TYPE lvc_s_fcat.
IF p_lt_campos IS INITIAL.
* Tabla dinámica obteniendo todos los campos, ya que no hay filtro,
* pero p_campos es obligatorio, por ende nunca pasa por aca.
CREATE DATA p_xtable TYPE TABLE OF (p_t_1).
ELSE.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
tabname = p_t_1
langu = sy-langu
TABLES
dfies_tab = lt_componentes_1
EXCEPTIONS
not_found = 1
internal_error = 2
OTHERS = 3.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
tabname = p_t_2
langu = sy-langu
TABLES
dfies_tab = lt_componentes_2
EXCEPTIONS
not_found = 1
internal_error = 2
OTHERS = 3.
* Unimos los campos de ambas tablas en una sola
APPEND LINES OF lt_componentes_1 TO p_lt_componentes.
APPEND LINES OF lt_componentes_2 TO p_lt_componentes.
* Ordenamiento para binary search
SORT p_lt_componentes BY fieldname.
* Recorremos tabla con campos
LOOP AT p_lt_campos ASSIGNING <fs_campo>.
* Leemos solo los que nos interesan, los campos de tabla 1 y 2
READ TABLE p_lt_componentes ASSIGNING <fs_t_bseg>
WITH KEY fieldname = <fs_campo>-campo BINARY SEARCH.
IF sy-subrc EQ 0.
* Mapeo del fieldcatalog para tabla dinámica
APPEND INITIAL LINE TO lt_dyn_fcat ASSIGNING <fs_dyn_cat>.
<fs_dyn_cat>-fieldname = <fs_t_bseg>-fieldname.
<fs_dyn_cat>-tabname = <fs_t_bseg>-tabname.
<fs_dyn_cat>-inttype = <fs_t_bseg>-inttype. "exid.
<fs_dyn_cat>-intlen = <fs_t_bseg>-intlen. "exlength.
<fs_dyn_cat>-decimals = <fs_t_bseg>-decimals.
<fs_dyn_cat>-dd_outlen = <fs_t_bseg>-outputlen. "dblength.
<fs_dyn_cat>-coltext = <fs_t_bseg>-reptext.
<fs_dyn_cat>-scrtext_l = <fs_t_bseg>-scrtext_s.
<fs_dyn_cat>-scrtext_m = <fs_t_bseg>-scrtext_m.
<fs_dyn_cat>-scrtext_s = <fs_t_bseg>-scrtext_l.
ENDIF.
ENDLOOP.
* Creacion de tabla dinamica (reference)
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = lt_dyn_fcat
IMPORTING
ep_table = p_xtable
EXCEPTIONS
generate_subpool_dir_full = 1
OTHERS = 2.
ENDIF.
ENDFORM. " F_TABLA_INTERNA
*&---------------------------------------------------------------------*
*& Form F_SELECCION_DATOS
*&---------------------------------------------------------------------*
* Seleccion de datos
*----------------------------------------------------------------------*
FORM f_seleccion_datos USING p_lt_union_1 TYPE tyt_campos
p_lt_union_2 TYPE tyt_campos
p_lt_campos_1 TYPE tyt_campos
p_lt_campos_2 TYPE tyt_campos
CHANGING p_xtable_3 TYPE REF TO data.
DATA: lv_inner TYPE string,
lv_campos TYPE string.
FIELD-SYMBOLS <fs_table_3> TYPE STANDARD TABLE.
ASSIGN p_xtable_3->* TO <fs_table_3>. " Puntero a tabla interna 2
** Obtención de condición where dinámicamente
* PERFORM f_obtencion_where USING p_union
* CHANGING lt_condicion.
PERFORM f_obtener_campos_visualizacion USING p_lt_campos_1
p_lt_campos_2
CHANGING lv_campos.
PERFORM f_obtener_inner USING p_t_1
p_t_2
p_lt_union_1
p_lt_union_2
CHANGING lv_inner.
SELECT (lv_campos) UP TO p_cant ROWS
FROM (lv_inner)
INTO TABLE <fs_table_3>.
* WHERE (lt_condicion).
ENDFORM. " F_SELECCION_DATOS
*&---------------------------------------------------------------------*
*& Form F_MOSTRAR_DATOS
*&---------------------------------------------------------------------*
* Mostramos resultado por medio de ALV
*----------------------------------------------------------------------*
FORM f_mostrar_datos USING p_lt_componentes TYPE tyt_dfies
p_lt_campos TYPE tyt_campos
p_lt_xtable TYPE REF TO data.
DATA: lr_functions TYPE REF TO cl_salv_functions,
ls_key TYPE salv_s_layout_key,
lr_toolbar TYPE REF TO cl_salv_functions_list,
lv_fe_ho TYPE string,
lr_obj_header TYPE REF TO cl_salv_form_layout_grid,
lv_header TYPE lvc_title,
lr_columns TYPE REF TO cl_salv_columns_table,
lr_display TYPE REF TO cl_salv_display_settings,
lr_sorts TYPE REF TO cl_salv_sorts,
gr_agg TYPE REF TO cl_salv_aggregations,
gr_agg2 TYPE REF TO cl_salv_aggregation,
lcx_data TYPE REF TO cx_salv_data_error,
lcx_not TYPE REF TO cx_salv_not_found,
lcx_msg TYPE REF TO cx_salv_msg,
lcx_exist TYPE REF TO cx_salv_existing,
lv_mensaje_err TYPE string,
lv_text_cab(60) TYPE c,
lc_x TYPE c VALUE 'X',
lc_usuario(08) TYPE c VALUE 'Usuario: ',
lc_fec_hr(13) TYPE c VALUE 'Fecha y Hora: ',
co_alv TYPE REF TO cl_salv_table.
FIELD-SYMBOLS: <fs_table> TYPE table.
ASSIGN p_lt_xtable->* TO <fs_table>. " Puntero a tabla interna
IF <fs_table> IS INITIAL .
MESSAGE text-009 TYPE 'S' DISPLAY LIKE 'E'.
EXIT.
ENDIF.
TRY.
CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = co_alv
CHANGING
t_table = <fs_table>.
CREATE OBJECT lr_obj_header.
* Header
lr_obj_header->create_grid( row = 2 column = 2 colspan = 6 ).
lr_obj_header->create_label( row = 1
column = 1
text = lc_usuario ).
lr_obj_header->create_label( row = 2
column = 1
text = lc_fec_hr ).
lr_obj_header->create_label( row = 1
column = 2
text = sy-uname ).
CONCATENATE ' ' sy-datum+6(2) '.' sy-datum+4(2)'.' sy-datum(4) ' - '
sy-uzeit(2)':' sy-uzeit+2(2) ':' sy-uzeit+4(2) INTO lv_fe_ho RESPECTING BLANKS.
lr_obj_header->create_label( row = 2
column = 2
text = lv_fe_ho ).
co_alv->set_top_of_list( lr_obj_header ). " Seteamos cabecera/ header
lr_columns = co_alv->get_columns( ).
lr_columns->set_optimize( lc_x ). " Optimizamos columnas
PERFORM change_name_columns USING p_lt_componentes
p_lt_campos
CHANGING lr_columns. " Cambiar nombre a las columnas
lr_toolbar = co_alv->get_functions( ).
lr_toolbar->set_all( abap_true ). " Habilitamos todas las opciones de herramientas disponibles
* CALL METHOD lr_toolbar->set_export_localfile " Habilitar descarga EXPORTINGvalue = abap_true. " habilitamos solo la descarga
* Sorts
lr_sorts = co_alv->get_sorts( ).
*
* lr_sorts->set_group_active( lc_x ).
* lr_sorts->add_sort( columnname = lc_belnr ).
* lr_sorts->add_sort( columnname = lc_status position = 1
* subtotal = lc_x
* sequence = if_salv_c_sort=>sort_up
* group = if_salv_c_sort=>group_none ).
* Display
lr_display = co_alv->get_display_settings( ).
lr_display->set_fit_column_to_table_size( lc_x ). " Ajustar visualización/ display
CLEAR lv_text_cab.
* Resultado
lv_text_cab = text-010.
MOVE lv_text_cab TO lv_header.
lr_display->set_list_header( lv_header ). " Título del reporte
co_alv->display( ).
CATCH cx_salv_data_error INTO lcx_data.
lv_mensaje_err = lcx_data->if_message~get_text( ).
CATCH cx_salv_not_found INTO lcx_not.
lv_mensaje_err = lcx_not->if_message~get_text( ).
CATCH cx_salv_existing INTO lcx_exist.
lv_mensaje_err = lcx_exist->if_message~get_text( ).
CATCH cx_salv_msg INTO lcx_msg.
lv_mensaje_err = lcx_msg->if_message~get_text( ).
ENDTRY.
ENDFORM. " F_MOSTRAR_DATOS
*&---------------------------------------------------------------------*
*& Form F_OBTENCION_WHERE
*&---------------------------------------------------------------------*
* Creación de where dinámicao para el Select
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM f_obtencion_where USING p_union TYPE string
CHANGING p_lt_condicion TYPE tyt_clause.
DATA : BEGIN OF gt_condtab OCCURS 0.
INCLUDE STRUCTURE hrcond.
DATA : END OF gt_condtab.
DATA: lt_campos TYPE tyt_campos,
ls_campo TYPE tys_campos.
FIELD-SYMBOLS <fs_wherecond> TYPE tys_clause.
SPLIT p_union AT space INTO TABLE lt_campos.
LOOP AT lt_campos INTO ls_campo.
gt_condtab-field = ls_campo-campo.
gt_condtab-opera = 'NE'.
CONCATENATE '<wa_table_1>-' ls_campo-campo INTO gt_condtab-low.
APPEND gt_condtab.
CLEAR gt_condtab.
ENDLOOP.
CALL FUNCTION 'RH_DYNAMIC_WHERE_BUILD'
EXPORTING
dbtable = space " can be empty
TABLES
condtab = gt_condtab
where_clause = p_lt_condicion
EXCEPTIONS
empty_condtab = 01
no_db_field = 02
unknown_db = 03
wrong_condition = 04.
ENDFORM. " F_OBTENCION_WHERE
*&---------------------------------------------------------------------*
*& Form CHANGE_NAME_COLUMNS
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* <--P_LR_COLUMNS text
*----------------------------------------------------------------------*
FORM change_name_columns USING p_lt_componentes TYPE tyt_dfies
p_lt_campos TYPE tyt_campos
CHANGING p_lr_columns TYPE REF TO cl_salv_columns_table.
DATA: lo_salv TYPE REF TO cx_salv_not_found,
lv_mensaje TYPE string,
ls_componente TYPE dfies, "x031l,
lo_column TYPE REF TO cl_salv_column_table, " Columna en particular
lt_dyn_fcat TYPE lvc_t_fcat,
lt_campos TYPE tyt_campos,
ls_campos TYPE tys_campos,
lr_campos TYPE RANGE OF fieldname,
lr_s_campos LIKE LINE OF lr_campos.
* Creamos rango de campos
lr_s_campos-sign = 'I'.
lr_s_campos-option = 'EQ'.
LOOP AT p_lt_campos INTO ls_campos.
lr_s_campos-low = ls_campos-campo.
APPEND lr_s_campos TO lr_campos.
ENDLOOP.
TRY.
LOOP AT p_lt_componentes INTO ls_componente WHERE fieldname IN lr_campos..
lo_column ?= p_lr_columns->get_column( ls_componente-fieldname ). " Obtener col
lo_column->set_long_text( ls_componente-scrtext_l ). " Set nombre largo
lo_column->set_medium_text( ls_componente-scrtext_m ). " Set nombre medio
lo_column->set_short_text( ls_componente-scrtext_s ). " Set nombre corto
lo_column->set_tooltip( ls_componente-scrtext_l ). " Set tooltip (descripción)
ENDLOOP.
CATCH cx_salv_not_found INTO lo_salv.
lo_salv->if_message~get_text( RECEIVING result = lv_mensaje ).
ENDTRY.
ENDFORM. " CHANGE_NAME_COLUMNS
*&---------------------------------------------------------------------*
*& Form F_MANEJAR_ERROR
*&---------------------------------------------------------------------*
* Manejo de erores
*----------------------------------------------------------------------*
* -->P_LV_ERROR Variable con número de mensaje
*----------------------------------------------------------------------*
FORM f_manejar_error USING p_lv_error TYPE p.
CASE p_lv_error.
WHEN 1.
MESSAGE text-001 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 2.
MESSAGE text-002 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 3.
MESSAGE text-003 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 4.
MESSAGE text-004 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 5.
MESSAGE text-005 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 6.
MESSAGE text-006 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 7.
MESSAGE text-012 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 8.
MESSAGE text-013 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 9.
MESSAGE text-014 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 10.
MESSAGE text-015 TYPE 'S' DISPLAY LIKE 'E'.
WHEN 11.
MESSAGE text-016 TYPE 'S' DISPLAY LIKE 'E'.
WHEN OTHERS.
ENDCASE.
ENDFORM. " F_MANEJAR_ERROR
*&-----------------------------------------------------------------------------*
*& Form F_OBTENER_CAMPOS_VISUALIZACION
*&-----------------------------------------------------------------------------*
* Obtenemos dinámicamente los campos a visualizar
*------------------------------------------------------------------------------*
* -->P_LT_CAMPOS Campos de visualización introducidos por pantala de selección
* <--P_LV_CAMPOS Campos en la selección
*------------------------------------------------------------------------------*
FORM f_obtener_campos_visualizacion USING p_lt_campos_1 TYPE tyt_campos
p_lt_campos_2 TYPE tyt_campos
CHANGING p_lv_campos TYPE string.
DATA ls_campos TYPE tys_campos.
* Campos de tabla 1
LOOP AT p_lt_campos_1 INTO ls_campos.
IF p_lv_campos IS INITIAL.
CONCATENATE 'a~'ls_campos-campo INTO p_lv_campos.
ELSE.
CONCATENATE p_lv_campos ' a~'ls_campos-campo INTO p_lv_campos.
ENDIF.
ENDLOOP.
* Campos de tabla 2
LOOP AT p_lt_campos_2 INTO ls_campos.
IF p_lv_campos IS INITIAL.
CONCATENATE 'b~'ls_campos-campo INTO p_lv_campos.
ELSE.
CONCATENATE p_lv_campos ' b~'ls_campos-campo INTO p_lv_campos.
ENDIF.
ENDLOOP.
ENDFORM. " F_OBTENER_CAMPOS_VISUALIZACION
*&---------------------------------------------------------------------*
*& Form F_OBTENER_INNER
*&---------------------------------------------------------------------*
* Obtener la sentencia INNER para nuestras tablas
*----------------------------------------------------------------------*
* -->P_T_1 Tabla 1 de unión
* -->P_T_2 Tabla 2 de unión
* -->P_LT_UNION_1 Campos de unión de tabla 1
* -->P_LT_UNION_2 Campos de unión de tabla 2
* <--P_LV_INNER String con sentencia de INNER
*----------------------------------------------------------------------*
FORM f_obtener_inner USING p_t_1 TYPE tabname
p_t_2 TYPE tabname
p_lt_union_1 TYPE tyt_campos
p_lt_union_2 TYPE tyt_campos
CHANGING p_lv_inner TYPE string.
DATA: ls_union_1 TYPE tys_campos,
ls_union_2 TYPE tys_campos.
CONCATENATE p_t_1 'as a INNER JOIN' p_t_2 'as b ON' INTO p_lv_inner SEPARATED BY space.
LOOP AT p_lt_union_1 INTO ls_union_1.
READ TABLE p_lt_union_2 INTO ls_union_2 INDEX sy-tabix.
CONCATENATE p_lv_inner ' b~' ls_union_2-campo ' = ' 'a~'ls_union_1-campo
INTO p_lv_inner RESPECTING BLANKS.
ENDLOOP.
ENDFORM. " F_OBTENER_INNER
zrda_select_dinamic_s01
*&---------------------------------------------------------------------*
*& Include ZRDA_SELECT_DINAMIC_S01
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-007.
PARAMETERS: p_t_1 TYPE dd03l-tabname OBLIGATORY, " Nombre de la tabla 1
p_t_2 TYPE dd03l-tabname OBLIGATORY. " Nombre de la tabla 2
SELECTION-SCREEN SKIP.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-008.
PARAMETERS: p_uni_1 TYPE string OBLIGATORY, " campos de union de tabla 1
p_uni_2 TYPE string OBLIGATORY, " campos de union de tabla 2
p_camp_1 TYPE string, " campos de tabla 1
p_camp_2 TYPE string. " campos de tabla 2
PARAMETERS: p_cant TYPE i DEFAULT 200.
SELECTION-SCREEN: END OF BLOCK b2.
SELECTION-SCREEN END OF BLOCK b1.
AT SELECTION-SCREEN.
IF p_camp_1 IS INITIAL AND
p_camp_2 IS INITIAL.
MESSAGE text-011 TYPE 'E'.
ENDIF.
zrda_select_dinamic_top
*&---------------------------------------------------------------------*
*& Include ZRDA_SELECT_DINAMIC_TOP
*&---------------------------------------------------------------------*
TYPES:
BEGIN OF tys_clause,
line(72) TYPE c,
END OF tys_clause,
tyt_clause TYPE STANDARD TABLE OF tys_clause,
BEGIN OF tys_campos,
campo(30) TYPE c,
END OF tys_campos,
tyt_campos TYPE STANDARD TABLE OF tys_campos,
BEGIN OF tys_fieldname,
fieldname TYPE fieldname,
END OF tys_fieldname,
tyt_fieldname TYPE STANDARD TABLE OF tys_fieldname,
tyt_dfies TYPE STANDARD TABLE OF dfies,
BEGIN OF tys_dd03l,
datatype TYPE datatype_d,
leng TYPE ddleng,
END OF tys_dd03l,
tyt_dd03l TYPE STANDARD TABLE OF tys_dd03l.
Existe dos subrutinas que no se usan, tranquilamente pueden borrarlas, son la f_all_campos y f_obtencion_where.
La causa principal de este “proyecto”, es obtener datos de prueba, me ha pasado de no tenerlos y tener que estar moviéndome entre tablas con la SE16N para obtener datos válidos. Para la próxima Fase del programa se usará la subrutina f_obtencion_where, para poder realizar un filtrado en el select.
El proceso de obtención de datos es completamente dinámico y realiza la unión por INNER JOIN.
Me gustaría que ABAPERS experimentados interesados vean el código y realicen una mirada crítica.