Programa/ALV unión de dos tablas de forma dinámica

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:

  1. Ingresar los nombres de las tablas.
  2. 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).
  3. Ingresar los campos de visualización, uno puede elegir que campos de la tabla 1 y de la tabla 2 quiere visualizar.
  4. 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.

7 Me gusta