SAP ABAP 常用语法 关键字详解 (超级全面)

文章目录


前言

      这篇文章会持续更新,先 点赞 关注 收藏 制作不易 谢谢🤞
      这篇文章会持续更新,先 点赞 关注 收藏 制作不易 谢谢🤞
      这篇文章会持续更新,先 点赞 关注 收藏 制作不易 谢谢🤞

      好多地方格式排版还未更新 多多见谅

      这篇文章给大家介绍一下ABAP中常用的语法 以及一些关键字的详细用法和解释。由于笔者也是初学ABAP不久对语法的使用和规范都不是很熟练所以记录下来方便自己和初学者的查阅。我会记录日常开发中常用的语法和关键字,大家有想查阅的内容可以先看目录然后点击跳转到对应的位置即可。目录只会对介绍的内容进行大致分类区分,具体有没有还需要跳转到对应位置去看。大家觉得文章实用的话还麻烦点点赞收藏一下 谢谢。这篇文章会持续长久更新。
      ABAP这门语言对于我们从其他语言转行或者新人来说我个人认为还是比较难的因为它不同于我们其他语言,你像C#和JAVA的语法非常相似甚至有些关键字都一样还有现在比较火的go语言,C和C++也是比较相似的,还有Python这门语言它的语法是非常简单简洁的,以上这些语言我认为语法以及关键字以及对数据的操作都是非常相似互通的,但是ABAP这门语言由于最初是借鉴了COBOL语言的而这门语言又比较古老导致现在的ABAP还留有它的身影,语法关键字对数据的操作和我们现在常见的语言还是又很大差别的。

什么是ABAP?

           ABAP可以说是和SAP紧密结合,甚至可以说SAP = ABAP,我们SAP系统就是由ABAP开发的,没有ABAP也就没有我们现在强大的SAP系统,ABAP有四种常见的用处,第一个就是可以开发报表,ABAP本来也是德语AllgemeinerBerichtsaufbereitungsprozessor的缩写,意思是“通用报表预处理器”。可以看出来我们ABAP开发报表的历史也是很久远了,从刚开始的画竖线横线制作报表,到FUN ALV 再到现在比较高级的OO ALV,还有就是可以做增强,就是对我们的SAP系统标准程序来做卡控以及功能的延展,还可以运用在smartforms智能表单中来通过取数调用函数传参实现打印程序,还有就是几种常见的接口开发,例如RFC、WebService 等等。


一、数据 声明创建

          这里介绍一些概念性的东西 eg: Like Type 声明数据的区别 创建 类型、变量、常量、结构、内表

DATA()内联声明

            a.声明数据的关键字

                       1.TYPE 与 LIKE 的区别
                            a.简单点来说,TYPE参照的必须是一个类型,LIKE参照的必须是一个对象。

                            b. TYPE 是用来引用一个标准的ABAP类型(如i,c,d,p,n等)或者数据字典中的数据元素、域、结构、表类型等。TYPE 声明的变量是原始类型的一个复制品,如果原始类型是在数据字典中定义的,它的语义属性会被保留。TYPE 后面一般用三种类型:1、dataelement = 数据元素 (一个的) 2、structure = 结构(一行的) 3、table type = 表类型(多行的)

                            c. LIKE 是用来引用一个已经在程序中声明的变量或常量,或者一个全局类的公共属性。LIKE 声明的变量是原始对象的一个别名,它继承了原始对象的所有属性,包括数据类型和值。这里的值指的是 LIKE 声明时指定的值,而不是原始对象的当前值。简单点说就是只会继承数据类型不会继承值。

DATA: v1 TYPE i  VALUE 10, "参考ABAP预定义i类型声明一个v1的变量
      v2 LIKE v1 VALUE 20. "参考变量v1声明一个v2的变量,这里如果不指定value 20 默认值为0

WRITE: / v1, v2. "输出 10 20

v1 = 40.
WRITE: / v1, v2. "输出 40 20

v2 = 50.
WRITE: / v1, v2. "输出 40 50

                       2.CREATE DATADATA 创建数据的区别
                            a.从概念上来说CREATE DATA 允许程序在运行时动态地创建数据对象,而 DATA 则需要在编译时明确指定数据对象的类型。如果你需要根据运行时条件来创建数据对象,可以选择使用 CREATE DATA。
                                 简单通俗点说,你可以把ABAP中的所有数据类型都想象为一个形状,比如字符串 是长方体,int类型 是正方体,内表 是圆柱体,等等。。。。当你在 ABAP 中使用 CREATE DATA 时,就像是你在运行程序的时候,创建了通用万能的数据盒子。这个盒子可以装不同类型的物体,比如字符串(长方体)、int(正方体)、内表(圆柱体),当你要装进去的时候也就数据存入内存的时候程序会给你把这个数据盒子捏造成和要装入类型一样的造型,比如捏成长方体,就存入的是字符串。。。。而当你使用 DATA 时,就像是你提前准备好了一个捏造好样子的数据盒子,里面只能放特定类型的东西,比如只能放数字或者只能放文本。。。。所以,CREATE DATA 更灵活,而 DATA 更固定。

                            b. DATA 很常用 其实它 跟 CREATE DATA 所能创建的数据对象类型 应该都一样。下面的例子我也只介绍 CREATE DATA。再介绍一个真实案例。

                            c. CREATE DATA 语句后面跟着 TYPE 关键字,用于指定数据对象的类型。你可以创建不同类型的数据对象,例如内表、结构、基本数据类型 等。

                            d. CREATE DATA示例 下面这个示例就是根据lv_data_type 不同值来创造不同的结构,大家测试的时候只需要关闭打开 lv_data_type 不同的注释即可。要使用 CREATE DATA 还是要提前声明创建一个数据对象的,这个对象参考的是ABAP中的data,REF TO data 声明的变量是一个引用型变量,可以指向任何数据类型。下面的章节也会介绍到 TYPE ANYTYPE REF TO data 创建数据对象的区别。

  TYPES: BEGIN OF ty_1,"声明一个结构类型 1
    col11 TYPE char10,
  END OF ty_1.
  TYPES: BEGIN OF ty_2,"声明一个结构类型 2
    col21 TYPE char10,
    col22 TYPE char10,
  END OF ty_2.
  TYPES: BEGIN OF ty_3,"声明一个结构类型 3
    col31 TYPE char10,
    col32 TYPE char10,
    col33 TYPE char10,
  END OF ty_3.
  
  DATA lv_data_type TYPE char1 VALUE '1'.
* DATA lv_data_type TYPE char1 VALUE '2'.
* DATA lv_data_type TYPE char1 VALUE '3'.

  DATA ls_data TYPE REF TO data.
  CASE lv_data_type.
  WHEN '1'.
    CREATE DATA ls_data TYPE ty_1.
  WHEN '2'.
    CREATE DATA ls_data TYPE ty_2.
  WHEN '3'.
    CREATE DATA ls_data TYPE ty_3.
  ENDCASE.

在这里插入图片描述

                            e. CREATE DATA 真实案例 下面这个ALV调用的FORM 是根据 用户选择不同的单选按钮 来创建了不同的结构的内表,然后再赋值 传给ALV进行展示。

FORM frm_alv_display USING pt_data TYPE any.

  DATA gt_excel TYPE REF TO data.

  IF p_rad1 = 'X'.
    CREATE DATA gt_excel TYPE TABLE OF ty_file1data.
  ELSEIF p_rad2 = 'X'.
    CREATE DATA gt_excel TYPE TABLE OF ty_file2data.
  ELSE.
    CREATE DATA gt_excel TYPE TABLE OF ty_file3data.
  ENDIF.

  FIELD-SYMBOLS: <fs_data> TYPE table.

  ASSIGN gt_excel->* TO <fs_data>.
  
  ASSIGN pt_data TO <fs_data>.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
    EXPORTING
      i_callback_program       = sy-repid
      i_callback_pf_status_set = 'FRM_STATUS_SET'
      i_callback_user_command  = ' '
      is_layout_lvc            = gs_layout
      it_fieldcat_lvc          = gt_fildcat
      i_save                   = 'A'
      it_events                = gt_event
    TABLES
      t_outtab                 = <fs_data>.
  IF sy-subrc <> 0.
* Implement suitable error handling here
  ENDIF.
