A(id:10,name:aa,gen:f)
B(id:20,gen:m,dm:01)
move-corresponding A to B.
—>B(id:10,gen:f,dm:01).
B如果有与A相同的Key,则替换对应的Value。
CONTINUE:用于结束当前循环,剩下的代码块不执行,进入下一循环。
CHECK 检查condition是否为真,如果为真就结束循环。
EXIT:立即结束循环并执行ENDDO、ENDWHILE、ENDSELECT,对于嵌套循环,只结束本循环,对其它层循环不影响。
CONSTANTS:gv_data TYPE string VALUE '类似于JAVA的FINAL'
用于定义固定值,该固定值不可改变
AT FIRST 循环开始时执行
AT LAST 循环结束时执行
AT NEW 出现新的 数据(非数字字段) 时执行
AT END
CLEAR用于清空不带表头的表。
REFRESH用于清空内表
RSPARAMS是select-options和parameters的通用结构,如图:
调用=='RS_REFRESH_FROM_SELECTOPTIONS’可以将s和p的值存入函数内表GIT_PARAMS[]==中,s的KIND为‘S’,p的KIND为‘P’,可以根据不同的KIND循环选出需要的值。
TABLES: MARA.
DATA:GIT_PARAMS TYPE TABLE OF RSPARAMS.
DATA:GWA_PARAMS TYPE RSPARAMS.
*&---------------------------------------------------------------------*
*& Selection Screen
*&---------------------------------------------------------------------*
SELECT-OPTIONS:S_MATNR FOR MARA-MATNR.
PARAMETERS:P_MTART TYPE MARA-MTART.
PARAMETERS:P_MATKL TYPE MARA-MATKL.
*&---------------------------------------------------------------------*
*& Start of Selection
*&---------------------------------------------------------------------*
START-OF-SELECTION.
CALL FUNCTION 'RS_REFRESH_FROM_SELECTOPTIONS'
EXPORTING
CURR_REPORT = SY-REPID
TABLES
SELECTION_TABLE = GIT_PARAMS[].
SORT GIT_PARAMS BY KIND.
WRITE:/ 'Parameters'.
WRITE:/ 'Name' ,20 'Value' .
LOOP AT GIT_PARAMS INTO GWA_PARAMS WHERE KIND = 'P'.
WRITE:/ GWA_PARAMS-SELNAME ,20 GWA_PARAMS-LOW.
ENDLOOP.
SKIP.
WRITE:/ 'Select-Options'.
WRITE:/ 'Name' ,20 'Sign' ,25 'Option',32 'Low',52 'High'.
LOOP AT GIT_PARAMS INTO GWA_PARAMS WHERE KIND = 'S'.
WRITE:/ GWA_PARAMS-SELNAME ,20 GWA_PARAMS-SIGN ,
25 GWA_PARAMS-OPTION, 32 GWA_PARAMS-LOW,
52 GWA_PARAMS-HIGH.
ENDLOOP.
在页头执行
**AT SELECTION-SCREEN OUTPUT **用于设置画面属性
设置AT SELECTION-SCREEN OUTPUT:
用于动态显示屏幕
屏幕设计
TABLES:EKKO.
SELECTION-SCREEN BEGIN OF BLOCK BLK01 WITH FRAME.
PARAMETERS:P_MAINT RADIOBUTTON GROUP G1 USER-COMMAND ACTIVE,
P_QUERY RADIOBUTTON GROUP G1 DEFAULT 'X' .
SELECTION-SCREEN END OF BLOCK BLK01.
SELECTION-SCREEN BEGIN OF BLOCK BLK02 WITH FRAME.
SELECT-OPTIONS: S_EBELN FOR EKKO-EBELN MODIF ID M1,
S_BUKRS FOR EKKO-BUKRS MODIF ID M1,
S_EKORG FOR EKKO-EKORG MODIF ID M1.
SELECTION-SCREEN END OF BLOCK BLK02.
屏幕显示逻辑
AT SELECTION-SCREEN OUTPUT.
LOOP AT SCREEN.
CASE SCREEN-GROUP1.
WHEN 'M1'.
IF P_MAINT = 'X'.
SCREEN-ACTIVE = '0'.
ELSE.
SCREEN-ACTIVE = '1'.
ENDIF.
MODIFY SCREEN.
ENDCASE.
ENDLOOP.
T-CODE :se11
通过调用从锁对象的定义自动生成的特定功能模块,在在线事务的编程中请求和释放锁定。必须在 ABAP 字典中显式创建这些锁对象。
注意事项
创建
填写对应信息并激活
点击锁模块查看生成的FM模块
在需要的程序调用即可
PERFORM FRM_LOCK_DATA USING LST_CJ-EMPID "加锁,传入主键
CHANGING O_SUBRC.
PERFORM FRM_UNLOCK_DATA USING LST_CJ-EMPID. "解锁
FORM FRM_LOCK_DATA USING P_LST_CJ_EMPID
CHANGING P_O_SUBRC.
CALL FUNCTION 'ENQUEUE_EZXXXX_01'
EXPORTING
MODE_ZTXXXXCJ = 'E'
MANDT = SY-MANDT
EMPID = P_LST_CJ_EMPID
* X_EMPID = ' '
* _SCOPE = '2'
* _WAIT = ' '
* _COLLECT = ' '
EXCEPTIONS
FOREIGN_LOCK = 1
SYSTEM_FAILURE = 2
OTHERS = 3
.
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form FRM_UNLOCK_DATA
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->P_LST_CJ_EMPID text
*----------------------------------------------------------------------*
FORM FRM_UNLOCK_DATA USING P_LST_CJ_EMPID.
CALL FUNCTION 'DEQUEUE_EZXXXX_01'
EXPORTING
MODE_ZTXXXXCJ = 'E'
MANDT = SY-MANDT
EMPID = P_LST_CJ_EMPID.
* X_EMPID = ' '
* _SCOPE = '3'
* _SYNCHRON = ' '
* _COLLECT = ' '
ENDFORM.
DESCRIBE TABLE lt_mat LINES lv_cont.
DESCRIBE FIELD el.
描述数据元素的属性,包括长度、类型、小数点等信息
DESCRIBE FIELD dobj
[TYPE typ [COMPONENTS com]]
[LENGTH ilen IN { BYTE | CHARACTER } MODE]
[DECIMALS dec]
[OUTPUT-LENGTH olen]
[HELP-ID hlp]
[EDIT MASK mask].
typ里放类型,com里放el的子元素,ilen里放长度,dec里放小数位数、olen里放输出长度,
DESCRIBE TABLE itab KIND knd.
CLEAR用于清理内表和工作区
对于有表头的内表WA_DATA,CLEAR WA_DATA表示清除工作区域,CLEAR WA_DATA[] 表示清除内表区域内不清楚工作区域。
REFRESH专门用于清理内表
FREE会清除内表并释放所占空间。
读取Excel表到SAP内表:
屏幕定义
*----------------------------------------------------------------------*
* 选择画面定义
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK BLK01 WITH FRAME.
PARAMETERS:P_FILE LIKE RLGRAP-FILENAME. "FILE SELECT PARAMETRER
SELECTION-SCREEN END OF BLOCK BLK01.
打开选择文件
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG "用于选择文件
EXPORTING
WINDOW_TITLE = 'OPEN FILE'
INITIAL_DIRECTORY = 'C:\' "选择文件打开的初始路径
CHANGING
FILE_TABLE = GT_FILE
RC = GW_RC
EXCEPTIONS
FILE_OPEN_DIALOG_FAILED = 1
CNTL_ERROR = 2
ERROR_NO_GUI = 3
NOT_SUPPORTED_BY_GUI = 4
OTHERS = 5.
IF SY-SUBRC <> 0.
ENDIF.
READ TABLE GT_FILE INTO GST_FILE INDEX 1.
P_FILE = GST_FILE-FILENAME. "将文件名赋值给P_FILE
读取P_FILE路径下的Excel文件到内表GT_DATA。
DATA: LWK_FILENAME TYPE RLGRAP-FILENAME, "字符串
LT_DATA TYPE TRUXS_T_TEXT_DATA.
LWK_FILENAME = P_FILE.
CALL FUNCTION 'TEXT_CONVERT_XLS_TO_SAP' "读取数据到内表
EXPORTING
* I_FIELD_SEPERATOR =
I_LINE_HEADER = 'X'
I_TAB_RAW_DATA = LT_DATA
I_FILENAME = LWK_FILENAME
TABLES
I_TAB_CONVERTED_DATA = GT_DATA
EXCEPTIONS
CONVERSION_FAILED = 1
OTHERS = 2.
上传模板:输入T-CODE SMW0上传模板,Web对象选择"WebRFC应用程序的二进制数据",然后新建上传即可。
模板下载:
使用以下FORM即可。
FORM FRM_TEMP_DOWNLOAD .
DATA: LWA_WWWDATA_TAB LIKE WWWDATATAB,
L_FILENAME TYPE RLGRAP-FILENAME.
READ TABLE GT_FILE INTO GS_FILE INDEX 1.
L_FILENAME = GS_FILE-FILENAME. "下载路径
SELECT SINGLE *
FROM WWWDATA
INNER JOIN TADIR
ON WWWDATA~OBJID = TADIR~OBJ_NAME
INTO CORRESPONDING FIELDS OF LWA_WWWDATA_TAB
WHERE WWWDATA~SRTF2 = 0
AND WWWDATA~RELID = 'MI' "标识二进制的对象
AND TADIR~PGMID = 'R3TR'
AND TADIR~OBJECT = 'W3MI'
AND TADIR~OBJ_NAME = 'ZTEMP_XXXX_01'."模板名字
IF SY-SUBRC = 0.
CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
EXPORTING
KEY = LWA_WWWDATA_TAB
DESTINATION = L_FILENAME.
MESSAGE '模板已下载到桌面' TYPE 'S'.
ENDIF.
ENDFORM.
DATA: GT_FILE TYPE FILETABLE,
GW_RC TYPE I.
FORM FRM_FILE_SEL .
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG "用于选择文件
EXPORTING
WINDOW_TITLE = 'OPEN FILE' "选择窗口名字
INITIAL_DIRECTORY = 'C:\' "选择初始路径
FILE_FILTER = CL_GUI_FRONTEND_SERVICES=>FILETYPE_EXCEL "过滤Excel类型文件
CHANGING
FILE_TABLE = GT_FILE
RC = GW_RC
EXCEPTIONS
FILE_OPEN_DIALOG_FAILED = 1
CNTL_ERROR = 2
ERROR_NO_GUI = 3
NOT_SUPPORTED_BY_GUI = 4
OTHERS = 5.
IF SY-SUBRC <> 0.
ENDIF.
ENDFORM.
方法二:
DATA: GV_FILENAME TYPE STRING,
GV_PATH TYPE STRING,
GV_FULLPATH TYPE STRING.
DATA: LV_FILE TYPE RLGRAP-FILENAME,
LV_OBJID TYPE WWWDATA-OBJID,
LS_KEY LIKE WWWDATATAB,
LV_SUBRC TYPE SY-SUBRC,
LV_DEFAULT_FILE_NAME TYPE STRING.
LV_DEFAULT_FILE_NAME = '批量修改资产卡片导入模板.xlsx'. "默认的文件名
*&--------获得要保存文件的路径名
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_SAVE_DIALOG
EXPORTING
WINDOW_TITLE = '请选择路径'
DEFAULT_FILE_NAME = LV_DEFAULT_FILE_NAME
FILE_FILTER = 'Excel 文件 (*.xls)'
CHANGING
FILENAME = GV_FILENAME
PATH = GV_PATH
FULLPATH = GV_FULLPATH
EXCEPTIONS
CNTL_ERROR = 1
ERROR_NO_GUI = 2
NOT_SUPPORTED_BY_GUI = 3
OTHERS = 4.
IF GV_PATH IS INITIAL.
MESSAGE '已取消下载' TYPE 'W'. "如果用户取消选择下载路径,那么相当于取消下载,结束程序
EXIT.
ENDIF.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
EXIT.
ENDIF.
定义指针直接改变内表值
示例:
LOOP AT GT_DATA ASSIGNING FIELD-SYMBOL().
-NUM = '1'.
-AGE = '10'.
ENDLOOP.
示例代码作用:将内表GT_DATA的每一行的NUM和AGE字段分别改为“1”和“10”。
LOOP AT GT_DATA ASSIGNING FIELD-SYMBOL() GROUP BY ( KEY1 = -HEADID KEY2 = ... ) ASSIGNING FIELD-SYMBOL().
LOOP AT GROUP ASSIGNING FIELD-SYMBOL().
-BUKRS = ...
-BLART = ...
-BLDAT = ...
-BUDAT = ...
ENDLOOP.
....
ENDLOOP.
对于上图所示数据 相同的凭证序号表示为同一组数据 在使用bapi进行操作时需要将同一凭证的数据导入到对应的内表中 处理起来就比较繁琐
可以使用以上代码实现分组循环:将内表GT_DATA按照HEADID等进行排序和分组 每一组都放到
使用Function进行内外部转换
"外部转内部-加前导零
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
INPUT = -HKONT
IMPORTING
OUTPUT = -HKONT.
"内部转外部-去前导零
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
EXPORTING
INPUT = -HKONT
IMPORTING
OUTPUT = -HKONT.
SAP S4 新语法
"内部转外部-去前导零
X = |{ X ALPHA = OUT }|.
"外部转内部-加前导零
X = |{ X ALPHA = IN }|.
效果:
代码:
SELECTION-SCREEN: "设置标签
BEGIN OF TABBED BLOCK P_TAB_MAT FOR 12 LINES,
TAB (18) TEXT-001 USER-COMMAND BUT1 DEFAULT SCREEN 2100,
TAB (18) TEXT-002 USER-COMMAND BUT2 DEFAULT SCREEN 2200,
END OF BLOCK P_TAB_MAT.
SELECTION-SCREEN BEGIN OF SCREEN 2100 AS SUBSCREEN ."第一个标签页内容
SELECTION-SCREEN BEGIN OF BLOCK B4 WITH FRAME TITLE TEXT-003.
SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN PUSHBUTTON 5(15) BUT3 USER-COMMAND DOWN .
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK B4.
SELECTION-SCREEN BEGIN OF BLOCK B1 WITH FRAME TITLE TEXT-003.
PARAMETERS: P_PATH TYPE RLGRAP-FILENAME.
SELECTION-SCREEN END OF BLOCK B1.
SELECTION-SCREEN END OF SCREEN 2100.
SELECTION-SCREEN BEGIN OF SCREEN 2200 AS SUBSCREEN ."第二个标签页内容
SELECTION-SCREEN BEGIN OF BLOCK B2 WITH FRAME TITLE TEXT-003.
PARAMETERS: RE_DISP RADIOBUTTON GROUP GP1,
RD_EDIT RADIOBUTTON GROUP GP1.
SELECTION-SCREEN END OF BLOCK B2.
SELECTION-SCREEN BEGIN OF BLOCK B3 WITH FRAME TITLE TEXT-003.
SELECT-OPTIONS: S_MATNR FOR ZMMT0001-MATNR.
SELECT-OPTIONS: S_LIFNR FOR ZMMT0001-LIFNR.
SELECT-OPTIONS: S_EKORG FOR ZMMT0001-EKORG.
SELECT-OPTIONS: S_WERKS FOR ZMMT0001-WERKS.
SELECT-OPTIONS: S_MJAHR FOR ZMMT0001-MJAHR NO-EXTENSION NO INTERVALS.
SELECT-OPTIONS: S_MONAT FOR ZMMT0001-MONAT.
SELECTION-SCREEN END OF BLOCK B3.
SELECTION-SCREEN END OF SCREEN 2200.
通过调用函数RS_VARIANT_CONTENTS
获取已保存的指定变式
变式准备:
实现代码例子:
TABLES:MAKT.
SELECTION-SCREEN BEGIN OF BLOCK BLK01 WITH FRAME.
PARAMETERS:P_DATE TYPE SY-DATUM.
SELECT-OPTIONS:S_MATNR FOR MAKT-MATNR.
SELECTION-SCREEN END OF BLOCK BLK01.
INITIALIZATION.
DATA:LT_RSPARAMS TYPE TABLE OF RSPARAMS .
"获取变式VALUE
CALL FUNCTION 'RS_VARIANT_CONTENTS'
EXPORTING
REPORT = SY-REPID "程序名
VARIANT = 'Z1' "变式名称
TABLES
VALUTAB = LT_RSPARAMS
EXCEPTIONS
VARIANT_NON_EXISTENT = 1
VARIANT_OBSOLETE = 2
OTHERS = 3.
BREAK-POINT.
获取结果:
主要调用方法/UI2/CL_JSON=>DESERIALIZE
实现效果如下:
数据准备:
[
{
"name":"张国立",
"age":12,
"hobby":[
"1",
"2"
]
},
{
"name":"张铁林",
"sex":"男",
"email":"[email protected]",
"url":"./img/2.jpg"
},
{
"name":"邓婕",
"age":12,
"hobby":[
"1",
"2"
]
},
{
"name":"张国立",
"age":12,
"hobby":[
"1",
"2"
]
},
{
"name":"张铁林",
"age":12,
"hobby":[
"1",
"2"
]
},
{
"name":"邓婕",
"age":12,
"hobby":[
"1",
"2"
]
}
]
实现代码:
SELECTION-SCREEN BEGIN OF BLOCK BLK01 WITH FRAME.
PARAMETERS: P_PATH TYPE STRING.
SELECTION-SCREEN END OF BLOCK BLK01.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR P_PATH.
DATA:LT_FTABLE TYPE FILETABLE,
LV_RC TYPE I.
CALL METHOD CL_GUI_FRONTEND_SERVICES=>FILE_OPEN_DIALOG
EXPORTING
WINDOW_TITLE = '选择文件'
CHANGING
FILE_TABLE = LT_FTABLE
RC = LV_RC
EXCEPTIONS
FILE_OPEN_DIALOG_FAILED = 1
CNTL_ERROR = 2
ERROR_NO_GUI = 3
NOT_SUPPORTED_BY_GUI = 4
OTHERS = 5.
IF SY-SUBRC = 0 AND LT_FTABLE IS NOT INITIAL.
READ TABLE LT_FTABLE INTO DATA(LS_FTABLE) INDEX 1.
P_PATH = LS_FTABLE-FILENAME.
ENDIF.
START-OF-SELECTION.
DATA : LT_TABLE TYPE STRING_TABLE. "对应DATA_TAB是没指定类型的 所以就使用STRING_TABLE
DATA:LV_JSON TYPE STRING.
"定义一个JSON对应的结构
TYPES:BEGIN OF TY_DATA,
NAME TYPE STRING,
AGE TYPE I,
HOBBY TYPE STRING_TABLE.
TYPES END OF TY_DATA.
DATA:LT_DATA TYPE TABLE OF TY_DATA.
* DATA:LS_DATA TYPE TY_DATA. “如果是单条数据 就用工作区来接受数据
IF P_PATH IS INITIAL.
MESSAGE 'ERROR PATH' TYPE 'E'.
ENDIF.
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
FILENAME = P_PATH
TABLES
DATA_TAB = LT_TABLE
EXCEPTIONS
FILE_OPEN_ERROR = 1
FILE_READ_ERROR = 2
NO_BATCH = 3
GUI_REFUSE_FILETRANSFER = 4
INVALID_TYPE = 5
NO_AUTHORITY = 6
UNKNOWN_ERROR = 7
BAD_DATA_FORMAT = 8
HEADER_NOT_ALLOWED = 9
SEPARATOR_NOT_ALLOWED = 10
HEADER_TOO_LONG = 11
UNKNOWN_DP_ERROR = 12
ACCESS_DENIED = 13
DP_OUT_OF_MEMORY = 14
DISK_FULL = 15
DP_TIMEOUT = 16
OTHERS = 17.
IF SY-SUBRC <> 0.
MESSAGE 'ERROR READ' TYPE 'E'.
ENDIF.
IF LT_TABLE IS NOT INITIAL.
LOOP AT LT_TABLE INTO DATA(LS_TABLE).
LV_JSON = LV_JSON && LS_TABLE.
CLEAR LS_TABLE.
ENDLOOP.
ENDIF.
"调用方法转换数据
CALL METHOD /UI2/CL_JSON=>DESERIALIZE
EXPORTING
JSON = LV_JSON
CHANGING
DATA = LT_DATA.
* DATA = LS_DATA.
BREAK-POINT.
在接口中有时候会遇到输出JSON数据,此时我们就要将目标内表数据转为JSON,在ABAP中有一个标准的方法可以将内表数据转换为JSON字符串:/UI2/CL_JSON=>SERIALIZE
"内表转Json
DATA:LV_JSON2 TYPE STRING."接收JSON数据字符串
**********************
*这里是根据源代码创建的名称映射表
*java等其他编程语言都是大小写敏感的,所以需要变为对应的名称
TYPES:
BEGIN OF NAME_MAPPING,
ABAP TYPE ABAP_COMPNAME,
JSON TYPE STRING,
END OF NAME_MAPPING .
DATA:
NAME_MAPPINGS TYPE HASHED TABLE OF NAME_MAPPING WITH UNIQUE KEY ABAP . "ABAP和JSON名称映射表
NAME_MAPPINGS = VALUE #(
( ABAP = 'NAME' JSON = 'name' )
( ABAP = 'AGE' JSON = 'age' )
( ABAP = 'HOBBY' JSON = 'hobby' )
)."设置映射值
***********************
CALL METHOD /UI2/CL_JSON=>SERIALIZE
EXPORTING
DATA = LT_DATA
NAME_MAPPINGS = NAME_MAPPINGS
RECEIVING
R_JSON = LV_JSON2.
LT_DATA数据如下:
实现效果如下:
相关事务代码:SM36
SM37
首先创建一个报表程序,功能就是每隔2秒就插入一条数据到数据库
DATA: LV_COUNT TYPE I VALUE 1,
LS_JOB TYPE ZTJOB.
WHILE 1 = 1 .
LS_JOB-COUNT_VALUE = LV_COUNT.
ADD 1 TO LV_COUNT.
GET TIME STAMP FIELD LS_JOB-WORK_STAMP.
INSERT ZTJOB FROM LS_JOB.
WAIT UP TO 2 SECONDS.
ENDWHILE.
定义作业
在SM46
中,首先随便取一个作业名称 然后点击开始条件
我们这里选择立刻
并保存
在进行完以上第五个步骤之后点击下方的保存即可
并会出现这样的提示表示后台作业已定义好
作业执行
进入SM37
中,选择作业状态为活动
并执行
就可以看到正在执行的作业,如果想要结束执行,就选中对应的作业名并点击STOP
按钮即可
FUNCTION Z_CURSOR_TEST_01.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" REFERENCE(IV_COUNT) TYPE I
*" TABLES
*" ET_TABLE STRUCTURE BSEG
*"----------------------------------------------------------------------
DATA:LV_PACKAGE_SIZE TYPE I VALUE 50. "定义单块数据大小
DATA:LV_CURSOR TYPE CURSOR.
DATA:LT_DATA TYPE TABLE OF BSEG.
OPEN CURSOR LV_CURSOR FOR SELECT * FROM BSEG
" WHERE ...
.
WHILE ( LINES( ET_TABLE ) < IV_COUNT ).
FETCH NEXT CURSOR LV_CURSOR
INTO TABLE LT_DATA
PACKAGE SIZE LV_PACKAGE_SIZE. "指定CURSOR大小
IF SY-SUBRC EQ 0.
APPEND LINES OF LT_DATA TO ET_TABLE.
ENDIF.
ENDWHILE.
ENDFUNCTION.
运行结果: