前言
Number Ranger Object 是在 SAP 系统中创建并包含一组已定义的唯一字符串的对象。 应用程序可以使用Number Ranger Object为数据库记录提供唯一Key。
这里是一些Number Ranger 的一些使用技巧和知识点,仅供参考。
一、基础使用
1. 根据年度流水
勾选截止年份标识
按照年份分别维护对应号码段间隔
获取时,年份字段传参
测试
2. 根据子对象(如公司代码等)分别流水
填写子对象对应数据元素
维护时会分别维护各个子对象下的间隔
代码传参
3. 延伸-根据月度流水
第一种:子对象为年月,或者按年流水,子对象为月份。
需要维护每个月份的号码段间隔,间隔的维护可以手动导入,也可以在获取流水号时判断如果当前月份无对应间隔维护时,自动生成.文末有附间隔导入对应程序,可供参考.
第二种:按月份清空NR状态 ,可在每月1号的凌晨清空当前号码段间隔
参考函数NUMBER_RANGE_INTERVAL_INIT
PS:也可以延伸出其它一些各种需求的流水号形式,相对来说虽然比较麻烦,但是还是优于通过自建表或者最大值+1的处理方式.。
4. 生成间隔对应的维护事务代码
在号码段编辑页面,输入编号范围事务,会在保存的时候自动生成对应事务码用来维护号码段间隔,这样就很方便。
二、知识点
1. 跳号
跳号的原因:
其一:服务器会将固定数目的流水号缓存下来,如果重启应用程序服务器实例,则缓存丢失,导致号码丢失.
其二: 先获取的号码没有commit,后获取的号码commit了(不绝对)
解决:可以设置无缓冲,或者设置并行缓存
注:
1. RSSNR0S1 可在并行缓存时查看未分配的号码
2. 无缓冲可能会减慢号码段流水号的获取速度,特别是多服务器的场景下
2. 剩余号码警告
早期的一些文档会写成到达多少百分比,而不是剩余
3. 外部给号
勾选外部编号,表示该号码段中号码为外部提供,使用NUMBER_CHECK检查是否在范围内,该检查不检查是否使用等情况。(此时不能使用函数获取下一个流水号)
4. 查看缓存中的号码
可以查看系统中目前号码段的缓存数据,可以结合debug解决部分主键重复的dump问题
5. 组页签配置
可以理解为将号码段配置根据组表字段分组,不常用,感兴趣的可以查看官方文档
示例号码段: TEST2,TEST5,TEST6,TEST7,TEST8
附2:号码段间隔导入程序
*&---------------------------------------------------------------------*
*& Report ZR_IMPORT_NUMRANGE
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zr_import_numrange.
* ALV 参数
DATA: gt_fieldcat TYPE lvc_t_fcat, "字段目录内表
gs_fieldcat TYPE lvc_s_fcat, "字段目录工作区
gs_layout TYPE lvc_s_layo. "用于定义ALV表单的相关格式、属性
* 声明OLE变量
DATA: gs_excel TYPE ole2_object,
gs_sheet TYPE ole2_object,
gs_cellhead TYPE ole2_object,
gs_cell1 TYPE ole2_object,
gs_cell2 TYPE ole2_object,
gs_range TYPE ole2_object,
gs_workbook TYPE ole2_object.
DATA: gt_tab TYPE TABLE OF alsmex_tabline,
gs_tab TYPE alsmex_tabline,
gv_col_count TYPE i.
DATA: gv_count TYPE i,
gv_length TYPE i.
DATA: gr_table TYPE REF TO data,
gr_line TYPE REF TO data.
*&---------------------------------------------------------------------*
* 指针定义
*&---------------------------------------------------------------------*
FIELD-SYMBOLS: <gt_table> TYPE STANDARD TABLE,
<gs_area> TYPE any,
<gs_field> TYPE any,
<gs_struc> TYPE any.
*&---------------------------------------------------------------------*
* 选择屏幕
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
PARAMETERS:p_fn LIKE rlgrap-filename DEFAULT 'C:\' OBLIGATORY MODIF ID ty1. "文件路径
PARAMETERS:p_object TYPE tnro-object OBLIGATORY DEFAULT 'Z*' MODIF ID ty1.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
PARAMETERS: p_r1 RADIOBUTTON GROUP r1 DEFAULT 'X' USER-COMMAND uc1,
p_r2 RADIOBUTTON GROUP r1.
SELECTION-SCREEN END OF BLOCK b2.
*&---------------------------------------------------------------------*
* 初始化
*&---------------------------------------------------------------------*
INITIALIZATION.
*&--------------------------------------------------------------------*
* 选择屏幕开始 *
*&--------------------------------------------------------------------*
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
CASE screen-group1.
WHEN 'TY1'.
IF p_r1 = 'X'.
screen-active = '1'.
ELSE.
screen-active = '0'.
ENDIF.
ENDCASE.
MODIFY SCREEN.
ENDLOOP.
AT SELECTION-SCREEN.
CLEAR sy-ucomm.
*&---------------------------------------------------------------------*
* 选择屏幕搜索帮助
*&---------------------------------------------------------------------*
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_fn.
PERFORM frm_get_fn. "取主数据文件路径
*&---------------------------------------------------------------------*
* 执行选择屏幕
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM frm_create_dynamic_table. " 创建动态内表
IF p_r1 = 'X'." 数据上载
PERFORM frm_upload_data. "上传文件到内表
* 设置输出格式
PERFORM frm_set_layout.
* 显示ALV
PERFORM frm_display_alv.
ENDIF.
IF p_r2 = 'X'." 模板下载
PERFORM frm_download.
ENDIF.
END-OF-SELECTION.
*&------------------------------------------------------------------------*
*& Form FRM_GET_FN
*&------------------------------------------------------------------------*
* text
*&---------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_get_fn .
CALL FUNCTION 'KD_GET_FILENAME_ON_F4'
CHANGING
file_name = p_fn.
ENDFORM. " FRM_GET_FN
*&------------------------------------------------------------------------*
*& Form FRM_CREATE_DYNAMIC_TABLE
*&------------------------------------------------------------------------*
* text
*&---------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_create_dynamic_table .
DATA: lv_col_pos TYPE i.
DATA: lr_tabdescr TYPE REF TO cl_abap_structdescr,
lt_dfies TYPE ddfields,
ls_dfies TYPE dfies.
lr_tabdescr ?= cl_abap_structdescr=>describe_by_name( 'INRIV' ).
lt_dfies = cl_salv_data_descr=>read_structdescr( lr_tabdescr ).
LOOP AT lt_dfies INTO ls_dfies.
MOVE-CORRESPONDING ls_dfies TO gs_fieldcat.
APPEND gs_fieldcat TO gt_fieldcat.
CLEAR gs_fieldcat.
ENDLOOP.
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = gt_fieldcat
IMPORTING
ep_table = gr_table.
ASSIGN gr_table->* TO <gt_table>.
ENDFORM.
*&------------------------------------------------------------------------*
*& Form FRM_UPLOAD_DATA
*&------------------------------------------------------------------------*
* 数据上传
*&---------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_upload_data .
DATA: lt_return TYPE bapiret2_t.
gv_col_count = lines( gt_fieldcat ).
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
EXPORTING
filename = p_fn
i_begin_col = 1
i_begin_row = 1
i_end_col = gv_col_count
i_end_row = 5000
* sheet_name = 1
TABLES
intern = gt_tab
EXCEPTIONS
inconsistent_parameters = 1
upload_ole = 2
OTHERS = 3.
IF sy-subrc = 0.
DELETE gt_tab WHERE row = 1. "删除字段名行
LOOP AT gt_tab INTO gs_tab.
AT NEW row.
APPEND INITIAL LINE TO <gt_table> ASSIGNING <gs_struc>.
ENDAT.
ASSIGN COMPONENT gs_tab-col OF STRUCTURE <gs_struc> TO <gs_field>.
IF sy-subrc = 0.
<gs_field> = gs_tab-value.
ENDIF.
ENDLOOP.
ENDIF.
ENDFORM. " FRM_UPLOAD_DATA
*&------------------------------------------------------------------------*
*& Form FRM_INPUT_DATA
*&------------------------------------------------------------------------*
* 数据更新
*&---------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_input_data .
DATA: lv_error_occured TYPE char1,
lv_warning_occured TYPE char1.
DATA: lt_error_iv TYPE TABLE OF inriv,
lt_intervals TYPE TABLE OF inriv,
ls_intervals TYPE inriv.
DATA: lt_interval_have TYPE STANDARD TABLE OF inriv,
ls_interval_have TYPE inriv.
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_LIST'
EXPORTING
object = p_object
TABLES
interval = lt_interval_have
EXCEPTIONS
nr_range_nr1_not_found = 1
nr_range_nr1_not_intern = 2
nr_range_nr2_must_be_space = 3
nr_range_nr2_not_extern = 4
nr_range_nr2_not_found = 5
object_not_found = 6
subobject_must_be_space = 7
subobject_not_found = 8
OTHERS = 9.
MOVE-CORRESPONDING <gt_table> TO lt_intervals.
LOOP AT lt_interval_have INTO ls_interval_have.
READ TABLE lt_intervals INTO ls_intervals WITH KEY subobject = ls_interval_have-subobject
nrrangenr = ls_interval_have-nrrangenr
toyear = ls_interval_have-toyear.
IF sy-subrc = 0.
IF ls_intervals-procind <> 'D'.
ls_intervals-procind = 'U'.
MODIFY lt_intervals FROM ls_intervals INDEX sy-tabix.
ENDIF.
ELSE.
APPEND ls_interval_have TO lt_intervals.
ENDIF.
ENDLOOP.
CALL FUNCTION 'NUMBER_RANGE_UPDATE_INIT'
EXPORTING
object = p_object
EXCEPTIONS
object_not_found = 1.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_UPDATE'
EXPORTING
object = p_object
* subobject = P_subobject
IMPORTING
* error = lt_error
error_occured = lv_error_occured
warning_occured = lv_warning_occured
TABLES
error_iv = lt_error_iv
interval = lt_intervals.
IF lv_error_occured = space.
CALL FUNCTION 'NUMBER_RANGE_UPDATE_CLOSE'
EXPORTING
object = p_object
EXCEPTIONS
no_changes_made = 1. "#EC *
COMMIT WORK AND WAIT.
MESSAGE 'Number range import sucesss' TYPE 'S'.
ELSE.
MESSAGE 'Number range import ERROR' TYPE 'S' DISPLAY LIKE 'E'.
ENDIF.
ENDFORM.
*&------------------------------------------------------------------------*
*& Form FRM_DOWNLOAD
*&------------------------------------------------------------------------*
* 模板下载
*&---------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*&---------------------------------------------------------------------*
FORM frm_download .
DATA: lv_filename TYPE string, "下载文件名
lv_wintitle TYPE string, "下载对话框标题名
lv_filepath TYPE string, "文件路径
lv_fullpath TYPE string. "全文件路径
DATA lv_pos TYPE dd03l-position .
CALL METHOD cl_gui_frontend_services=>file_save_dialog
EXPORTING
window_title = lv_wintitle "对话框的标题
file_filter = '.xls' "文件的filter
CHANGING
filename = lv_filename "保存的文件名
path = lv_filepath "文件路径
fullpath = lv_fullpath "全文件路径
* USER_ACTION =
EXCEPTIONS
cntl_error = 1
error_no_gui = 2
OTHERS = 3.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
IF lv_fullpath IS NOT INITIAL.
" 保存模版
PERFORM frm_save_excel USING lv_fullpath.
MESSAGE s208(00) WITH TEXT-011.
ENDIF.
ENDFORM. " FRM_DOWNLOAD
*----------------------------------------------------------------------*
* *设置输出格式
*----------------------------------------------------------------------*
FORM frm_set_layout.
CLEAR gs_layout.
gs_layout-sel_mode = 'A'. "设置行模式"
gs_layout-cwidth_opt = 'X'. "优化列宽设置"
gs_layout-zebra = 'X'. "设置斑马线"
ENDFORM.
*----------------------------------------------------------------------*
* **显示ALV
*----------------------------------------------------------------------*
FORM frm_display_alv.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
EXPORTING
i_callback_program = sy-repid "当前程序
is_layout_lvc = gs_layout "界面格式"
it_fieldcat_lvc = gt_fieldcat "字段属性"
i_callback_pf_status_set = 'SET_PF_STATUS' "状态
i_callback_user_command = 'ALV_USER_COMMAND' "控制指令
TABLES
t_outtab = <gt_table>.
ENDFORM.
*----------------------------------------------------------------------*
* 响应触发事件
*----------------------------------------------------------------------*
FORM alv_user_command USING pv_ucomm LIKE sy-ucomm
ps_selfield TYPE slis_selfield.
DATA: lo_ref_grid TYPE REF TO cl_gui_alv_grid.
CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
IMPORTING
e_grid = lo_ref_grid. "获取全局变量
CALL METHOD lo_ref_grid->check_changed_data."获取响应事件
ps_selfield-refresh = 'X'.
CASE pv_ucomm."用户操作事件
WHEN '&IMPORT'."导入
PERFORM frm_input_data.
CALL METHOD lo_ref_grid->check_changed_data."获取响应事件
ps_selfield-refresh = 'X'.
WHEN OTHERS.
ENDCASE.
ENDFORM.
**定义界面状态栏
FORM set_pf_status
USING pt_extab TYPE slis_t_extab.
"参照程序 SAPLKKBL 里面的 STANDARD_FULLSCREEN
SET PF-STATUS 'STANDARD'."自定义状态名称
ENDFORM.
*&------使用OLE操作EXCEL填充数据并导出
FORM frm_save_excel USING pv_fullpath TYPE string.
* 启动excel
CREATE OBJECT gs_excel 'EXCEL.APPLICATION'.
IF sy-subrc <> 0 .
WRITE: / 'ERROR'.
STOP.
ENDIF.
* 启动工作簿
CALL METHOD OF
gs_excel
'WORKBOOKS' = gs_workbook.
* 使excel不可视
SET PROPERTY OF gs_excel 'VISIBLE' = 0.
* 建立worksheet
SET PROPERTY OF gs_excel 'SHEETSINNEWWORKBOOK' = 1. "如果是读取excel文件中的内容 则是直接打开工作簿第一页
CALL METHOD OF
gs_workbook
'ADD'.
* 激活SHEET
CALL METHOD OF
gs_excel
'WORKSHEETS' = gs_sheet
EXPORTING
#1 = 1.
LOOP AT gt_fieldcat INTO gs_fieldcat.
gv_count = gv_count + 1.
gv_length = gs_fieldcat-intlen.
PERFORM frm_set_property USING gv_count gv_length.
CALL METHOD OF gs_sheet 'Cells' = gs_cellhead EXPORTING #1 = 1 #2 = gv_count.
SET PROPERTY OF gs_cellhead 'value' = gs_fieldcat-scrtext_l.
ENDLOOP.
* 存入文件
GET PROPERTY OF gs_excel 'ACTIVESHEET' = gs_sheet.
GET PROPERTY OF gs_excel 'ACTIVEWORKBOOK' = gs_workbook.
WAIT UP TO 1 SECONDS.
CALL METHOD OF
gs_sheet
'SAVEAS'
EXPORTING
#1 = pv_fullpath
#2 = 1. "将excel文件保存为 FN1 路径
CALL METHOD OF gs_workbook 'CLOSE'. "关闭工作区
CALL METHOD OF gs_excel 'QUIT'. " 退出excel
* 释放操作
FREE OBJECT gs_sheet.
FREE OBJECT gs_workbook.
FREE OBJECT gs_excel.
FREE OBJECT gs_range.
FREE OBJECT gs_cellhead.
ENDFORM.
FORM frm_set_property USING pv_col TYPE i pv_length TYPE i.
DATA lv_str TYPE string.
* 设置单元格格式带前导零
CALL METHOD OF
gs_sheet
'Cells' = gs_cell1
EXPORTING
#1 = 2
#2 = pv_col. "起始单元格
CALL METHOD OF
gs_sheet
'Cells' = gs_cell2
EXPORTING
#1 = 999
#2 = pv_col. "结束单元格
CALL METHOD OF
gs_sheet
'gs_range' = gs_range
EXPORTING
#1 = gs_cell1
#2 = gs_cell2. "设置区域(从3行1列 到 999行1列)
DO pv_length TIMES.
CONCATENATE lv_str '0' INTO lv_str.
ENDDO.
SET PROPERTY OF gs_range 'NumberFormatLocal' = lv_str."设置单元格格式
ENDFORM.