ENDFORM.                    " FRM_ALV_DISPLAY

                       2.TYPE ANY TYPE REF TO data 的区别
                            a.其实我自己最开始对这两有混淆,不知道大家有没有。在这里我还是按照自己最后的理解说明一下吧。

                            b.从专业术语来说TYPE REF TO data 是声明了一个指向任意类型数据对象的引用,而 TYPE ANY 是是声明了一个ABAP 中通用数据类型的数据对象,它不是一个引用类型,而是一个实际的数据对象。而且 TYPE ANY 声明的数据对象在编译时会分配内存空间 TYPE REF TO data 在声明时并没有为其分配内存空间。

                                 简单通俗点说TYPE ANY 就是不管啥数据都能存 都能放进去,它是没有类型的是用于存储不确定的数据类型 就好像跟其他语言里面的装箱拆箱一样吧。大家可以搜一下装箱拆箱。就是你想存什么就存什么 有时候在perform子程序传参的时候要用。因为你也不知道你传进来的数据是什么样的就好像上面哪个ALV的案例一样, TYPE REF TO data 其实上面也说了,它就是在程序运行时才能 确定我要存进来的数据是什么类型。是动态声明数据对象的,其实TYPE REF TO data 最终要 CREATE DATA 的这一步 是和 TYPE ANY 意义是一样的,都是声明一个数据对象。只不过一个是存确定的数据类型 一个是存任意的数据类型。所以 TYPE ANY 和 TYPE REF TO data 的区别是 TYPE REF TO data 最终是一个确定的数据对象类型,用来存确定的数据。而TYPE ANY也是存数据的,但是你可以存任何数据类型不管是内表还是字符串还是结构都可以存。都可以先放进去 后面想用的话再经过拆箱拿出来用。

                            c.虽然 TYPE REF TO data 和 TYPE ANY 在功能上有所不同,但在某些情况下可以结合使用。例如,在某些情况下,你可能需要一个引用来指向任何类型的数据对象,并且还需要一个实际的数据对象来存储任意类型的值。在这种情况下,你可以使用 TYPE REF TO data 来声明一个引用,并根据需要将其关联到 TYPE ANY 声明的数据对象上。上面哪个ALV就是一个案例。

            a.变量 常量 通用泛型

                       1.变量 与 常量 的区别
                            a. CONSTANTS 声明出来的数据是常量,DATA声明出来的数据是变量。

                            b. CONSTANTS 常量的数值一旦确定是不能修改的而且必须是最初定义的时候就用 VALUE 关键字赋值好了,DATA 变量的数值一旦确定在程序运行过程中是可以反复修改的而且最初可以用 VALUE 关键字赋值也可以在程序运行过程中赋值。

                            c. CONSTANTS 常量一定是全局变量,DATA 变量可以声明为全局变量也可以声明为局部变量。

  CONSTANTS: lc_constant TYPE I VALUE 10. " 定义常量

  DATA: gv_variable TYPE I. " 定义变量
  gv_variable = 20. " 给变量赋值

                       3.步骤一 a 3
                            pass

            b.内表 结构

                       1.参考 结构类型 或者 结构
                            声明内表常见的有参考 结构类型 或者参照 结构 ,这里很明显结构类型是一个类型,而结构是一个已存在的数据对象。所以这里的语法就要有所不同。参考结构类型使用 TYPE TABLE OF 参考结构体就是用LIKE TABLE OF,什么时候用TYPE 什么时候用LIKE上面也介绍过了。但其实这里 TYPE TABLE OF可以参考结构类型也可以参考一个结构。是因为 TYPE 可以引用一个数据对象作为数据类型,这种情况下,TYPE 的作用和 LIKE 一样,都是复制数据对象的类型

	TYPES: BEGIN OF t_struct,"声明一个结构类型
	         col1 TYPE i,
	         col2 TYPE i,
	       END OF t_struct.
	
	DATA: itab1 TYPE TABLE OF t_struct."参照结构类型声明一个内表
	
	DATA: struc TYPE t_struct.      "参照结构类型声明一个结构
	DATA: itab2 LIKE TABLE OF struc."用LIKE参照结构类声明一个内表(注意上方黄色标注)
	DATA: itab3 TYPE TABLE OF struc."用TYPE参照结构类声明一个内表(注意上方黄色标注)
	
	DATA: itab4 LIKE TABLE OF t_struct."这行会报错因为t_struct是一个类型,LIKE必须参照对象
	
	DATA itab5 TYPE resb."参照数据库透明表可以不用写TABLE OF 因为参照的类型本身就是表 

                       2.步骤一 b 2
                            pass

                       3.步骤一 b 3
                            pass

            b.deep类型

                       1.结构包含结构
                            pass

                       2.结构包含内表
                            创建的数据对象是一个结构包着一个内表 当结构中的字段需要是个内表的话参考的表类型要使用后缀WITH DEFAULT KEY,意思是默认键包括所有字符类型(C, N, D, T)和字节类型(X)字段。也就是说,当你定义一个内表并使用 WITH DEFAULT KEY 时,系统会自动将内表中所有字符类型和字节类型字段作为键字段。 如果你不想使用默认键,可以定义一个显式键。例如:WITH UNIQUE KEY data1 data2.

  TYPES:
    BEGIN OF ty_tabledata, "这是内表参考的结构类型
      data1 TYPE  char10,
      data2 TYPE  char10,
    END OF ty_tabledata  .
    
  "gt_tabledata 是根据上面的结构类型创建一个内表
  DATA gt_tabledata TYPE TABLE OF ty_tabledata. 
  
  "tt_tabledata 是根据上面的结构类型创建一个表类型
  "如果字段要参考表类型需要加后缀 WITH DEFAULT KEY 不然会报错说是通用类型
  TYPES tt_tabledata TYPE STANDARD TABLE OF ty_tabledata WITH DEFAULT KEY. 
  
  TYPES:
    BEGIN OF ty_result          ,
      proc_num TYPE int4        ,
      status   TYPE char1       ,
      data     LIKE gt_tabledata,"也可以写 TYPE tt_tabledata 
    END OF ty_result.

  DATA  gt_result TYPE ty_result. "这是最终的数据效果 是一个结构包含着一个内表

  gt_result-proc_num = '88'.
  gt_result-status   = 'E' .

  DATA  gs_data TYPE ty_tabledata."先给gs_data赋值 再用gs_data APPEND 到 gt_result-data中去

  gs_data-data1 = '我是data1'.
  gs_data-data2 = '我是data2'.
  APPEND gs_data TO gt_result-data.

  gs_data-data1 = '我是data2-1'.
  gs_data-data2 = '我是data2-2'.
  APPEND gs_data TO gt_result-data.

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( gt_result-proc_num ).
  out->write_data( gt_result-status ).
  out->write_data( gt_result-data )->display( ).
  
  "如果转为json
  json = '{"PROC_NUM":"88","STATUS":"E","DATA":[{"DATA1":"我是data1","DATA2":"我是data2"},{"DATA1":"我是data2-1","DATA2":"我是data2-2"}]}'.

                       3.结构包含结构和内表
                            pass

二、操作 结构 内表

          这里主要介绍内表如何操作,结构的操作不多解释因为比较简单,而且操作内表的时候离不开结构所以将演示的例子放在一起,介绍内表的操作我们按照 增 删 改 查 的顺序介绍。

            a.添加数据

                       给内表添加数据的关键字是APPEND 下面介绍多种使用APPEND添加数据的方式。
                       1. 使用结构
                            给结构添加数据的时候要注意是否要做清空结构的这个操作,有时候第二次添加的时候某个字段是要为空的,但是这个字段还保持着上次的值,所以要清空掉。但是如果确保这个字段会被重新赋值值覆盖的话就可以不用清空。

  DATA  LT_HTTPNVP TYPE TIHTTPNVP.         "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUEDATA  LS_HTTPNVP TYPE LINE OF TIHTTPNVP. "参考内表声明一个结构 作为此内表的表头使用

  LS_HTTPNVP-NAME  =  'COLLAGEN-TIMEOUT'."结构中的NAME字段赋值
  LS_HTTPNVP-VALUE =  '3000'            ."结构中的VALUE字段赋值

  APPEND LS_HTTPNVP TO  LT_HTTPNVP      ."依据当前结构给内表添加一行

* 根据需求看是否要清空结构再重新赋值 我这里就不用清空 因为我两个字段都会重新赋值 覆盖之前的值
  LS_HTTPNVP-NAME  =  'CONTENT-TYPE'                  ."结构中的NAME字段赋值
  LS_HTTPNVP-VALUE =  'APPLICATION/JSON;CHARSET=UTF-8'."结构中的VALUE字段赋值

  APPEND LS_HTTPNVP TO  LT_HTTPNVP      ."依据当前结构给内表添加一行

                       2. 使用 带有表头行的内表
                            带有表头行的内表是比较方便的,相当于一口气也声明了一个结构吧,只不过这个结构 和 内表 是相同的名字。给内表添加数据的时候只需要APPEND <内表名>。详情 请看下面案例。清理结构 表头行 内表 的操作 在步骤b会详细介绍。

  DATA  LT_HTTPNVP TYPE TIHTTPNVP WITH HEADER LINE. "这是一个带有表头行的内表
  
  LT_HTTPNVP-NAME  =  'COLLAGEN-TIMEOUT'."结构中的NAME字段赋值
  LT_HTTPNVP-VALUE =  '3000'            ."结构中的VALUE字段赋值

  APPEND LT_HTTPNVP                     ."依据当前结构给内表添加一行

* 根据需求看是否要清空表头行再重新赋值 我这里就不用清空 因为我两个字段都会重新赋值 覆盖之前的值
  CLEAR LT_HTTPNVP."这里我清空一下表头行 因为我想让第二次添加的数据VALUE字段值为空
  LT_HTTPNVP-NAME  =  'CONTENT-TYPE'                  ."结构中的NAME字段赋值

  APPEND LT_HTTPNVP                     ."依据当前结构给内表添加一行

                       3. 使用 行内表达式
                            这种方式不需要内表有表头行,在运行的过程ABAP会为你处理表头行的创建。括号里面直接写对应的字段和值就行,可以一行一行添加 也可以一口气添加多行。 多行添加的时候不能给带有表头行的内表添加不然会报错: 需要 ")",而非 "("

  DATA LT_HTTPNVP TYPE TIHTTPNVP. "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUE*单行赋值
  APPEND VALUE #( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000' )                           TO LT_HTTPNVP."请求头赋值
  APPEND VALUE #( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON;CHARSET=UTF-8' ) TO LT_HTTPNVP."请求头赋值
  
*多行赋值
  LT_HTTPNVP = VALUE #( ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON;CHARSET=UTF-8' ) )."请求头赋值

                       3. 使用INSERT
                            INSERT 和 APPEND 的区别是 INSERT 可以通过指定索引位置来向内表的任意位置添加行。如果指定的索引位置已经被占用,则后续的行会被移动以腾出空间。APPEND 是会将新的行添加到内表的末尾,无需指定索引位置。这样可以简化代码,并且在性能方面通常比 INSERT 更高效,因为不需要移动其他行来腾出空间。

  DATA  LT_HTTPNVP TYPE TIHTTPNVP.
  DATA  LS_HTTPNVP TYPE LINE OF TIHTTPNVP. "参考内表声明一个结构 作为此内表的表头使用

  LT_HTTPNVP = VALUE #( ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON;CHARSET=UTF-8' ) )."请求头赋值

* 此时内表已经有两行数据 第一行是COLLAGEN-TIMEOUT 第二行是CONTENT-TYPE 我现在想给这两行中间插入一行
* 用表头行或者再声明一个结构 插 都可以 我这里用结构 因为上面用行内表达式插入多行是不能给带有表头行的内表添加的数据的
  LS_HTTPNVP-NAME  =  'User-Agent'.
  LS_HTTPNVP-VALUE =  'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'.

  INSERT LS_HTTPNVP INTO LT_HTTPNVP INDEX 2. "在索引位置2处添加行

                       4. 使用 内表追加
                             APPEND LINES OF <内表名1> TO <内表名2> 语句在 ABAP 中用于将一个内表的所有行追加到另一个内表中 语句在 ABAP 中用于将一个内表的所有行追加到另一个内表中,这在处理批量数据操作时非常有用。

  DATA lt_httpnvp01 TYPE tihttpnvp.
  DATA lt_httpnvp02 TYPE tihttpnvp.

  DATA(out) = cl_demo_output=>new( )."用于展示数据的对象 (可以忽略)


*给 lt_httpnvp01 添加数据
  lt_httpnvp01 = VALUE #(
                        ( name = 'Feild01' value = '字段01的值')
                        ( name = 'Feild01' value = '字段02的值')
                        ( name = 'Feild03' value = '字段03的值')
                      ).

  out->write_data( value = lt_httpnvp01 name = 'LT_HTTPNVP01' )."给展示数据的对象添加此时 lt_httpnvp01 的数据

*给 lt_httpnvp02 添加数据
  lt_httpnvp02 = VALUE #(
                      ( name = 'Feild04' value = '字段04的值')
                      ( name = 'Feild05' value = '字段05的值')
                    ).

  out->write_data( value = lt_httpnvp02 name = 'LT_HTTPNVP02' )."给展示数据的对象添加此时 lt_httpnvp02 的数据

  APPEND LINES OF lt_httpnvp02 TO lt_httpnvp01. "将内表 lt_httpnvp02 的数据追加到 lt_httpnvp01中

  out->write_data( value = lt_httpnvp01 name = 'LT_HTTPNVP01' )->display( )."给展示数据的对象添加最终 lt_httpnvp01 的数据 并展示

在这里插入图片描述

                       3. 使用COLLECT
                            这个是合计数据的时候使用的添加数据关键字。在使用的过程中要注意一下几点1、唯一性检查:COLLECT 语句会自动检查添加的行在内表中的唯一性(要有最够的主键字段不然合计效果可能达不到预期)。如果添加的行在内表中已经存在,则会增加该行的计数字段(如果存在)。如果内表中不存在该行,则将该行添加到内表中。 2、数据结构一致性:添加的数据对象必须与目标内表的结构兼容 3、内表排序:如果内表是排序表,并且添加的行会改变排序顺序,则添加操作后可能需要重新排序内表。 4、性能考虑:对于大型内表或频繁执行的操作,COLLECT 可能会影响性能,因为它会在内部进行线性搜索以查找是否存在相同的行。在这种情况下,使用 APPEND 语句可能更有效率。

  DATA: BEGIN OF LS_STUDENT,"声明一个结构 两个字段 姓名 和 成绩
        NAME  TYPE STRING,"姓名作为键
        SCORE TYPE I,     "成绩是数值类型的 金额也是数值类型的
      END OF LS_STUDENT.

  DATA: LT_STUDENTS LIKE TABLE OF LS_STUDENT."参考结构声明一个内表

  LS_STUDENT-NAME = 'JOHN'.
  LS_STUDENT-SCORE = '30'.
  COLLECT LS_STUDENT INTO LT_STUDENTS."此时内表有一行

  LS_STUDENT-NAME = 'ALICE'.
  LS_STUDENT-SCORE = '20'.
  COLLECT LS_STUDENT INTO LT_STUDENTS."此时内表有两行

  LS_STUDENT-NAME = 'TOM'.
  LS_STUDENT-SCORE = '60'.
  COLLECT LS_STUDENT INTO LT_STUDENTS."此时内表有三行

  LS_STUDENT-NAME = 'JOHN'.
  LS_STUDENT-SCORE = '20'.
  COLLECT LS_STUDENT INTO LT_STUDENTS."这行就出现了合计的效果 因为键有相同的行JOHN 就给JOHN的那行成绩添加了20

  LOOP AT LT_STUDENTS INTO LS_STUDENT."执行了4COLLECT操作 内表最终有三行
    WRITE: / LS_STUDENT-NAME, LS_STUDENT-SCORE.
  ENDLOOP.

            b.删除 清空 数据

                       1.清空内表
                           a. REFRESH ITAB
                                 会删除内表的所有行,并释放 除了 初始内存需求外的所有内存空间。
                           b.CLEAR ITAB[ ]
                                 会删除内表的所有行,但不会释放内存空间。 通常 CLEAR 用于清空 变量 和 工作区,REFRESH 和 FREE 用于内表。笔者最喜欢使用这种方式。

 DATA  LT_HTTPNVP TYPE TIHTTPNVP WITH HEADER LINE. "这是一个带有表头行的内表
 CLEAR ITAB[ ]"清空内表
 CLEAR ITAB"清空表头行

                           c. FREE ITAB
                                 会删除内表的所有行,并释放所有占用的内存空间,包括初始内存需求 。 一般来说,FREE 应该只在不再需要内表或者不会立即重新填充内表的情况下使用,以便节省内存 。

                       2.删除行
                           a. DELETE INDEX

  DATA: BEGIN OF LS_STUDENT,"声明一个结构 两个字段 姓名 和 成绩
        NAME  TYPE STRING,"姓名
        SCORE TYPE I,     "成绩
      END OF LS_STUDENT.

  DATA: LT_STUDENTS LIKE TABLE OF LS_STUDENT."参考结构声明一个内表

  LS_STUDENT-NAME = 'JOHN'.
  LS_STUDENT-SCORE = '30'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'ALICE'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'TOM'.
  LS_STUDENT-SCORE = '60'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'GLYN'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.

  LOOP AT LT_STUDENTS INTO LS_STUDENT.
    WRITE: / LS_STUDENT-NAME, LS_STUDENT-SCORE.
    IF LS_STUDENT-NAME = 'GLYN'.
       DELETE LT_STUDENTS."根据索引删除 这里可以不用写索引 循环中系统会自动帮你加上 SY-TABIX
    ENDIF.
  ENDLOOP.

  DELETE LT_STUDENTS INDEX 1."根据索引删除

                           b. DELETE WHERE

  DATA: BEGIN OF LS_STUDENT,"声明一个结构 两个字段 姓名 和 成绩
        NAME  TYPE STRING,"姓名
        SCORE TYPE I,     "成绩
      END OF LS_STUDENT.

  DATA: LT_STUDENTS LIKE TABLE OF LS_STUDENT."参考结构声明一个内表

  LS_STUDENT-NAME = 'JOHN'.
  LS_STUDENT-SCORE = '30'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'ALICE'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'TOM'.
  LS_STUDENT-SCORE = '60'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'GLYN'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.

  DELETE LT_STUDENTS WHERE SCORE = '20'."删除所有成绩为20的行
*-----------------以下是一些扩展用法-----------------
*DELETE <内表名> WHERE <字段名> NOT IN <选择对象内表> .
*DELETE <内表名> WHERE <字段名> IN <选择对象内表> .
*<选择对象内表>例子: SELECT-OPTIONS s_werk_d FOR afpo-dwerk. "生产工厂

                           c. DELETE FROM 结构体

  DATA: BEGIN OF LS_STUDENT,"声明一个结构 两个字段 姓名 和 成绩
        NAME  TYPE STRING,"姓名
        SCORE TYPE I,     "成绩
      END OF LS_STUDENT.

  DATA: LT_STUDENTS LIKE TABLE OF LS_STUDENT."参考结构声明一个内表

  LS_STUDENT-NAME = 'JOHN'.
  LS_STUDENT-SCORE = '30'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'ALICE'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'TOM'.
  LS_STUDENT-SCORE = '60'.
  APPEND LS_STUDENT TO LT_STUDENTS.
  LS_STUDENT-NAME = 'GLYN'.
  LS_STUDENT-SCORE = '20'.
  APPEND LS_STUDENT TO LT_STUDENTS.

  DELETE TABLE LT_STUDENTS FROM LS_STUDENT."根据结构删 删掉了name为GLYN成绩为20的那行

                       3.步骤二 a 3
                            pass

            c.删除 重复相邻行

                       请先看完以下内容就明白删除重复相邻行如何根据删除需求去对内表如何排序了。 ABAP SORT 默认是 升序也就是 从小到大,如果要降序从大到小使用 DESCENDING,例如我们需要对内表中的所有行按日期时间从大到小可以如下操作,这样最新的数据就会在内表最上面了。

SORT <内表名> BY <日期字段> DESCENDING <时间字段> DESCENDING.

                       1.所有字段都相同就删除
                           看下面这个案例,右边是原来的内表,左边是执行删除之后的内表。红色框出来的那行会被删除,因为两个字段值都跟上面那行一样。
                           COPY CODE:👉DELETE ADJACENT DUPLICATES FROM itab COMPARING ALL FIELDS.
在这里插入图片描述
                       2.指定字段相同就删除
                           看下面这个案例,右边是原来的内表,左边是执行删除之后的内表。红色框出来的行会被删除,因为 COL1 这个字段值都跟上面那行一样。
                           COPY CODE:👉DELETE ADJACENT DUPLICATES FROM itab COMPARING col1.
在这里插入图片描述

                       3.有相同字段就删除
                           看下面这个案例,右边是原来的内表,左边是执行删除之后的内表。红色框出来的行会被删除,因为 它们每次跟上一行比的时候其中有相同的字段值,理解起来需要注意的是它先是比较 比完先删掉这以为这下面这个例子再删第三行的时候第二行其实已经不存在了所以第三行是去和第一行比较了。第四行也是同样的 也是去和第一行比较了,下图中我也有文字描述。
                           COPY CODE:👉DELETE ADJACENT DUPLICATES FROM itab.
在这里插入图片描述

            d.修改数据

                       1.MODIFY
                           a. 根据字段结构修改

  DATA LT_HTTPNVP TYPE TIHTTPNVP. "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUEDATA LS_HTTPNVP TYPE IHTTPNVP . "工作区
  
*多行赋值
  LT_HTTPNVP = VALUE #(
                        ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON' )
                        ( NAME = 'User-agen'        VALUE = 'edge' )
                      )."请求头赋值

  LS_HTTPNVP-NAME  = 'User-agen'.
  LS_HTTPNVP-VALUE = '火狐'.

  "一旦有内表被读取 sy-tabix 就会被更改为读取的索引行
  READ TABLE LT_HTTPNVP TRANSPORTING NO FIELDS WITH KEY NAME = 'User-agen'.
  "根据 索引 结构 修改内表行
  MODIFY LT_HTTPNVP FROM LS_HTTPNVP INDEX sy-tabix.

                           b. 根据索引

  "修改内表第一行
  MODIFY LT_HTTPNVP FROM LS_HTTPNVP INDEX 1.

                           c. 根据循环条件判断

  DATA LT_HTTPNVP TYPE TIHTTPNVP. "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUEDATA LS_HTTPNVP TYPE IHTTPNVP . "工作区

*多行赋值
  LT_HTTPNVP = VALUE #(
                        ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON' )
                        ( NAME = 'User-agen'        VALUE = 'edge' )
                      )."请求头赋值

  LOOP AT LT_HTTPNVP INTO LS_HTTPNVP.

    IF LS_HTTPNVP-NAME =  'User-agen'.
    
      LS_HTTPNVP-VALUE = '火狐'.
      "写不写index sy-tabix 都无所谓 不写系统会自动帮你做这个事情
      MODIFY LT_HTTPNVP FROM LS_HTTPNVP INDEX sy-tabix.
      "不要把sy-tabix 和 sy-index 搞混淆了 sy-index 是loop循环次数
    ENDIF.

  ENDLOOP.

                           c. MODIFY 后缀
                                有时候我们只想修改指定字段,这就要用 TRANSPORTING 这个关键字了,详细使用方法看下面示例。

  TYPES:
  BEGIN OF ty_tabledata,
    data1 TYPE  char10,
    data2 TYPE  char10,
    data3 TYPE  char10,
    data4 TYPE  char10,
  END OF ty_tabledata  .
  
  DATA gt_data1 TYPE TABLE OF ty_tabledata."修改这个内表会用 TRANSPORTING关键字
  DATA gt_data2 TYPE TABLE OF ty_tabledata."用来做效果对比同样数据的内表

  DATA gs_data  TYPE ty_tabledata.
  
  gt_data1 = VALUE #(
                   ( data1 = '1'   data2 = '2'   data3 = '3'   data4 = '4'  )
                   ( data1 = '11'  data2 = '22'  data3 = '33'  data4 = '44' )
                   ( data1 = '111' data2 = '222' data3 = '333' data4 = '44' )
                    ).
  gt_data2 = gt_data1.

  gs_data-data1 = 'data1'.
  gs_data-data2 = 'data2'.
  gs_data-data3 = 'data3'.
  gs_data-data4 = 'data4'.

  "虽然gs_data其他几个字段也有不同的值 但是这个语句只会修改索引为2 字段为data2的数据
  MODIFY gt_data1 FROM gs_data INDEX 2 TRANSPORTING data2.
  MODIFY gt_data2 FROM gs_data INDEX 2.

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( gt_data1 ).
  out->write_data( gt_data2 )->display( ).

在这里插入图片描述

                       2.ASSIGN分配内存地址 修改内存的地址的值
                           a. 内联声明

  DATA LT_HTTPNVP TYPE TIHTTPNVP. "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUE*多行赋值
  LT_HTTPNVP = VALUE #(
                        ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON' )
                        ( NAME = 'User-agen'        VALUE = 'edge' )
                      ).
                      
  LOOP AT LT_HTTPNVP ASSIGNING FIELD-SYMBOL(<FS_HTTPNVP>)."内联声明的语法是FIELD-SYMBOL么有S 

    IF <FS_HTTPNVP>-NAME =  'User-agen'.

      <FS_HTTPNVP>-VALUE = '火狐'."相当于直接操作内存地址了

    ENDIF.

  ENDLOOP.

                           b. 逐步声明

  DATA LT_HTTPNVP TYPE TIHTTPNVP. "参考的TIHTTPNVP本身就是内表 是设置HTTP请求头的内表 如设置 超时时间 请求内容类型 User-Agent 这个内表只有两个字段分别是 NAMEVALUE
  FIELD-SYMBOLS <FS_HTTPNVP> TYPE IHTTPNVP.

*多行赋值
  LT_HTTPNVP = VALUE #(
                        ( NAME = 'COLLAGEN-TIMEOUT' VALUE = '3000')
                        ( NAME = 'CONTENT-TYPE'     VALUE = 'APPLICATION/JSON' )
                        ( NAME = 'User-agen'        VALUE = 'edge' )
                      ).

  LOOP AT LT_HTTPNVP ASSIGNING <FS_HTTPNVP>.

    IF <FS_HTTPNVP>-NAME =  'User-agen'.

      <FS_HTTPNVP>-VALUE = '火狐'.

    ENDIF.

  ENDLOOP.

                       3.步骤二 a 3
                            pass

            e.读取数据

                       数据准备

  DATA lt_httpnvp TYPE tihttpnvp. 
  DATA ls_httpnvp TYPE ihttpnvp .
*多行赋值
  lt_httpnvp = VALUE #(
                        ( name = 'name1' value = '1' )
                        ( name = 'name2' value = '2' )
                        ( name = 'name3' value = '3' )
                        ( name = 'name4' value = '4' )
                        ( name = 'name5' value = '5' )
                      ).

                       1.根据索引获取指定行数据
                            超出索引会报错,所以用新语法得先判断数据是否存在。也可以用TRY捕获错误。

  READ TABLE lt_httpnvp INTO ls_httpnvp INDEX 2."根据索引读取
  ls_httpnvp = lt_httpnvp[ 5 ]                 ."简洁的新语法

                       2.根据关键字获取指定行数据
                            新语法数据不存在会报错所以用新语法得先判断数据是否存在。也可以用TRY捕获错误。

  READ TABLE lt_httpnvp INTO ls_httpnvp WITH KEY name = 'name3'            ."根据单个关键字
  READ TABLE lt_httpnvp INTO ls_httpnvp WITH KEY value = '4'               ."根据单个关键字
  READ TABLE lt_httpnvp INTO ls_httpnvp WITH KEY name = 'name3' value = '3'."根据多个关键字
  ls_httpnvp = lt_httpnvp[ name = 'name5' value = '5' ]                    ."简洁的新语法

                       3.获取指定行索引
                            TRANSPORTING NO FIELDS 是不赋值的意思就不用些 into 到某个结构中了。

  READ TABLE lt_httpnvp WITH KEY name = 'name3' TRANSPORTING NO FIELDS."读取到之后 系统变量 SY-TABIX 就是数据所在索引
  DATA(lv_index) = line_index( lt_httpnvp[ name = 'name2' ] )."简洁的新语法

                       4.判断数据是否存在

  READ TABLE lt_httpnvp WITH KEY name = 'name3' TRANSPORTING NO FIELDS."读取到之后 系统变量 SY-TABIX 就是数据所在索引
  IF sy-subrc = 0 ."存在对应行
  ELSE."不存在对应行
  ENDIF.

  "简洁的新语法
  IF line_exists( lt_httpnvp[ name = 'name3' ] )."存在对应行  
  ELSE."不存在对应行
  ENDIF.

                       5.新语法最好这样写

  "第一种方式:使用 TRY 捕获错误
  TRY .
      ls_httpnvp = lt_httpnvp[ 6 ].
    CATCH cx_sy_itab_line_not_found .
      MESSAGE '未找到数据' TYPE 'E' .
  ENDTRY.


  "第二种方式:先判断是否存在
  IF line_exists( lt_httpnvp[ name = 'name3' ] )."存在对应行  "简洁的新语法
    ls_httpnvp = lt_httpnvp[ name = 'name3' ].
  ELSE."不存在对应行
    MESSAGE '未找到数据' TYPE 'E' .
  ENDIF.

在这里插入图片描述

            f.排序

                       1.步骤二 a 1
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

二、操作 透明表

          这里主要介绍如何操作数据库表,我们按照 增 删 改 查 的顺序介绍。

            a.添加数据

                       给透明表添加数据的方法有多种,它们之间的区别我们要注意区分。下面介绍多种给透明表添加数据的方式,操作完只会我们都可以用 SY-SUBRC 系统变量去判断是否操作成功。
                       1.使用 INSERT 添加数据
                            a.无任何后缀

*这是一次性 操作多条数据 是根据内表新增插入数据到透明表
  INSERT <透明表> FROM TABLE <参考透明表声明的内表>.

*这是 操作一条数据 是根据结构新增插入数据到透明表
  INSERT <透明表> FROM <参考透明表声明的结构>.

                            b.键值冲突扩展语法
                            ACCEPTING DUPLICATE KEYS:这部分指示系统在遇到重复键值(即主键或唯一键值与数据库中已有记录相同)时,不会抛出错误,而是简单地忽略这些重复的记录,继续插入其他不重复的记录。 这个选项对于确保批量插入操作不会因为个别重复键值而中断非常有用。例如,当你从一个数据源批量加载数据到数据库表中时,可能会有一些重复的记录,你不希望整个插入操作因为这些重复记录而失败。不会因为插入失败而影响 sy-subrc 的值。

*这是一次性 操作多条数据 是根据内表新增插入数据到透明表
  INSERT <透明表> FROM TABLE <参考透明表声明的内表> ACCEPTING DUPLICATE KEYS.

*这是 操作一条数据 是根据结构新增插入数据到透明表
  INSERT <透明表> FROM <参考透明表声明的结构> ACCEPTING DUPLICATE KEYS.

                       2.使用 MODIFY 添加数据
                            MODIFY 有一个特点 有则修改 无则添加。 也就是如果透明表中存在与指定条件匹配的数据行,则会修改非关键字段的值;如果不存在匹配的数据行,则会添加一条新的数据行。
                            这使得 MODIFY 语句非常方便,因为它可以根据条件执行修改或添加操作,而不需要使用额外的逻辑来判断是修改还是添加。

*这是一次性 操作多条数据 是根据内表增加或者修改透明表的数据
  MODIFY <透明表> FROM TABLE <参考透明表声明的内表>.

*这是 操作一条数据 是根据结构增加或者修改透明表的数据
  MODIFY <透明表> FROM <参考透明表声明的结构>.

            b.删除清空数据

                       1.使用 DELETE 添加数据
                            pass

*这是一次性 删除多条数据 是根据内表删除透明表的数据
  DELETE <透明表> FROM TABLE <参考透明表声明的内表>.

*这是 删除一条数据 是根据结构删除透明表的数据
  DELETE <透明表> FROM <参考透明表声明的结构>.

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

            c.修改数据

                       1.使用 UPDATE 修改数据

                           a. 代码示例
                                 下面这个示例是根据透明表 zsaptogep_log 的三个关键字reqid、gep_type、ebeln 去更新 zsaptogep_log 的部分字段。

UPDATE zsaptogep_log SET   rec_date   = ls_log-rec_date
                           rec_time   = ls_log-rec_time
                           rec_msg    = ls_log-rec_msg
                           rec_status = ls_log-rec_status
                     WHERE reqid      = ls_log-reqid    AND
                           gep_type   = ls_log-gep_type AND
                           ebeln      = ls_log-ebeln      .

                           b. UPDATE透明表特点
                                 UPDATE 可能比 MODIFY 更高效,因为 UPDATE 可以直接在数据库级别执行是通用的 SQL 语句, UPDATE 更加灵活,适用于复杂的数据更新需求,可以根据具体情况指定要更新的字段。而 MODIFY 就不能像修改内表哪有只修改部分字段了。

                       2.使用 MODIFY 修改数据

                           a. 代码示例
                                  MODIFY 在上面给透明表添加数据数据的时候已经介绍举例说明过了 ,详情请看上面透明表添加数据的部分。但是给大家一个可以做到和UPDATE 同样效果的代码示例只更新部分字段。下面这个示例就相当于只更新了ADDRESS 字段。

  DATA: ls_customer TYPE ZCUSTOMER.

  SELECT SINGLE * FROM ZCUSTOMER INTO ls_customer
    WHERE CUSTOMER_ID = '123'.

  IF sy-subrc = 0.
    ls_customer-ADDRESS = 'New Address'.
    MODIFY ZCUSTOMER FROM ls_customer.
  ENDIF.

                           b. MODIFY透明表特点
                                 MODIFY 通常需要将整个数据行传输到应用服务器,然后在应用服务器上执行更新操作,可能会增加网络开销和处理时间。 MODIFY 如果要做到只更新部分字段的话就只能像上面那样操作了,不然其他字段如果没赋值那么更新完透明表之后未赋值的那些字段就变为空了,它不能像修改内表一样使用TRANSPORTING 关键字来修改部分字段,如果有只更新部分字段的需求还是用UPDATE吧。

            d.读取数据

            e.回滚

                       回滚在操作数据库层面是一个很重要的点,回滚是指在数据库管理系统中取消已经执行的事务或操作,并将数据库恢复到之前的状态。这是确保数据库数据完整性和一致性的关键机制之一。如果一个操作导致了错误或者不符合预期,通过回滚可以将数据库恢复到操作之前的状态,避免数据损坏或不一致性。
                       1.回滚代码示例
                            下面的这个代码示例是一个 RFC 部分逻辑它是根据结构 ls_log 更新 SAP 中的透明表 zsaptogep_log 的逻辑。如果 MODIFY 成功 并且 status 等于 success 那么就提交,否则就执行回滚。

  MODIFY zsaptogep_log FROM ls_log."更新数据库表 如果只更新部分字段就用UPDATE
  IF sy-subrc = 0 AND status = 'success'.
    COMMIT WORK AND WAIT."提交
    ex_type = 'S'.
    ex_message = result-requestid && ' update success!'.
  ELSE.
    ROLLBACK WORK."回滚
    ex_type = 'E'.
    ex_message = result-requestid && ' update failed!'.
  ENDIF.

                       2.代码详解

                            COMMIT WORK: 这部分指示数据库将当前事务中的所有更改永久性地应用到数据库中。换句话说,它告诉数据库确认所有的更新操作,使它们对其他用户可见,并将它们持久化到数据库中。ABAP如果操作数据表没有写COMMIT WORK其实会自动将事务提交到数据库中。这种隐式提交通常发生在ABAP的数据库更新语句之后,例如MODIFY, INSERT, DELETE等。

                            AND WAIT: 这部分指示程序等待数据库确认提交操作的完成,直到数据库返回一个确认信号,表明事务已经成功提交或失败。这种等待确保在继续执行后续代码之前,程序能够知道提交操作的结果。这对于需要确保事务已经完成的情况非常重要。就是等数据库更新完之后再执行后续代码。

                            ROLLBACK WORK: 这部分指示数据库取消当前事务中的所有更改,将数据库恢复到事务开始时的状态。换句话说,它撤销了事务中的所有操作,就好像这些操作从未发生过一样。例如上面的代码示例 我们数据库表更新成功了旦 status 字段不等于 success 那么就会撤回刚才的更新操作。

三、OPEN SQL

          这里基础的 OPEN SQL不再介绍,只介绍一些实用的语法。其实不同系统版本 对于OPEN SQL 的一些语法支持是不同的。虽然代码没有爆红,但是激活的时候就提示不行。这个要根据自己ABAP版本看了,如果不持支 那么就只能在ABAP层面再操作数据了。

            a.聚合函数

                       1.
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

            a.CASE 操作

                       1.
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

            a. 去前导零 拼接截取 字符串 大小写 等等。。。。。。。

                        在 Open SQL 中,除了标准的 SQL 函数之外,还提供了一些额外的函数用于方便地处理数据。这些函数通常与标准的 SQL 函数一起使用,用于在查询中执行特定的操作或处理数据。以下是一些常见的 Open SQL 额外函数:ECC好像大多数都不持支这样用
                       1.去除前导零
                            ltrim( ) 可以用来去除字符串左侧的空格。这个函数我们和 OPEN SQL 结合起来就可以去除前导零 代码示例如下。

  "vbak-vbeln 这个字段一般在表中都是有前导零的
  DATA gv_vbeln1 TYPE vbak-vbeln.
  DATA gv_vbeln2 TYPE vbak-vbeln.

  SELECT SINGLE vbeln FROM vbak INTO gv_vbeln1. "open sql 取出vbak-vbeln
  SELECT SINGLE ltrim( vbeln, '0' ) AS vbeln FROM vbak INTO gv_vbeln2."open sql 取出vbak-vbeln 去除前导零

--------------------------ABAP 7.40 及更高版本中可以这样写--------------------------
  SELECT SINGLE vbeln FROM vbak INTO @data(gv_vbeln1). "open sql 取出vbak-vbeln
  SELECT SINGLE ltrim( vbeln, '0' ) AS vbeln FROM vbak INTO @data(gv_vbeln2)."open sql 取出vbak-vbeln 去除前导零
--------------------------ABAP 7.40 及更高版本中可以这样写--------------------------

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( gv_vbeln1 ).
  out->write_data( gv_vbeln2 ).
  out->display( ).

                       2.拼接字符串
                            这个拼接的函数好像只能接收两个参数,下面的示例是将 KNA1 客户主数据透明表中的 客户编号(kunnr) 与 客户名称(name1 ) 两个字段拼接在了一起。

  SELECT SINGLE concat( kunnr, name1 ) AS full_name
  FROM kna1
  INTO @DATA(lv_full_name).

--------------------------也可以直接写一个字符串--------------------------
  SELECT SINGLE concat( '这是客户名称:', name1 ) AS full_name
  FROM kna1
  INTO @DATA(lv_full_name).
--------------------------也可以直接写一个字符串--------------------------

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( lv_full_name ).
  out->display( ).

在这里插入图片描述

                       2.截取字符串
                            下面的示例是将 KNA1 客户主数据透明表中的 客户名称(name1 ) 取前两个字符,如果要取2到5的字符就改函数里面的参数即可。如果要取 2 到 末尾 就得 SE11 去看这个字段有多长了,如果是 CHAR35 那么 我们传2 ,34即可。

  SELECT SINGLE SUBSTRING( name1, 1, 2 )
  FROM kna1
  INTO @DATA(lv_name1).

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( lv_name1 ).
  out->display( ).

