该功能可以根据用户在选择屏幕输入的表名、行数,动态创建内表、动态查询,然后根据获取到的数据进行ALV展示。
代码如下:
java
REPORT ZMYDEMO001.
DATA:
GV_TABNAME TYPE TABNAME,
GR_DATA_TABLE TYPE REF TO DATA,
LO_TYPEDESCR TYPE REF TO CL_ABAP_TYPEDESCR,
GO_STRUCT_DESCR TYPE REF TO CL_ABAP_STRUCTDESCR,
GO_TABLE_DESCR TYPE REF TO CL_ABAP_TABLEDESCR,
LV_LINE_COUNT TYPE I,
LV_TABCLASS TYPE TABCLASS,
LV_DOMNAME TYPE DOMNAME,
LV_SCRTEXT_S TYPE SCRTEXT_S.
* 字段描述存储(全版本兼容结构)
DATA: LT_DDFIELD TYPE STANDARD TABLE OF DFIES,
LS_DDFIELD TYPE DFIES.
DATA: LV_JSON_STRING TYPE STRING.
*----------------------------------------------------------------------*
* 字段符号声明
*----------------------------------------------------------------------*
FIELD-SYMBOLS:
<FT_DATA> TYPE ANY TABLE,
<FS_LINE> TYPE ANY,
<FS_FIELD> TYPE ANY.
*----------------------------------------------------------------------*
* 选择屏幕
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK B1.
PARAMETERS:
P_NAME TYPE TABNAME OBLIGATORY,
P_MAX TYPE I DEFAULT 500.
SELECTION-SCREEN END OF BLOCK B1.
*----------------------------------------------------------------------*
* 主程序
*----------------------------------------------------------------------*
START-OF-SELECTION.
" 1. 表名转大写
GV_TABNAME = P_NAME.
TRANSLATE GV_TABNAME TO UPPER CASE.
" 2. 验证表存在性和类型
SELECT SINGLE TABCLASS
INTO LV_TABCLASS
FROM DD02L
WHERE TABNAME = GV_TABNAME
AND AS4LOCAL = 'A'
AND AS4VERS = '0000'.
IF SY-SUBRC <> 0.
MESSAGE '错误:表不存在或未激活' TYPE 'E'.
ENDIF.
IF LV_TABCLASS <> 'TRANSP' AND LV_TABCLASS <> 'VIEW'.
MESSAGE '错误:只支持查询透明表和视图' TYPE 'E'.
ENDIF.
" 3. 读取字段描述(内置类型+数据元素双保险)(重要步骤)
PERFORM GET_FIELD_DESC_ULTIMATE USING GV_TABNAME CHANGING LT_DDFIELD.
" 4. 动态创建内表(核心步骤)
TRY.
LO_TYPEDESCR = CL_ABAP_STRUCTDESCR=>DESCRIBE_BY_NAME( GV_TABNAME ).
GO_STRUCT_DESCR ?= LO_TYPEDESCR.
GO_TABLE_DESCR = CL_ABAP_TABLEDESCR=>CREATE(
P_LINE_TYPE = GO_STRUCT_DESCR
P_TABLE_KIND = CL_ABAP_TABLEDESCR=>TABLEKIND_STD ).
CREATE DATA GR_DATA_TABLE TYPE HANDLE GO_TABLE_DESCR.
CATCH CX_ROOT INTO DATA(LX_CREATE).
MESSAGE '动态创建内表失败: ' && LX_CREATE->GET_TEXT( ) TYPE 'E'.
ENDTRY.
" 5. 分配字段符号
ASSIGN GR_DATA_TABLE->* TO <FT_DATA>.
IF <FT_DATA> IS NOT ASSIGNED.
MESSAGE '错误:无法分配内表字段符号' TYPE 'E'.
ENDIF.
" 6. 动态查询数据
IF P_MAX <= 0 OR P_MAX > 2000.
P_MAX = 500.
ENDIF.
TRY.
SELECT * UP TO P_MAX ROWS INTO TABLE <FT_DATA> FROM (GV_TABNAME).
IF SY-SUBRC <> 0.
MESSAGE 'SQL查询失败: 没有找到数据' TYPE 'I'.
ENDIF.
CATCH CX_ROOT INTO DATA(LX_SELECT).
MESSAGE 'SQL查询失败: ' && LX_SELECT->GET_TEXT( ) TYPE 'E'.
ENDTRY.
"ALV展示
PERFORM SHOW_DATA_ALV.
*----------------------------------------------------------------------*
* 子例程1:读取字段描述(内置类型+数据元素全支持)
*----------------------------------------------------------------------*
FORM GET_FIELD_DESC_ULTIMATE USING IV_TAB TYPE TABNAME CHANGING CT_FLD TYPE DFIES_TAB.
CALL FUNCTION 'DDIF_FIELDINFO_GET'
EXPORTING
TABNAME = IV_TAB
LANGU = SY-LANGU
ALL_TYPES = 'X'
TABLES
DFIES_TAB = CT_FLD
EXCEPTIONS
OTHERS = 1.
IF SY-SUBRC <> 0.
MESSAGE '获取字段信息失败' TYPE 'E'.
ENDIF.
" 为内置类型字段补全描述
LOOP AT CT_FLD INTO LS_DDFIELD.
IF LS_DDFIELD-ROLLNAME IS INITIAL.
" 尝试1:从DD03T获取表字段专属文本
SELECT SINGLE DDTEXT
INTO LS_DDFIELD-SCRTEXT_S
FROM DD03T
WHERE TABNAME = IV_TAB
AND FIELDNAME = LS_DDFIELD-FIELDNAME
AND DDLANGUAGE = SY-LANGU.
" 尝试2:从域文本表获取描述
IF LS_DDFIELD-SCRTEXT_S IS INITIAL AND LS_DDFIELD-DOMNAME IS NOT INITIAL.
SELECT SINGLE DDTEXT
INTO LS_DDFIELD-SCRTEXT_S
FROM DD07T
WHERE DOMNAME = LS_DDFIELD-DOMNAME
AND DDLANGUAGE = SY-LANGU.
ENDIF.
" 尝试3:兜底方案
IF LS_DDFIELD-SCRTEXT_S IS INITIAL.
CONCATENATE LS_DDFIELD-FIELDNAME '(' LS_DDFIELD-INTTYPE ')' INTO LS_DDFIELD-SCRTEXT_S.
ENDIF.
MODIFY CT_FLD FROM LS_DDFIELD.
ENDIF.
ENDLOOP.
ENDFORM.
*----------------------------------------------------------------------*
* 子例程2:ALV显示
*----------------------------------------------------------------------*
FORM SHOW_DATA_ALV.
DATA: LO_ALV TYPE REF TO CL_SALV_TABLE,
LO_COLS TYPE REF TO CL_SALV_COLUMNS_TABLE,
LO_COL TYPE REF TO CL_SALV_COLUMN_TABLE,
LV_TEXT TYPE SCRTEXT_S.
TRY.
CL_SALV_TABLE=>FACTORY( IMPORTING R_SALV_TABLE = LO_ALV CHANGING T_TABLE = <FT_DATA> ).
LO_COLS = LO_ALV->GET_COLUMNS( ).
LO_COLS->SET_OPTIMIZE( ABAP_TRUE ).
LOOP AT LT_DDFIELD INTO LS_DDFIELD.
TRY.
LO_COL ?= LO_COLS->GET_COLUMN( LS_DDFIELD-FIELDNAME ).
IF LS_DDFIELD-SCRTEXT_S IS NOT INITIAL.
LV_TEXT = LS_DDFIELD-SCRTEXT_S.
ELSE.
LV_TEXT = LS_DDFIELD-FIELDNAME.
ENDIF.
LO_COL->SET_SHORT_TEXT( LV_TEXT ).
CATCH CX_ROOT.
CONTINUE.
ENDTRY.
ENDLOOP.
LO_ALV->DISPLAY( ).
CATCH CX_ROOT.
" ALV异常时降级输出
LOOP AT <FT_DATA> ASSIGNING <FS_LINE>.
WRITE: / <FS_LINE>.
ENDLOOP.
ENDTRY.
ENDFORM.