在这里插入图片描述

                       3.获取字符串长度
                            pass

  SELECT SINGLE LENGTH( name1 ) AS name1_len
  FROM kna1
  INTO @DATA(lv_name1_len).

  "数据展示
  DATA(out) = cl_demo_output=>new( ).
  out->write_data( lv_name1_len ).
  out->display( ).

在这里插入图片描述

三、操作 数据

          步骤二介绍

            a.字符串模板语法 大全

DATA lv_string  TYPE string.


" 使用 ALIGN 设置输入位置  '    12,345' -> '12345    '(不过好像是转为字符串了)
DATA lv_number  TYPE i VALUE 12345.
lv_string = |{ lv_number ALIGN = LEFT }|. WRITE: / lv_string.


" 使用 DECIMALS 设置小数位 1234.56->1234.560
DATA lv_amount  TYPE p DECIMALS 2 VALUE '1234.56'.
lv_string = |{ lv_amount DECIMALS = 3 }|. WRITE: / lv_string.


" 使用 DATE 格式化日期 20240101->2024-01-01
DATA lv_date    TYPE d VALUE '20240101'.
lv_string = |{ lv_date DATE = USER }|. WRITE: / lv_string.


" 使用 TIME 格式化时间 123456->12:34:56
DATA lv_time    TYPE t VALUE '123456'.
lv_string = |{ lv_time TIME = USER }|. WRITE: / lv_string.


" 使用 CURRENCY 币别转化 1234.56->123456 (会自动扩大100倍数因为日元没有 分 毛)
DATA lv_currency  TYPE p DECIMALS 2 VALUE '1234.56'.
lv_string = |{ lv_currency CURRENCY = 'JPY' }|. WRITE: / lv_string.


" 使用 ALPHA 转为内码 12345->000000000000012345 可以使用 WIDTH 关键字指定长度
DATA: lv_matnr TYPE matnr VALUE '12345'.
lv_string = |{ lv_matnr ALPHA = IN WIDTH = 18 }|.WRITE: / lv_string.


" 使用 ALPHA 转为外码 000000000000012345->12345 可以使用 WIDTH 关键字指定长度
DATA: lv_matnr1 TYPE matnr VALUE '000000000000012345'.
lv_string = |{ lv_matnr1 ALPHA = OUT WIDTH = 18 }|.WRITE: / lv_string.

            a.字符串 拼接 分割 截取 替换

                       1.拼接字符串
                            a. 插值语法 (比较实用)
                                   详情请看代码中的注释 注释很详细。

  DATA(MSG) = |{ LINES( LT_ROWS ) } records processed|.
* 运行结果 假设内表中有10行数据那么MSG的值就为:10 records processed

* LT_ROWS 是一个内表  records processed是死值字符串。
* LINES() 是一个函数  用来返回一个内表的行数。
* { }     是一个表达式分隔符,用来表示在字符串中插入一个表达式的值。
* ||      是一个字符串分隔符,用来表示字符串的开始和结束。
*------------------------------------------------------------------------------------------------------

* 下面是一些扩展用法

* 在字符串中插入其他变量的值
  DATA(MSG) = |The name is { name }|. "这样就可以把name变量的值放在字符串中。
* 运行结果 假设name变量值为小贱贱那么MSG的值就为:The name is 小贱贱
*------------------------------------------------------------------------------------------------------

* 在字符串中插入转义字符
  DATA(MSG) = |ThisIsANewline \n IAmNewLine|."这样就可以在字符串中换行。
* 运行结果 需要打断点在视图选择TXTX浏览器中的文本才能看到效果 
*------------------------------------------------------------------------------------------------------

* 在字符串中插入格式化字符
  DATA RES TYPE STRING."格式化之后的值
  DATA NUM TYPE P DECIMALS 3 VALUE '9.999'."要格式化的值
  TYPES: TY TYPE P DECIMALS 2."格式化的类型

  RES = | The name is { CONV TY( NUM ) } |."这样就可以将9.999格式化为两位小数点的值
  WRITE RES.
* 运行结果 RES最终等于The name is  10.00 因为四舍五入了
*------------------------------------------------------------------------------------------------------

* 在字符串中插入表达式的结果
  DATA(MSG) = |The sum is { x + y }|. "这样就可以在字符串中显示两个数的和。
* 运行结果 如果X2 y为5 那么MSG的值就为:7
*------------------------------------------------------------------------------------------------------

* 还可以用来增加去掉前导零
  DATA NUM  TYPE CHAR10 VALUE 1.
  NUM = |{ NUM ALPHA = IN }|. "0000000001 增加了前导零
  NUM = |{ NUM ALPHA = OUT }|."1          取消了前导零

                            b. 使用 && 或者 & 拼接 (比较直接简单)
                                   && 和 & 都可以用来连接字符串,但是它两还是有区别的,简单来说, && 允许你在字符串中插入 ABAP 表达式,而 & 则直接将两个字符串连接起来。再直接点就是 && 可以拼接变量 而 & 只能拼接只能手敲字符串 并且&拼接出来的结果长度不能大于 255 个字符。不然会报错 在 ABAP 中,单行字符串文本(例如 STRING 类型)的长度限制是 255 个字符。因此,在你的示例中,由于字符串 str 的长度超过了 255 个字符,导致出现了错误。具体看下面的示例代码。

  DATA STR1 TYPE STRING VALUE '我是'.
  DATA STR2 TYPE STRING VALUE '小贱贱'.

  DATA STR3 TYPE STRING .
  DATA STR4 TYPE STRING .

  STR3 = STR1 && STR2 && '死侍'."这样就没问题 && 是字符串模板运算符 也就是能插入表达式
* STR3 = STR1 & STR2 & '死侍'.  "这样会报错 因为 & 是字符串连接运算符。

  STR4 = '我是' & '钢铁侠'.     "如果拼接的最终结果字符大于255也会报错 用&&就不会报错

  WRITE:/ STR3. "结果:我是小贱贱死侍
  WRITE:/ STR4. "结果:我是钢铁侠

                            b. 使用 CONCATENATE 关键字
                                   CONCATENATE 拼接字符串也是很常用的,并且还可以将字符串使用指定连接符 连接起来。

  CONCATENATE str1 str2 INTO str "就是将str1和str2拼接成str
  CONCATENATE str1 str2 INTO str SEPARATED BY ' ' "就是在str1和str2之间加上一个空格。 也可以加其他字符

                       2.分割字符串
                            a. 存储到单个目标字段

DATA: lv_str TYPE string VALUE 'steel_rods'."要分割的字符串
DATA: lv_res1 TYPE string,"结果存储到的目标字段1
      lv_res2 TYPE string."结果存储到的目标字段2
      
SPLIT lv_str AT '_' INTO lv_res1 lv_res2."按照符号 _ 进行分割 存储到 lv_res1 lv_res2 中。
* 如果分隔符位于字符串的首或尾,那么拆分后的结果可能会包含一个空字符串。

WRITE: lv_res1,lv_res2."打印结果::steel rods

                            b. 存储到内表中

DATA:lv_string TYPE string.
DATA :BEGIN OF ls_string,"声明一个结构只有一个字段col1
        col1 TYPE char50,
      END OF ls_string.

DATA:lt_string LIKE STANDARD TABLE OF ls_string."参照上面的结构声明一个STANDARD(标准)内表
*不加STANDARD就声明的是通用表,通用表的类型可以是标准表,也可以是排序表或者哈希表,具体取决于赋值给它的数据对象的类型。
*也就是说 当一个排序表赋值给一个通用表的时候 这个通用表就会变为排序表就具有排序表的行为,如按照键值排序等。其它情况也如此。

lv_string = '1,2,3,4'."要分割的字符串
SPLIT lv_string AT ',' INTO TABLE lt_string."将字符串按照逗号分割存入内表中

LOOP AT lt_string INTO ls_string."循环打印内表中的结果
  WRITE:/ ls_string-col1.
ENDLOOP.

                       3.截取切片 字符串
                            a. 使用 SUBSTRING 函数

  DATA(RESULT1)  = SUBSTRING(        VAL = 'ABCDEFGH' OFF = 2 LEN = 2 )             ."从下标2开始往后截取2位 (OFF LEN 两个参数必须指定一个)
  DATA(RESULT2)  = SUBSTRING_FROM(   VAL = 'ABCDEFGH' SUB = 'CD'  )                 ."从CD字符串开始到结尾 (SUB必传,未指定LEN则一直到字符串末尾,搜索默认区分大小写使用CASE调整)
  DATA(RESULT21) = SUBSTRING_FROM(   VAL = 'ABCDEFGH' SUB = 'cd' CASE = ABAP_FALSE )."CASEABAP_FALSE 不区分大小写 默认为ABAP_TRUE
  DATA(RESULT3)  = SUBSTRING_AFTER(  VAL = 'ABCDEFGH' SUB = 'CD' )                  ."从CD字符串之后开始到结尾  (SUBSTRING_FROM相似 只不过偏移量会加上搜索字符串的长度)
  DATA(RESULT4)  = SUBSTRING_BEFORE( VAL = 'ABCDEFGH' SUB = 'CD' )                  ."从头开始到CD字符串之前 用法都与SUBSTRING_FROM相似
  DATA(RESULT5)  = SUBSTRING_TO(     VAL = 'ABCDEFGH' SUB = 'CD' )                  ."从头开始到CD字符串结束 用法都与SUBSTRING_FROM相似

  WRITE / RESULT1. " CD
  WRITE / RESULT2. " CDEFGH
  WRITE / RESULT21." CDEFGH
  WRITE / RESULT3. " EFGH
  WRITE / RESULT4. " AB
  WRITE / RESULT5. " ABCD
  
* substring_from( val = text{sub = substring}|{regex = regex}[case = case] [occ = occ] [len = len])
* 上面这行是这个函数的完整参数 上面的那些例子我只介绍了常用的参数 regex 正则表达式 和 occ 指定匹配的发生情况 大家F1自己去研究一下

                            b. 字符串操作符 +

  DATA: STR TYPE STRING VALUE 'Hello, World!'.

  DATA(RES1) = STR+0(5). " 从下标0开始提取长度为5的子字符串
  DATA(RES2) = STR+7(5). " 从下标7开始提取长度为5的子字符串 空格也算一个字符串

  "获取字符串长度 在切片用的时候要保证不超出索引 减2是因为我们想从下标2位置开始切 不然就超出索引报错了 反正就灵活使用就行
  DATA(LEN)  = STRLEN( STR ) - 2 .
  DATA(RES3) = STR+2(LEN). " 从下标2开始提到字符串末尾

  WRITE / RES1. " HELLO
  WRITE / RES2. " WORLD
  WRITE / RES3. " LLO, WORLD!

                            c. 使用正则表达式 FIND REGEX
                                   这种方法复杂和低效,只是告诉大家也可以这样切,不做演示。

                       4.替换字符串中指定字符
                            a. REPLACE
                                   这个还是很实用方便的,例如实际项目中我们可能遇到异常的JSON,可能接收 到数据的时候引号是Unicode编码了我们就可以用REPLACE 把字符替换回来,如下下图所示。

  DATA lv_string  TYPE string VALUE '11111122211111122211112111'.

  REPLACE ALL OCCURRENCES OF '222' IN lv_string WITH '1'."把字符串里面所有的222替换为1

  WRITE / lv_string."11111122211111122211112111->1111111111111111112111

在这里插入图片描述

            a.字符串 查找 等等

SEARCH THREE_DOG FOR I_COLOR. 查找字符串
                       1.查找
                            pass

            a.包含 存在 以**开头 等于 大小于 CO CA CP CS EQ NE LT GT LE GE

                      下面这四个比较运算符是 判断 包含 存在 模式匹配 的,常用的是CS。如果要判断一个字符串是否被另外一个字符串包含就用CS,CO看清楚了再慎用

包含 存在 比较运算符解释作用
CO(Contains Only):     CO 左边数值 所有字符 都存在于 右边数值中。
CA(Contains Any):      CA 左边数值 任意一个字符 存在于 右边数值中。
CP(Contains Pattern): CP 左边数值 匹配 右边数值的模式。
CS(Contains String):   CS 右边数值 被 左边数值 包含。

                       1.CO
                            CO 是判断 左边数值 所有字符 是否 都存在于 在 右边数值中。注意: 这里的 “所有字符” 是指 左边数值 中的每一个字符都必须出现在 右边数值中,且字符的顺序无关紧要。

                            a.情况1: 这里的 str1 是 CO 左边的数值, str2 是 CO 右边的数值。然后结合上面CO的注解以及代码中的注释即可理解。注意下面的字符是没有顺序的因为CO运算符在比较的时候字符的顺序无关紧要。

  DATA(str1) = 'bae'.
  DATA(str2) = 'abcdef'.
  
  IF str1 CO str2. " b a e 这三个字符都存在于 str2 中所以这个判断为true
    WRITE 'str1中的所有字符都存在于str2中'.
  ELSE.
    WRITE 'str1中的所有字符不存在于str2中'.
  ENDIF.
*运行后打印结果: str1中的所有字符都存在于str2中

***********************************************************************************************
  DATA(str1) = 'beg'.
  DATA(str2) = 'abcdef'.
  
  IF str1 CO str2." b e 这两个字符都存在于 str2 中但是g这个字符不存在于str2 所以这个判断为false
    WRITE 'str1中的所有字符都存在于str2中'.
  ELSE.
    WRITE 'str1中的所有字符不存在于str2中'.
  ENDIF.
*运行后打印结果: str1中的所有字符不存在于str2中

                       2.CA
                            CA 是判断 左边数值 任意一个字符 是否 存在于 在 右边数值中。

                            a.情况1: 这里的 str1 是 CA 左边的数值, str2 是 CA 右边的数值。然后结合上面CA的注解以及代码中的注释即可理解。

  DATA(str1) = 'aty'.
  DATA(str2) = 'abcdef'.

  IF str1 CA str2. " 虽然 t y两个字符不存在于 str2中 但是 a 字符 存在于 str2中 所以此判断为true
    WRITE 'str1中有字符存在于str2中'.
  ELSE.
    WRITE 'str1中没有任何字符存在于str2中'.
  ENDIF.
*运行后打印结果: str1中有字符存在于str2中

***********************************************************************************************

  DATA(str1) = 'ty'.
  DATA(str2) = 'abcdef'.

  IF str1 CA str2. " t y 两个字符都不存在于 str2 中 所以此判断为false
    WRITE 'str1中有字符存在于str2中'.
  ELSE.
    WRITE 'str1中没有任何字符存在于str2中'.
  ENDIF.
*运行后打印结果: str1中没有任何字符存在于str2中

                       3.CP
                            CP 是判断 左边数值 是否 与 右边数值的模式匹配。感觉就好像跟用F4搜索帮助的感觉一样。 下图是系统中使用搜索帮助的案例。只要会用系统中的搜索帮助模糊匹配就能很容易理解CP。
在这里插入图片描述
在这里插入图片描述

                            a.模式1:*号 这里的 str1 是 CP 左边的数值, str2 是 CP 右边的数值。然后结合上面CP的注解以及代码中的注释即可理解。

  DATA(str1) = 'SAP2024'.
  DATA(str2) = 'SAP*'.

  IF str1 CP str2. " str2 以SAP开头后面跟一个星号 表示开头为SAP结尾为意长度的字符都能与str2匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1是被str2模式匹配的

***********************************************************************************************

  DATA(str1) = 'SAP2024'.
  DATA(str2) = 'TSAP*'.

  IF str1 CP str2. " str2 以TSAP开头后面跟一个星号 但是str1却是以SAP开头的 所以不匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1不能被str2模式匹配

***********************************************************************************************

  DATA(str1) = 'HELLOSAP2024'.
  DATA(str2) = '*SAP*'.

  IF str1 CP str2. " str2 前后星号中间为SAP字符 表示只要中间是SAP开头末尾可以为任意长度字符都能与str2匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1是被str2模式匹配的

                            b.模式2:+号 这里的 str1 是 CP 左边的数值, str2 是 CP 右边的数值。然后结合上面CP的注解以及代码中的注释即可理解。

  DATA(str1) = 'SAP2'.
  DATA(str2) = 'SAP+'.

  IF str1 CP str2. " str2 以SAP开头后面跟个+号表示只要以SAP开头后面跟一个任意字符的数值都能被str2匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1是被str2模式匹配的

***********************************************************************************************

  DATA(str1) = 'SAP20'.
  DATA(str2) = 'SAP+'.

  IF str1 CP str2.str2 以SAP开头后面跟个+ 但是str1以SAP开头后后面跟了2个字符所以不被匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1不能被str2模式匹配

***********************************************************************************************

  DATA(str1) = 'SAP2024'.
  DATA(str2) = 'SAP++++'.

  IF str1 CP str2. " str2 以SAP开头后面跟个四个+号表示只要以SAP开头后面跟四个任意字符的数值都能被str2匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1是被str2模式匹配的

                            c.模式3:* + 结合使用 相信大家在看完上面的案例之后都可以举一反三了。

  DATA(str1) = 'TSAP2024'.
  DATA(str2) = '+SAP*'.

  IF str1 CP str2. " str2 以中间为SAP 开头为+结尾为* 表示开头为任意字符中间为SAP结尾为任意长度字符都能被str2匹配
    WRITE 'str1是被str2模式匹配的'.
  ELSE.
    WRITE 'str1不能被str2模式匹配'.
  ENDIF.
*运行后打印结果: str1是被str2模式匹配的

                       4.CS
                            CS 是判断 右边数值 是否 存在于 左边数值中。注意: 与CO不同的是CS必须是连续的。

                            a.情况1: 这里的 str1 是 CS右边的数值, str2 是 CS左边的数值。然后结合上面CS的注解以及代码中的注释即可理解。

  DATA(str1) = 'bcd'.
  DATA(str2) = 'abcdef'.

  IF str2 CS str1. "str1 为 bcd字符串这个字符存在于str2中且连续 所以判断为true
    WRITE 'str1被str2包含'.
  ELSE.
    WRITE 'str1不被str2包含'.
  ENDIF.
*运行后打印结果: str1被str2包含

***********************************************************************************************

  DATA(str1) = 'bed'.
  DATA(str2) = 'abcdef'.

  IF str2 CS str1. "str1 为 bed字符串虽然b e d 这三个字符串都存在于str2中但是不连续啊 所以判断为false
    WRITE 'str1被str2包含'.
  ELSE.
    WRITE 'str1不被str2包含'.
  ENDIF.
*运行后打印结果: str1不被str2包含

等于 大小 比较运算符解释作用
EQ(Equal To):                        左操作数等于右操作数。
NE(Not Equal To):                  左操作数不等于右操作数。
LT(Less Than):                      左操作数小于右操作数。
GT(Greater Than):                  左操作数大于右操作数。
LE(Less Than or Equal To):    左操作数小于或等于右操作数。
GE(Greater Than or Equal To):左操作数大于或等于右操作数。

                       5.大小比较运算符
                            这里的大小比较运算符比较简单我就不给出案例了直接给出等价的操作符即可

                            a.EQ: 就是 = 号
                            b.NE: 就是 <> 号
                            c.LT:  就是 < 号
                            d.GT: 就是 > 号
                            e.LE:  就是 <= 号
                            f.GE:  就是 => 号

            a.字符串调整 清理空格 大小写

                       1.清理空格
                           使用 CONDENSE

  DATA:str1 TYPE char50 VALUE '  你         好'.
  DATA:str2 TYPE char50 VALUE '  你         好'.

  CONDENSE str1        ."使用CONDENSE可以删除前导尾随空格,将连续空格变为一个空格
  CONDENSE str2 NO-GAPS."添加 NO-GAPS 后缀可以删除所有空格
  WRITE / str1."你 好
  WRITE / str2."你好

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

            a.数据类型 转化

在 ABAP 中,你可以使用 WRITE 语句或 CONVERT 函数将 TIMESTAMP 类型的变量转换为字符串。下面是两种方法的示例:

使用 WRITE 语句:

            a.增加 去除 前导零

                       1.使用插值语法
                            有些系统版本可能不支持

  DATA lv_vbeln TYPE vbak-vbeln VALUE '12'."12

  "增加前导零
  lv_vbeln = |{ lv_vbeln ALPHA = IN  }|   ."0000000012
  "去除前导零
  lv_vbeln = |{ lv_vbeln ALPHA = OUT }|   ."12

*如果变量参考的类型没固定长度可以使用 WIDTH 关键字指定长度
  DATA lv_vbeln TYPE string VALUE '12'.
  lv_vbeln = |{ lv_vbeln ALPHA = IN WIDTH = 20 }|   ."00000000000000000012

                       2.使用函数

  DATA lv_vbeln TYPE vbak-vbeln VALUE '12'."12
  
  "增加前导零
  CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
    EXPORTING
      input        = lv_vbeln
    IMPORTING
      output       = lv_vbeln."0000000012
      
  "去除前导零
  CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
    EXPORTING
      input        = lv_vbeln
    IMPORTING
      output       = lv_vbeln."12

            a.数据 类型 格式 合法 校验

                       1.校验日期是否有效
                           a.判断是否为0
                            最简单的方法就是判断这个日期字段是否等于 0,详细请看下面案例与注释。

FORM data_check .

  DATA lv_date1 TYPE DATS VALUE '20240202'.
  DATA lv_date2 TYPE DATS VALUE '20230240'."2月份没有40号这天
  DATA lv_date3 TYPE DATS VALUE '2049'    ."格式错误不是YYYYMMDD
  DATA lv_date4 TYPE DATS VALUE '10101010'.
  DATA lv_date5 TYPE DATS VALUE ''        ."为空也不行
  DATA lv_date6 TYPE DATS VALUE '09210203'."没有0921PERFORM check_date USING lv_date1.
  PERFORM check_date USING lv_date2.
  PERFORM check_date USING lv_date3.
  PERFORM check_date USING lv_date4.
  PERFORM check_date USING lv_date5.
  PERFORM check_date USING lv_date6.

ENDFORM.

FORM check_date  USING pv_date.

  IF pv_date = 0.
    WRITE / pv_date && ' 校验不通过'.
    WRITE / .
  ELSE.
    WRITE / pv_date && ' 校验通过'.
    WRITE / .
  ENDIF.

ENDFORM.

在这里插入图片描述

                           b.使用函数
                            可以用函数但是我感觉没必要。不做介绍。


二、程序 架构 分区 解耦

          步骤二介绍

            a.Perform 子例程

注意 关键字顺序
                       1.步骤二 a 1
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

二、面向对象 OO

          步骤二介绍
=> -> 调用有什么区别
调用方法 加括号与不加括号的区别

            a.步骤二 a

                       1.步骤二 a 1
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

二、各类运算符

          这里介绍一些常用的运算逻辑符,也会介绍到不常用的,如果需要用到也可以来到这里再查阅
?=

            a.步骤二 a

                       1.步骤二 a 1
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

二、内存指针动态创建及操作

          这里不再详细讲述如何创建声明部分,创建声明部分在本文上面已经详细讲过,部分可能某些老的系统版本不兼容。
ASSIGN im_dataTO <fs_structure>.
ASSIGN im_data->* TO <fs_structure>. 区别

            a.步骤二 a

                       1.步骤二 a 1
                            pass

                       2.步骤二 a 2
                            pass

                       3.步骤二 a 3
                            pass

二、获取各种对象的属性

          

            a.获取 字符串 内表 长度

                       1.获取内表长度
                           a. 使用 DESCRIBE

  "描述 gt_data 这个内表的 行数 赋值给 lv_lines.
  DESCRIBE TABLE gt_data LINES data(lv_lines).

                           b. 使用 LINES()

  "LINES() 是一个函数 用来返回一个内表的行数。
  data(lv_lines) = LINES( gt_data ).

                       2.获取字符串长度
                            STRLEN( ) 是获取字符串的字符长度也就是字符数,dynamic_output_length( )是获取字符串的输出长度,它会考虑到字符串在输出时的实际长度。对于非英文字符(如中文字符),通常会占据两个字符的位置,因此输出长度会相应地增加。
                           a. 使用 STRLEN( )

  DATA lv_string TYPE string VALUE 'AB中国'.
  
  "STRLEN( )函数用于获取 字符串字符数量 lv_len 为4
  data(lv_len) = STRLEN( lv_string ).

                           a. 使用 类

  DATA str1 TYPE string VALUE 'AB中国'.
  
  "lv_len为6 每个中文占两个字符
  data(lv_len) = cl_abap_list_utilities=>dynamic_output_length( str1 ).

            a.根据内表 获取 字段名 字段描述

            a.步骤二 a

二、系统变量

          

            a.常用系统变量

            b.不常用系统变量

在这里插入图片描述
在这里插入图片描述

二、ABAP 内置函数

          在我们ABAP语言中是有好多内置的实用函数的,这个是语言层面,和我们SE37的函数是两码事。

            a.内表是否存在指定的行 LINE_EXISTS()

                       1.代码示例

* LT_RETURN 是一个有TYPE字段的内表

IF LINE_EXISTS( LT_RETURN[ TYPE = 'E' ] ) OR LINE_EXISTS( LT_RETURN[ TYPE = 'A' ] ).

* 这种语法是用来在ABAP中检查一个内表中是否存在指定的行

                       2.函数详解
                           LINE_EXISTS是一个谓词函数,它接受一个表达式作为参数,并返回一个布尔值。
                       3.代码详解
                           这种语法的意思是,检查 LT_RETURN 内表中是否存在 TYPE 字段等于 ’E’ 或者 ’A’ 的行,并返回相应的真或假。如果存在这样的行,那么结果为真;如果不存在这样的行,那么结果为假。这种语法可以方便地在条件判断中使用,而不需要使用其他函数或者操作符。

            a.大小写转化 TO_UPPER TO_LOWER TO_MIXED

                       1.代码示例

lv_upper = TO_UPPER( lv_text ).
lv_lower = TO_LOWER( lv_text ).
lv_mixed = TO_MIXED( lv_text ).

二、ABAP 新语法

          新语法使用起来还都是非常方便的。

            a.LOOP分组循环

                       1.代码示例

DATA  lt_data TYPE tihttpnvp.

lt_data = VALUE #(
                      ( name = '字段1' value = '1-01')
                      ( name = '字段2' value = '2-01' )
                      ( name = '字段3' value = '3-01' )
                      ( name = '字段1' value = '1-02' )
                      ( name = '字段2' value = '2-02' )
                      ( name = '字段1' value = '1-03' )
                      ( name = '字段1' value = '1-04' )
                      ( name = '字段2' value = '2-03' )
                    ).

LOOP  AT lt_data INTO DATA(ls_data) GROUP BY ( name = ls_data-name )
                 ASCENDING ASSIGNING FIELD-SYMBOL(<group>).

  WRITE / '开始处理' && <group>-name && '这一组'.

  LOOP  AT GROUP <group> ASSIGNING FIELD-SYMBOL(<fs>).
    WRITE:/ <fs>-name,<fs>-value.
  ENDLOOP.

  WRITE / '已经处理完' && <group>-name && '这一组'.
ENDLOOP.

                       2.运行效果
                           GROUP BY后面是要指定根据哪些字段分组,name是内表中的字段名,ls_data-name代表具体的值。这个分组循环比AT NEW好用,也不用对内表按照字段排序。
在这里插入图片描述

            b.SWITCH 简洁强大的判断赋值操作

                       1.代码示例
                           感觉是 CASE 的 升级版一样。lv_month 是你要判断的值,WHEN 后面是判断你判断的值是否条件成立,THEN 后面的值会赋值给lv_season,SWITCH后面的string是指定要返回的数据类型

DATA(lv_month) = '05'.

DATA(lv_season) = SWITCH string(
  lv_month
  WHEN '01' OR '02' OR '03' THEN '春天'
  WHEN '04' OR '05' OR '06' THEN '夏天'
  WHEN '07' OR '08' OR '09' THEN '秋天'
  WHEN '10' OR '11' OR '12' THEN '冬天'
  ELSE '月份不存在'
).

                       3.嵌套用法

DATA(lv_month) = '02'.

DATA(lv_season) = SWITCH string(
  lv_month
  WHEN '01' OR '02' OR '03' THEN SWITCH string(
                                               lv_month
                                               WHEN '01' THEN '春天第1个月'
                                               WHEN '02' THEN '春天第2个月'
                                               WHEN '03' THEN '春天第3个月'
                                               )
  WHEN '04' OR '05' OR '06' THEN '夏天'
  WHEN '07' OR '08' OR '09' THEN '秋天'
  WHEN '10' OR '11' OR '12' THEN '冬天'
  ELSE '月份不存在'
).


WRITE / lv_season.

总结

        以上就是今天要讲的内容,本文仅仅简单介绍了ABAP一些常用的语法和关键字 ,感觉笔者讲的好对自己有帮助的还麻烦点个免费的赞赞制作不易谢谢谢谢!!!如果有说错或者不好的地方还望大家提出来见谅。感觉笔者写的好的别忘了关注点赞加评论哦,也欢迎大家一起来讨论。谢谢!

  • 19
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiao贱贱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值