SAP ABAP 基础知识

0:前言

作者是ABAP新手 之前只学过C / JAVA等语言,所以笔记类型偏向于把ABAP的本质知识和C以及JAVA串联起来,在学习的基础上加了一些自己的理解,故希望读者具有C和面向对象的基础,才能更好的学习各项语言。

1:SAP开发工具

工具名:SAP GUI

常用 T-code (事务码)

se38 创建程序、ABAP 编辑器
se80 abap工作台
SE84 访问 ABAP 资源库信息系统(在 SAP 轻松访问菜单中,选择工具 → ABAP 工作台 → 概览 → 信息系统)
SE11 ABAP 字典(显示、更改、创建)
SE12 ABAP 字典(仅显示)
SE51 屏幕绘制器
SE41 菜单绘制器
SE37 功能构建器
SE24 类构建器
SM30 数据库表维护视图
/o GUI新开窗口
/n GUI当前窗口

常用系统变量

SY-SUBRC: 系统执行某指令后,表示执行成功与否的变量,0表示成功

SY-DBLNT: 被处理过的记录的笔数

SY-UNAME: 当前使用者登入SAP的USERNAME

SY-DATUM: 当前系统日期

SY-UZEIT: 当前系统时间

SY-TCODE: 当前执行程序的Transaction code

SY-REPID: 当前程序名称

SY-INDEX : 当前LOOP循环过的次数

SY-TABIX: 当前处理的是internal table 的第几笔

SY-TMAXL: Internal table的总笔数

SY-SROWS: 屏幕总行数

SY-SCOLS: 屏幕总列数

SY-MANDT: 當前系統編號(CLIENT NUMBER)

SY-VLINE: 画竖线

SY-ULINE: 画横线

SY-PAGNO: 当前页号

SY-LINSZ: 当前报表宽度

SY-LINCT: 当前报表长度

SPACE: 空字符串

SY-LSIND: 列表索引页

SY-LISTI: 上一个列表的索引

SY-LILLI: 绝对列表中选定行的行号

SY-CUROW: 屏幕上的行

SY-CUCOL: 光标列

SY-CPAGE: 列表的当前显示页

SY-STARO:真实行号

SY-LISEL: 选择行的内容,长度为255

SY-LANGU:当前系统语言
SY-LINNO: 当前行
SY-SUBRC:语句执行后的返回值,0表示成功
SY-DATUM:当前服务器日期
SY-UZEIT:当前服务器时间
SY-ULINE:255长度的水平线
SY-VLINE:垂直线
SY-INDEX:循环说执行的次数
SY-TABIX:内表循环的次数
SY-DYNNR:当前Screen号
SY-MANDT:当前登录的Client号
SY-STEPL:返回当前操作的屏幕行号(Table Control)
SY-LOOPC:当前表格控件在屏幕中的总行数(Table Control)
SY-UCOMM:PAI所出发的功能代码
SY-DYNNR:当前屏幕号
SY-MSGID:Message Class
SY-MSGNR:Message Number
SY-MSGTY:Message Type
SY-MSGV1~4:Message Variant
SY-LINCT:REPROT语句中设定的LINE-COUNT
SY-LINSZ:REPROT语句中设定的LINE-SIZE
SY-SROWS:当前窗口的列表行数
SY-SCOLS:当前窗口的列表栏目数
SY-PAGNO:当前页的页码
SY-LINNO:当前选定行的行号
SY-COLNO:当前选定列的列号
SY-LSIND:当前列表索引,第一级列表为1
SY-LILLI:选择某行时光标行位置
SY-CUROW:选择某行时光标列位置 
  1. 程序命名
    1. 定制化程序 Z开头
    2. 自己测试使用 不开放给用户 Y开头
  2. 对程序设
    请添加图片描述

程序类型一般是 可执行程序

2:数据类型

2.1:ABAP基本数据类型

2.1.1:数据类型分类

  • 数据类型 Data Type

    1. ABAP基本数据类型

      • 系统内部定的数据类型

      • 类型初始长度可变长度初始值意义
        I440整型
        F880浮点型
        P81-160高精度小数
        C11-65535‘…’文本字段
        D88‘00000000’YYYYMMDD
        N11-65535‘0…0’数字字符串
        T66‘000000’HHMMSS
        X11-65535X’0…0’十六进制字段
      • 三种数字类型

        • 整数型 I :非整型运算进行四舍五入 ,

        • 小数型 P :允许小数位 可用1~16位 小数位最大14位 小数点1位 高精度 存什么就展示什么 不存在精度丢失(其实也是字符串来表示小数)

          • 必须设置程序属性为 Fixed point arithmetic(即定点算法,一般默认选中),若不选,类型P将失效为整数类型

            DATA gv_p(16) TYPE P. "可变长度,指定变量长度,如果不指定 默认为8B 此时16是指32位的数字 可以有31个数字"
            DATA gv_p TYPE P DECIMALS 2."指定小数位为2位,最多可以14位"
            
          • 此类型两个数字的大小为1B,默认8B:可以表示一个15位的大数字,小数点占一个位置,一共是16个位,总共占8B。

        • 浮点型 F :定义指数 ,需要调用”FLTP_CHAR_CONVERSION“函数把其转换位其他类型数据后才可以输出。

          • F转换二进制时会发生进位误差。
          • 数值较大或者是不需要进行四舍五入时可以使用类型F,取近似值时使用
        • 创建程序时候没有选择 Fixed point arithmetic ,那么使用P类型时小数点会被忽略 只忽略小数点 例如 :1.1会变成11。

      • 四种字符串类型:

        • C:定义文字,数字,特殊字符

        • N:用于显示C类型的数字,以字符串的方式显示整数

          • 类型I:与变量长度无关,输出变量自身值。
          • 变量N:变量值长度不足,前面补0补足位数,length位补够。并以字符串形式显示数值。
        • D:日期类型

          *日期类型和时间类型
          DATA: gv_date TYPE d.
          gv_date = sy-datum."获取当前的日期"
          WRITE :/ gv_date.
          
          gv_date = gv_date + 3."以日为计算基础 结果还是日期"
          WRITE :/ gv_date.
          
          
          DATA: gv_time TYPE t.
          gv_time = sy-uzeit."获取当前的时刻 093859 HHMMSS"
          WRITE :/ gv_time.
          gv_time = gv_time - 60."以秒为计算基础"
          WRITE :/ gv_time.
          
        • T:时间类型

          • 系统变量

            sy-datum 和 sy-datlo 都表示系统日期

            前面表示是SAP系统时间,后面表示是用户机的时间。

            sy-uzeit 和 sy-timelo 都表示系统时间

    2. 局部数据类型

      • 存在于程序内部
    3. 全局数据类型

      • 存在于数据字典中
      • 所有的程序都可以使用的数据类型
      • SE11创建ABAP数据字典对象
  • 数据变量 Data Variable

TYPES dtype[TYPE type|Like dobj]"关键词 TYPES"

DATA var[TYPE type|Like dobj]

TYPES: ty_char TYPE c LENGTH 11, "长度11的文本
	   ty_date TYPE d, "日期"
	   ty_float TYPE f, "浮点型"
	   ty_int TYPE i, "整数"
	   ty_num TYPE n, "数字文本"
	   ty_packed TYPE p LENGTH 10 DECIMALS 3,"压缩号"
	   ty_time TYPE t, "时间"
	   ty_x TYPE x, "十六进制"
	   ty_xstring TYPE xstring, "十六进制"

2.1.2:声明数据类型 TYPE/LIKE

方法一:参照基本数据类型定义变量

ABAP提供的基本类型定义变量
DATA:gv_num TYPE i,
	 gv_deci TYPE F,
	 变量名 TYPE 类型名,(最后一句要加句号 英文.)

方法二:参照局部数据类型定义变量

将程序中常用的数据以及结构声明为一个数据类型(自定义数据类型),但是此类数据类型只能在该程序内部使用

TYPES:BEGIN OF t_struct, "相当于是C语言的结构体"
	  col1 TYPE c,
      col2 TYPE i,
      col3 TYPE d,
      END OF t_struct.
      
DATA:gs_struct TYPE t_struct,
	 gv var LIKE gs struct_col1.

方法三:参照全局数据类型定义变量

利用ABAP数据字典定义变量的方法,此数据类型在所有程序都可以使用。

DATA:gv_carrid TYPE s_carr_id,"数据字典类型"
	 gv_connid TYPE sflight-carrid, "数据字典类型"
	 gv_var TYPE c LENGTH 20. "全局数据类型"

LIKE:参考目标类型来声明

2.1.3:DATA语句

DATA 语句用于定义数据变量。

变量名包括了 “_”,最长可定义30位。

  1. TYPE 变量类型名

    DATA:gv_num1 TYPE i,
    	 gv_id   TYPE i.
    

    冒号 使得一个命令从逗号开始执行,直达遇到句号结束

    用一个冒号就可以避免重复使用相同命令

  2. LIKE num

    num 代表任何类型的变量,gv_num2可以定义成与gv_num1相同类型的变量。

    DATA:gv_num2 LIKE gv_num1
    
  3. VALUE int

    设置变量的初始值

    如果使用VALUE IS INITIAL (初始化),变量的初始值为所参照的数据类型的初始值,是可省略的。

    DATA:gv_num TYPE i VALUE 123,
         gv_flag       VALUE 'X',
         gv_idx LIKE sy-tabix VALUE 45.
    
  4. LENGTH n

    指定字段长度,仅适用于C,N,P,X类型。

    DATA:gv_num TYPE n LENGTH 2.
    
  5. DECIMALS n

    仅适用于 P类型,n是指定1~14位的小数。

    DATA:gv_num TYPE p DECIMALS 3.
    

2.1.4:ABAP基本语法

  1. 程序使用句号. 表示一个语句的结束。

  2. 注释分两种

    1:
    *这是一个行注释
    2:
    "这是一个右注释
    
  3. 字符串使用单引号 ‘this is string’ 显示。

    gv_val = 'Enjoy ABAP'.
    
  4. 各个命令用空格分开

    gv_val = 'Enjoy'. 正确写法 各命令符号之间有空格
    

2.1.5:命名规则

SAP规定:

  1. ABAP 数据字典的程序以及数据对象后命名时,要以Z或Y开头
  2. 不能使用INSERT/APPEND 等关键字
  3. 允许定义变量名长度最大为30位,其中包含“_”。
  4. 变量前2位表示范围以及类型。

请添加图片描述

1:定义全局变量(Global Variable)

全局变量在程序激活状态下,一直占用内存地址。

定义全局变量时候要以G开头

具体数据定义方法:

请添加图片描述

前缀长度设置是3位。

​ 1:范围

​ 2:数据类型

​ 3:数据类型

例如:GVF_CARRID 意思是全局 字段 浮点型

2:局部变量

abap里面的局部变量和Java不同 abap局部变量不会自动清空 只是不能用于其他块内 局部变量在块内计算后会保持数据 再次调用该块 局部变量需要手动CLEAR才会清空局部变量的值

程序模块内的有效变量

请添加图片描述

2.1.6:数字运算符(演算子)

数字类型 F 、I 、P可使用

符号用法作用相同关键字
+A + BADD A TO B
-A - BSUBTRACT B FROM A
*A * BMULTIPLY A BY B
/A / BDIVIDE A BY B
DIVA DIV B取整
MODA MOD B取余
**A ** B乘幂

数字运算用函数

函数说明用法
ABS返回绝对值ABS(-100) 返回100
SIGN返回符号负数 -> -1;0-> 0; 正数-> +;
CEIL返回不小于该值的最小整数ceil(1,3),ceil(1.7) 都返回2
FLOOR与CEIL相反floor(1,3),floor(1.7) 返回1
TRUNC取得整数部分trunc(1,3)返回1
FRAC取得小数部分frac(‘2.9’) 返回0.9

Floating-Point函数

请添加图片描述

2.1.7:字符类型

字符字段,有以下四种类型

  • C:用于定义文字,数字,特殊文字。
  • N:用于显示C类型的数字,以字符串形式显示整数。
  • D:日期类型。
  • T:时间类型。
DATA gv_fd.
DATA gv_fd TYPE c.
DATA gv_fd(1) TYPE c. "直接指定C类型长度"
DATA gt_fd TYPE c LENGTH 1. "指定C,N,X,P的长度"

*以上四句语法执行效果一样
DATA gv_f0.
DATA gv_f1 TYPE C.
DATA gv_f2(1) TYPE C.
DATA gv_f3(2) TYPE C.
DATA gv_f4 TYPE C LENGTH 2.
DATA gv_f5(5).
DATA gv_len TYPE i.

MOVE: 'CHINA' TO gv_f0,
      'CHINA' TO gv_f1,
      'CHINA' TO gv_f2,
      'CHINA' TO gv_f3,
      'CHINA' TO gv_f4,
      'CHINA' TO gv_f5.
WRITE :/ gv_f0,
       / gv_f1,
       / gv_f2,
       / gv_f3,
       / gv_f4,
       / gv_f5.
gv_len = STRLEN( gv_f5 ).
WRITE / gv_len."write / 代表换行"

2.1.8:不定长ABAP基本数据类型 string

最具代表的有:String 类型

程序执行时,才生成动态内存

命令语句说明用法
FIND串内存在X字母时,sy-subrc变量(系统变量)返回值是0FIND P IN TEXT
REPLACE把F中的G 部分用P来替换掉REPLACE G IN F WITH INTO P
TRANSLATE大小写的替换TRANSLATE A TO LOWER/UPPER CASE
SHIFT左移位符号,所有字符向左移动一位SHIFT A
CONDENSE去掉串左边的空格实现左对齐CONDENSE A NO-GAPS
NO-GAPS去掉串内的空格配合condense使用
OVERPLAY填充Y前n个字符到串X内的首次检测到的n个连续空格中OVERPLAY X WITH Y
CONCATENATE连接两个串A,B,并存到CCONCATENATE A B INTO C.
SPLIT以X为分隔符分割字符串S为A,B,CSPLIT S AT ‘X’ INTO A,B,C
COUNT匹配指定字符串substring或正则式regex出现的子串次数,返回的类型为i整型类型count( val = TEXT {sub = substring} {regex = regex})
MATCH返回的为匹配到的字符串。注:每次只匹配一个。occ:表示需匹配到第几次出现的子串。如果为正,则从头往后开始计算,如果为负,则从尾部向前计算match( val = TEXT REGEX = REGEX occ = occ)
STERLENString类型的尾部空格会计入字符个数中,但C类型的变量尾部空格不会计算入strlen(arg)
`test space   ` ===> 结果是“test space  ” "可以完全识别空格"           
'test space   ' ===> 结果是“test space”   "会把多余的空格给去掉"        

2.1.9:Hexadecimal类型 十六进制类型 X类型

1B 8字节 => 4个字节为一个十六进制的码位

在ABAP 中主要用于印刷和图片处理部分

2.1.10:DESCRIBE

2.1.10.1:DESCRIBE FIELD
DESCRIBE FIELD DATA1 
   [TYPE typ [COMPONENTS com]]                 "运行结果是data1的类型被存储在typ1变量里,com1则存放了data1里面有几个子元素。"           
   [LENGTH ilen IN { BYTE | CHARACTER } MODE]  "运行的结果是data1定义的长度存在了ilen里。"
   [DECIMALS dec]                              "运行的结果是如果data1是小数,dec则存放了小数点后的位数。"
   [OUTPUT-LENGTH olen]                        "运行的结果是data1的输出长度存在了olen里。"
   [HELP-ID hlp] 
   [EDIT MASK mask].
2.1.10.2:DESCRIBE TABLE
DESCRIBE TABLE itab   [KIND knd]  [LINES lin]  [OCCURS n]   "判断内表itab的某些属性并把它们指定到指定的变量中。不同的选项使你能够判断表类型,当前字段行数 和 初始化需要的内存大小。"
2.1.10.3:DESCRIBE DISTANCE
DESCRIBE DISTANCE BETWEEN dobj1 AND dobj2 INTO dst
                          IN {BYTE|CHARACTER} MODE. 
                          "这个语句把数据对象dobj1和dobj2的起始位置的距离赋给i类型的数据对象dst。如果是复杂数据类型,被参照的数据类型是不相关的除了内部参照的位置(对于字符串和内表)或者参考变量。Dobj1和dobj2以哪种顺序被指定并不重要。"

2.1.11:字符串表达式

String Template字符模板:字符串模板在 | … | 之间定义,主要分为两部分,固定文本和变量

变量只能在 { … } 内使用,大括号之外的所有字符均作为固定文本使用,空格始终不会被忽略

在使用变量时,可以通过控制语句来指定数据的显示格式,如例1,将日期用系统格式输出

在固定文本中,如果出现 | ,{ } 或 \ 等特殊字符时,需要使用转义符 \,如例2

"1 将日期转换为系统格式
"这里date= environment是用来格式化日期的,将日期转换成系统格式。
DATA(lv_string) = |Today is { sy-datum DATE = ENVIRONMENT }|. 

"2 当有特殊符号时,在前面增加“\”,如:| 、{ } 或 \
data(lv_vbeln1) = conv vbeln('123').
lv_vbeln1 = |\\\|{ lv_vbeln1 }\}7|.

使用&或&&将多个字符模板串链接起来,可以突破255个字符的限制


|...| &  |...|
|...| && |...|
"上面两行代码效果一样"
"在没有没有变量表达式或控制字符\r \n \t的时候 不需要使用字符模板也可以连接 但是如果有控制字符时不加字符模板将会失去控制效果"

`...` && `...`   "忽略尾部空格  

2.2:局部数据类型

2.2.1:声明类型

在程序中声明的数据类型视为局部数据类型,利用关键字TYPES 声明。

*局部数据类型

TYPES t_char10(10) TYPE c.
DATA gv_val1 TYPE t_char10.
DATA gv_val2 LIKE gv_val1.

gv_val1 = '1234567890'.
WRITE / gv_val1.

gv_val2 = '1234567890'.
WRITE / gv_val2.

*结构体--------------------------->start.
*声明结构体
TYPES: BEGIN OF t_ren,
  name TYPE c LENGTH 20,
  country TYPE c LENGTH 15,
  city TYPE c LENGTH 10,
  END OF t_ren.
*定义结构体变量
  DATA gs_people1 TYPE t_ren.

  gs_people1-name = 'JANG JONG SUK'.
  gs_people1-country = 'CHINA'.
  gs_people1-city = 'Beijing'.

  WRITE :/ gs_people1-name,
           gs_people1-country,
           gs_people1-city.
*嵌入--嵌入结构体类型
TYPES: BEGIN OF t_info.
  INCLUDE TYPE t_ren as ren.
TYPES: phone TYPE c LENGTH 10,
END OF t_info.

DATA gs_people2 TYPE t_info.

gs_people2-ren-name = 'JANG JONG SUK'.
gs_people2-ren-country = 'CHINA'.
gs_people2-ren-city = 'Beijing'.
gs_people2-phone = '123456789'.

WRITE :/ gs_people2-ren-name,
         gs_people2-ren-country,
         gs_people2-ren-city,
         gs_people2-phone.

*直接定义结构体变量
DATA: BEGIN OF gs_people3,
  name TYPE c LENGTH 20,
  country TYPE c LENGTH 15,
  city TYPE c LENGTH 10,
  END OF gs_people3.

  gs_people3-name = 'WW SUK'.
  gs_people3-country = 'CHINA'.
  gs_people3-city = 'Beijing'.

  WRITE :/ gs_people3-name,
           gs_people3-country,
           gs_people3-city.

*嵌入--嵌入结构体变量--使用AS的
DATA: BEGIN OF gs_people4.
  INCLUDE STRUCTURE gs_people3 AS ren.
DATA: phone TYPE c LENGTH 10,
END OF gs_people4.

gs_people4-ren-name = 'WWisAS SUK'.
gs_people4-ren-country = 'CHINA'.
gs_people4-ren-city = 'Beijing'.
gs_people4-phone = '123456789'.

WRITE :/ gs_people4-ren-name,
         gs_people4-ren-country,
         gs_people4-ren-city,
         gs_people4-phone.

*嵌入--嵌入结构体变量--不用AS的简写
DATA: BEGIN OF gs_people5.
  INCLUDE STRUCTURE gs_people3.
DATA: phone TYPE c LENGTH 10,
END OF gs_people5.

gs_people5-name = 'WWnotAS SUK'.
gs_people5-country = 'CHINA'.
gs_people5-city = 'Beijing'.
gs_people5-phone = '123456789'.

WRITE :/ gs_people5-name,
         gs_people5-country,
         gs_people5-city,
         gs_people5-phone.

2.3:ABAP数据字典类型数据

数据字典的数据类型为全局数据类型

三种形式:

  • 表以及视图
  • 数据类型:数据元素,结构体,表类型
  • 类型组

创建方式:

​ T-CODE:SE11创建、查询、修改数据字典

*数据字典
*参照表,视图声明数据类型
DATA: gs_sflight TYPE sflight."参考sflght表来生产变量 并进行赋值查询

SELECT SINGLE * FROM sflight INTO gs_sflight WHERE carrid = 'AA'.

WRITE:/ gs_sflight-carrid,
        gs_sflight-connid.

*参照表的部分字段进行定义变量
DATA: gv_carrid TYPE sflight-carrid,
      gv_connid TYPE sflight-connid,
      gv_fldate TYPE sflight-fldate.
gv_carrid = 'AA'.
gv_connid = 0017.
gv_fldate = sy-datum.
WRITE: gv_carrid,
       gv_connid,
       gv_fldate.

*参照基本数据类型进行定义变量
*数据元素
DATA gs_carrid TYPE s_carr_id. "TYPE SFLIGHT-CARRID的数据元素
gs_carrid = 'AA'.
WRITE: 'Carrid:',gs_carrid.

*结构体 用se11 命令新建的数据字典的结构体

DATA gs_struct TYPE zstruct.

gs_struct-col1 = '1'.
gs_struct-col2 = 'Structure'.
gs_struct-col3 = 'ABAP Dictionary Test'.

WRITE: gs_struct-col1,gs_struct-col2,gs_struct-col3.

*利用类型组的TYPE 定义 

DATA: gv_tgrpl TYPE ztgrp_typ1,
      gv_tgrp2 TYPE ztgrp_typ2.
      gv_tgrpl ='Type Group'.
      gv_tgrp2-coll ='Test'.
      gv_tgrp2-col2 =7.
WRITE:gv_tgrp1,gv_tgrp2-coll,gv_tgrp2-col2,ztgrp_name.

请添加图片描述

2.3.1:数据元素与域

数据元素是构成结构、表的基本组件,域又定义了数据元素的技术属性。

将技术信息从Data element提取出来为Domain域的好处:技术信息形成的Domain可以共用,而每个表字段的业务含意不一样,会导致其描述标签、搜索帮助不一样,所以牵涉到业务部分的信息直接Data element中进行描述,而与业务无关的技术信息部分则分离出来形成Domain

1:Data element

Data element主要附带Search Help、Parameter ID、以及标签描述

2:Domain

Domain主要从技术方面描述了Data element,如Data Type数据类型、Output Length输出长度、Convers. Routine转换规则、以及Value Range取值范围

2.4:赋值

2.4.1:给变量赋值

实际处理时,用MOVE 或者WRITE TO 语句来给变量赋值。

move a to b. a的数据类型还会被转换成b类型 (除了D和T以外,所有数据类型可以互相转换)
b=a.
write a to b.
都是把a的值赋值给b

*move-corresponding
如果想对结构体赋值
那么要使用
move-corresponding string1 to string2.
会按照名字相同的字段进行赋值
如果用move 则是单纯的按顺序赋值

*结构体赋值
DATA: BEGIN OF gs_ren1,
  name(20) VALUE 'Kim Sung Joon',
  country(10) VALUE 'China',
  city(20) VALUE 'Beijing',
  END OF gs_ren1.

DATA: BEGIN OF gs_info,
  name(20),
  city(20),
  phone(10) VALUE '1234567890',
  END OF gs_info.

MOVE-CORRESPONDING gs_ren1 TO gs_info.
WRITE:/ gs_info-name,gs_info-city,gs_info-phone.

*write 语句有两种用法 
1:输入报表 
2:变量赋值 加TO
将a的数据类型转换成C后进行赋值给b。
前提是a是可以转换成C类型的。

2.4.2:用offset 进行赋值

DATA: a(8) VALUE 'ABCDEFGH',
      b(8),
      m TYPE i VALUE 2,
      n TYPE i VALUE 3.
MOVE a+2(3) TO b. "CDE"
MOVE a+m(n) to b. "CDE"

MOVE a+m(n) to b+p(q). "前后两个都可以偏移"
*b值为CDE 意思是从a开头往后2个开始,也就是第三个字符开始C,起始点,然后偏移3个字符,C\D\E。

*CLEAR 清除变量内容 回归默认值

2.4.3:结构体之间的计算操作

ADD-CORRESPONDING
SUBTRACT-CORRESPONDING
MULTIPLY-CORRESPONDING
DIVIDE-CORRESPONDING
DATA: BEGIN OF gs rate,"比重
peng TYPE f VALUE '0.8'
Zhou TYPE fVALUE'1.0',
END OF gs rate.
DATA: BEGIN OF gs result,
Peng TYPE i VALUE 95.
Zhou TYPEi VALUE 70.
END OF gs result.
MULTIPLY-CORRESPONDING gs_result BY gs_rate.
WRITE:'Test Result',Peng:',gs_result-Peng,'Zhou:',gs_result-Zhou.

2.5:其他变量

程序中经常使用的值可以定义为常量。

定义常量后在程序内不可以进行修改。

*常量
CONSTANTS: c_company(10) VALUE 'LG CNS'.
CONSTANTS: BEGIN OF c_people,
            name(20) VALUE'Zhou Wen Woo',
            country(10) VALUE 'China',
           END OF c_people.
WRITE:c_company,c_people-name,c_people-country.
*静态变量
DO 3 TIMES."指定子程序循环3次
  PERFORM call_subr.
ENDDO.

DO 3 TIMES."指定子程序循环3次
  PERFORM call_subr2.
ENDDO.

FORM call_subr."子程序块 要写在报表后面
  STATICS lv_val TYPE i.
  lv_val = lv_val + 1.
  WRITE :/'STATIC Variable:',lv_val.
 ENDFORM.
*不用静态变量
FORM call_subr2."子程序块
  DATA lv_val TYPE i.
  lv_val = lv_val + 1.
  WRITE :/'NOT STATIC Variable:',lv_val.
 ENDFORM.
 
*TABLE
TABLES:scarr.
SELECT FROM scarr.
WRITE:scarr-carrid,scarr-carrname.
ENDSELECT.

3:SQL

  • DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等;
  • DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据);
  • DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;
  • DQL(Data Query Language):数据查询语言,用来查询记录(数据)

3.1:sql种类

  • OPEN SQL:
    • ABAP 语言使用 只能使用DML语言 (以及select)
    • 比native sql使用简单
    • 可以使用本地缓冲器
  • NATIVE SQL:数据库接口操作数据库
    • 可以直接连接数据库使用DML DDL 语言
    • 还可以使用OPEN SQL 的语句 (select update delete)

3.2:sql与本地缓冲器

请添加图片描述

3.3:OPEN SQL

关键字功能
SELECT从数据库表中读取数据
INSERT往数据库表中追加数据
UPDATE修改数据库表的数据
MODIFY执行的是INSERT + UPDATE功能。存在此条数据 用update;不存在 就是用insert
DELETE删除数据库表数据

所有的OPEN SQL 成功后:

  • 会修改系统变量 SY-SUBRC 为 0;
  • SY-DBCNT 为返回的数据个数;

读取数据命令

语句功能
SELECT
INTO指定查询结果数据存储的变量,并在程序中应用
FORM查询表名
WHERE条件查询
GROUP BY分组查询
HAVING限制GROUP BY条件
ORDER BY用于排序

3.3.1:SELECT:

  •  select single :只从数据库内取一条数据,多条中的任意一条
     select single :只从数据库内取一条数据,多条中的任意一条
     select *:所有字段全查出来
     select :结果有多条时,结果会保存到内表
     select distinct :用于删除重复值,查出结果全是去重了的
     
    *1---select使用into的结果如果不是内表,而是结构体(工作区)或者字段时候,就需要endselect
     SELECT * INTO gs_wa FROM sflight WHERE carrid EQ 'AA'.
     ENDSELECT.
    *1---要使用 endselect结束,相当于是在loop循环中执行select使,每取出一条数据,就把他追加到结构体中。
    
    select cols as othername "给字段指定别名" 
    
    

3.3.2:into

  • 查一条数据时用结构体,工作区接数据

    SELECT ... INTO [CROSSPONDING FIELDS OF] wa.
    

    当查询多个关键字的时候,使用crossponding fields of来进行自动匹配同名字段

  • 查多条数据时用内表

    select ... into|appending [crossponding fields of] TABLE itab [package size n]
    
    • appending:直接在原有内表上追加数据
    • into:先清空内表数据,然后插入数据
    • package size of:设置一次追加到内表的条数,查询条数大于n,就一次只追加n条。
      • 一次是指一次select,但并非表示查到n个就不查了,会在endselect区间内一直查下去,每一个endselect区间内都是一次循环查询,一次查n个出来清空内表后放进内表(如果用into)。
      • 此时要用endselect来结束语句。
  • 查个别字段用变量:

    • 查询数据库内个别数据库字段

    • into后面列出两个以上目标地时需要用括号分别指定变量名,如果空白,会报错

      SELECT ... INTO (f1,f2)...
      

      在select 语句里面查询两个字段的语句如下所示

      SELECT carrid connid INTO (gv_carrid,gv_connid) FROM SFLIGHT
      
      

3.3.3:FROM

用于指定数据库表或视图。

可用AS添加别名,动态指定数据库表名

两个作用:

  • 定义表的选项
  • 控制访问数据库表的选项
    • select … FROM TABLE option.
    • 请添加图片描述

表类型:

  1. 静态的表(固定表),可以使用AS设置别名,别名设置后,该语句内不能再用本来的名字。

  2. 动态表(用个变量存放表的名字),此时该变量内存放的表名字必须是大写字母,并且要在数据字典中存在。

    DATA tname type c.
    tname = 'MYTABLE'."MYTABLE 要大写,并且要在数据字典中存在该表"
    
    

3.3.4:JOIN

在关系型数据库内同时取得多个数据库表值时,用JOIN来连接。

TYPES: BEGIN OF t_str,
		carrid TYPE sflight-carrid,
        carrname TYPE scarr-carrname,
       END OF t_str.
DATA: gs str TYPE t_str.
SELECT SINGLE a~carrid b~carrname INTO CORRESPONDING FIELDS OF gs_str FROM sflight AS a INNER JOIN scarr AS b ON a~carrid EQ b carrid WHERE a~carrid ='AA'.
WRITE:gs str-carrid,gs_str-carrname.
内连接查询

​ 两张表交集的部分

​ 隐式内连接:
SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;

​ 显式内连接:
SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ...;

​ 显式性能比隐式高

外连接查询

​ 左外连接:
​ 查询左表所有数据,以及两张表交集部分数据
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ...;
​ 相当于查询表1的所有数据,包含表1和表2交集部分

ABAP OPEN SQL中只能用左外连接。

3.3.5:限制查询个数

select ... FROM 

4:内表

类似于C语言的动态数组

INITIAL SIZE 后没有直接占用内存,而是预约了内存空间。

4.1:表

DATA 表名 TYPE 表类型.
INITIAL SIZE 件数.

TYPES: BEGIN OF s_type,
	no(6) TYPE c,
	name(10) TYPE c,
	part(16) TYPE c,
END OF s_type.
TYPES t_type TYPE STANDARD TABLE OF s_type INITIAL SIZE 100.
DATA struct1 TYPE t_type.


struct1-name = 'wyx'."此时只是在为结构体赋值
APPEND struct1."append命令是追加的意思,在向内表插入值。

struct1-name = 'zcy'.
APPEND struct1.

4.1.1:内表的定义

主要有三种

  1. 参照结构体类型

  2. 参照已经有的结构体变量

    1. 只能用like table of 不能用type

    2. like line of与like table of和like

      1. like line of: 生成的是结构体

        LIKE LINE OF后面只能接一个内表,表示一个DATA参数具有和内表一样的结构(structure),例如有一个TABLES:Z_USER,Z_USER有两个字段,一个ID,一个NAME,那么

        DATA:WA LIKE LINE OF Z_USER 表示WA和Z_USER的STRUCTURE一样,可以吧WA当做Z_USER的WORK AREA来用。

      2. like table of: 生成的是内表

        LIKE TABLE OF 后面接一个STRUCTURE,表示一个DATA参数是一个内表,这个内表的结构和后面接的那个结构一样,例:

        DATA:BEGIN OF WA,
        
               ID TYPE I,
        
               NAME(10) TYPE C,
        
        END OF WA.
        
        DATA: ITAB LIKE TABLE OF WA.
        

        这里的ITAB直接就是一个内表了,WA是它的WORK AREA。

      3. like:

        可以跟内表,可以跟结构体,复制出来的就是后面的东西

  3. 参照数据库表

*内表定义 赋值 输出
TYPES: BEGIN OF s_type,
  no(6) TYPE c ,
  name(10) TYPE c,
  part(16) TYPE c,
END OF s_type.

DATA struct TYPE STANDARD TABLE OF s_type WITH NON-UNIQUE KEY NO WITH HEADER LINE.

struct-no = '001'.
struct-name = 'wyx'."此时只是在为结构体赋值
APPEND struct."append命令是追加的意思,在向内表插入值。

struct-no = '002'.
struct-name = 'yx'."此时只是在为结构体赋值
APPEND struct."append命令是追加的意思,在向内表插入值。


LOOP AT struct.
  WRITE :/ struct-no,struct-name.
ENDLOOP.

*内表定义 DATA LIKE table DATA
DATA: BEGIN OF s_data,
  no(6) TYPE c ,
  name(10) TYPE c,
  part(16) TYPE c,
END OF s_data.

DATA struct_2 LIKE STANDARD TABLE OF s_data WITH NON-UNIQUE KEY no WITH HEADER LINE.

*参照全局表定义内表

DATA struct_3 LIKE SORTED TABLE OF scarr WITH UNIQUE KEY carrid."按全局表来定义struct3

DATA struct_4 LIKE LINE OF struct_3."按struct3的类型来定义内表

SELECT * INTO TABLE struct_3 FROM scarr.

LOOP AT struct_3 INTO struct_4.
 WRITE :/ struct_4-carrid,struct_4-carrname.
ENDLOOP.
*LOOP AT struct_3. 没有表头 必须用工作区才能够进行操作
*  WRITE :/ struct_3-carrid,struct_3-carrname.
*ENDLOOP.


4.1.2:表头的操作

*表头 带表头的内表操作 实际上是表头工作区和表名相同 故省略了工作区 
TYPES: BEGIN OF t_str,
      col1 TYPE i,
      col2 TYPE i,
 END OF t_str.

DATA gt_itab TYPE TABLE OF t_str WITH HEADER LINE.

DO 3 TIMES.
  gt_itab-col1 = sy-index."DO循环的次数 sy-index
  gt_itab-col2 = sy-index ** 2."2次方
  APPEND gt_itab.
  ENDDO.

LOOP AT gt_itab.
  WRITE:/ gt_itab-col1,gt_itab-col2.
  ENDLOOP.

一般建议使用以下书写方式 就算有表头的内表 在操作时也写出与内表同名的工作区

DATA gt_itab TYPE TABLE OF t_str WITH HEADER LINE.

DO 3 TIMES.
  gt_itab-col1 = sy-index."DO循环的次数 sy-index
  gt_itab-col2 = sy-index ** 2."2次方
  APPEND gt_itab To gt_itab.
  ENDDO.

LOOP AT gt_itab into gt_itab.
  WRITE:/ gt_itab-col1,gt_itab-col2.
  ENDLOOP.

请添加图片描述

4.2:内表的类型

ABAP内边包含三种类型:标准表、排序表、散列表。

请添加图片描述

标准表:用key查询(On)
​ 标准表是一种索引表(Index Table),可以不指定Key(即没有主键)。或者指定不唯一的主键(NON-UNIQUE KEY),但不能指定唯一的主键(UNIQUE KEY)。
可以使用(INDEX)和主键(KEY)或者字段来查询标注表,但最常用的就是索引访问。
标准表的特点就是填充表的速度快。若需要经常使用索引访问表,就选择标准表,标注表也是最常用的内部表。

排序表:用key查询(Ologn)
​ 排序表也是一种索引表,其与标准表的区别是排序表是按主键自动进行排序的,而标准表只能采用SORT来进行排序。
必须指定KEY作为排序参考字段,主键(KEY)可以是唯一的或者是不唯一的。
排序表可以使用INDEX或者KEY来查询。
排序表已经按照KEY来排序,因此可以不用在排序,如果需要经常使用键来访问数据,或者希望数据能够自动排序,就用排序表。
排序表可以采用二分查找(BINARY SEARCH)方法。

散列表:用key查询(O1)
​ 与标准表和排序表不同,散列表不是一种索引表,散列表内部的标识记录的散列值是根据散列算法计算的出来的,散列表可以提供快速的插入和查找操作。
散列表必须指定KEY,并且是UNIQUE KEY,不可使用索引(INDEX)来查询,只能使用主键(KEY)查询。
查询散列表耗费的事件与表的记录数量无关,如果记录量非常大并且需要主键访问,就可以考虑使用散列表。

4.2.1:标准表 索引表

data a type standard table of b

TYPE STANDARD TABLE OF 
WITH DEFAULT KEY "即使不写这句 也默认存在 ,并且会将内表中以char类型定义的前几个字段定义成g"
  • 标准表关键字并非唯一的 ,可以有很多个;

    • 特别是设置了with default key 后,会把全部的c类型的字段全部设置为关键字
    • 如果没有设置任何的key,默认也是with default key 这个效果
  • 标准表只能设置key是 with non-unique key,也就是允许关键字非主键,可以有同列重复的字段在其中

  • 可以通过索引访问

    read table gt_itab index 2.
    

标准表定义与使用

*标准表
TYPES: BEGIN OF t_line,
  field1 TYPE c LENGTH 5,
  field2 TYPE c LENGTH 4,
  field3 TYPE i,
  END OF t_line.

TYPES t_standard TYPE STANDARD TABLE OF t_line.

DATA gt_itab2 TYPE t_standard WITH HEADER LINE.

gt_itab2-field1 = 'En'.
gt_itab2-field2 = 'ABAP'.
gt_itab2-field3 = 2.
APPEND gt_itab2.

gt_itab2-field1 = 'Enjoy'.
gt_itab2-field2 = 'ABAP'.
gt_itab2-field3 = 1.
APPEND gt_itab2.

4.2.2:排序表 索引表

*排序表
TYPES: BEGIN OF t_line2,
  seq TYPE c,"如果是default key 那么会根据第一个c类型来当主键
  col TYPE c,
  END OF t_line2.

TYPES t_tab TYPE SORTED TABLE OF t_line2 WITH UNIQUE/NON-UNIQUE DEFAULT KEY/ KEY col."必须指定是唯一的还是非唯一的,如果是非唯一的,就算key的字段有重复也可以进行insert插入.

DATA gt_itab3 TYPE t_tab WITH HEADER LINE.

gt_itab3-col = 'B'.
gt_itab3-seq = '1'.
INSERT TABLE gt_itab3.

gt_itab3-col = 'A'.
gt_itab3-seq = '2'.
INSERT TABLE gt_itab3.

gt_itab3-col = 'C'.
gt_itab3-seq = '1'.
INSERT TABLE gt_itab3.

CLEAR gt_itab3.
READ TABLE gt_itab3 INDEX 2.

WRITE:/ gt_itab3-col,gt_itab3-seq.
  • 排序表UNIQUE的时候,插入相同的插不进去,但不会报错
  • 用NON-UNIQUE的时候可以插进去
  • 排序表用append 进行追加的时候,如果追加顺序是相悖的就会造成排序问题从而报错

4.2.3:哈希表

*哈希表
**L.STRUCTURE Type定义
TYPES:BEGIN OF t_line3,
  col TYPE c,
  seq TYPE i,
END OF t_line3.
**2.定义标准表类型
TYPES t_tab3 TYPE HASHED TABLE OF t_line3 WITH UNIQUE KEY col.
**3.定义内表
DATA gt_itab4 TYPE t_tab3 WITH HEADER LINE.

gt_itab4-col ='B'.
gt_itab4-seq ='1'.
INSERT TABLE gt_itab4.

gt_itab4-col ='A'.
gt_itab4-seq ='2'.
INSERT TABLE gt_itab4.

CLEAR gt_itab4.
READ TABLE gt_itab4 WITH TABLE KEY col ='A'.
WRITE:/ gt_itab4-col,gt_itab4-seq.
  • 哈希内表不存在索引,不能用read table a index 1访问。
  • 只能用read table a with table key col 或者 read table a with key col的方式访问

4.2.4:READ 命令

*read.
READ TABLE gt_itab2 WITH KEY field3 = 2.
WRITE :/ gt_itab2-field1,gt_itab2-field2,gt_itab2-field3.

READ TABLE gt_itab2 INDEX 1.
WRITE :/ gt_itab2-field1,gt_itab2-field2,gt_itab2-field3.

READ TABLE gt_itab2 INDEX 2.
WRITE :/ gt_itab2-field1,gt_itab2-field2,gt_itab2-field3.
4.2.4.1:工作区

同名工作区会保存最近的一次改变的内容在其中

4.2.5:with table key 和with key

  • with table key 时候,要指定所有定义的关键字

    READ TABLE gt_itab2 with table key a = '1' b = '2' c = '3'.
    
  • with key时候,只用指定一个关键字

    READ TABLE gt_itab2 with  key a = '1'.
    

4.2.6:内表的旧式定义

旧方式定义的表只能是标准表,不能使用排序表或者哈希表
TYPES a TYPE/LIKE b OCCURS n. "n=0时,代表内存大小没有限制,其他数字没有意义。
等于
TYPES|DATA <itab> TYPE|LIKE STANDARD TABLE OF <linetype> WITH NON-UNIQUE DEFALUT KEY INITIAL KEY INITIAL SIZE <n> [WITH HEADER LINE].
TYPES: BEGIN OF t_line,
	col TYPE c,
	seq TYPE i,
	END OF t_line.

DATA gt_itab TYPE t_line OCCURS 0 WITH HEADER LINE.

gt_itab-col = 'A'.
gt_itab-seq = '1'.
INSERT table gt_itab.

CLEAR gt_itab.
READ TABLE gt_itab INDEX 1.
WRITE:/ gt_itab-col,gt_itab-seq.

4.3:比较内表的速度

插入:用标准表快 append

查找:用排序表、哈希表快 read 哈希最快

排序表默认是已经排序,并且默认read是用二分查找法查找,不能添加BINARY SEARCH命令。

标准表要想用二分查找,需要先用SORT排序,然后用BINARY SEARCH进行二分查找。

SORT itab BY col1 col2 col3.
READ TABLE itab WITH KEY col1 = 500 col2 = 200 col3 = 300 BINARY SEARCH.

4.4:内表命令

4.4.1:内表赋值

内表采用MOVE进行赋值。

MOVE itab1 TO itab2.     
"如果带表头的用该方法赋值时,只复制了itab1的表头中的数据给itab2 
"和itab2 = itab1一样

MOVE itab1[] TO itab2[].
"会复制表体数据给itab2 
"和itab2 = itab1一样

类型不同的时候,用下面这个,不管两个表的字段顺序咋样,只有有相同名字的字段就可以赋值

MOVE-CORRESPONDING itab1 TO itab2. "也是对结构体赋值的命令
  • itab1[]:代表表体
  • itab1:有表头时代表表头工作区;没有表头时代表整个内表

没有表头的内表,需要定义一个结构体作为工作区,使用 like line of 就可以定义出一个与内表结构一样的结构体

4.4.2:内表初始化

内表初始化:清空内容,保留结构

  • CLEAR:
    • clear itab:有表头时候,只初始化表头;没有表头,初始化全部
    • clear itab[]:可以清空表体,不清空表头
    • clear a:a是基本类型变量,可以清空内容,重置为默认值
  • REFRESH:仅仅清楚内标,专门清除内表的,不能清除基本变量
  • FREE:free itab 会直接释放itab所占据的内存空间

4.4.3:内表排序

SORT:

默认是用 ASCENDING 升序排列。

不能用于排序表,会发生错误。

只能用于标准表和哈希表。

sort itab ASCENDING|DESCENDING 

1:对没有指定关键字的标准表使用sort

将组合字符串类型的字段作为关键字进行排序,默认的排序方法为ASCENDING。

2:指定排序字段:

SORT itab [ASCENDING|DESCENDING] BY f1 [ASCENDING|DESCENDING] f2[ASCENDING|DESCENDING]

f1字段如果存在null值,会字段排除此列

3:stable sort

  • 排序算法是有稳定性存在的:稳定就是指相同数据排序时原始在前面的排序后仍然在前面。
  • 而sort是不稳定排序的,会造成排序的相对次序改变,在实际业务中会造成取值异常的问题。
  • 如果用stable sort就可以解决,会达到稳定的排序的目标,但是耗时会比sort更长。

4.4.4:内表属性

DESCRIBE TABLE itab [LINES gv_line][OCCURS gv_init][KIND gv_kind].

DESCRIBE语句确认内表属性

LINES:表示内表包含的数据件数,最常用。

OCCURS:返回内表的初始大小

KIND:返回内表的类型 【T标准表|S排序表|H哈希表】

4.4.5:追加内表数据

INSERT:

  • 利用关键字追加一条数据

    insert line into table itab
    

    执行成功后会让系统变量 SY-SUBRC返回0。

    如果内表存在唯一键,当执行insert时,若表中已经有了相同关键字的数据,系统变量SY-SUBRC会返回4,但是不报错

  • 利用关键字追加多条数据

    利用insert语句追加多条数据,但是itab1与itab2表类型要相同

    insert lines of itab1 [from n1][TO n2] into table itab2 "从itab1的n1行到n2行的数据全插入
    
    
  • 利用索引追加一/多条数据

    insert line into table itab2 [index i].
    insert lines OF itab1 INTO itab2 into [index i].
    
  • 不同类型内表 insert效果不一样

    • 标准表:
      • 追加到内表最后一行
      • 与append语句有相同的效果
    • 排序表
      • 按照内表排序号的顺序追加数据
      • 插入行不可以打乱按照关键字排序的顺序,否则插入不成功
      • 如果是NON-UNIQUE KEY 类型的,那么相同关键字的数据会插入已经有的上一行
    • 哈希表
      • 插入过程中系统按照关键字的哈希索引顺序进行追加,有可能插入到已有数据前

APPEND:

  • 只能用索引 哈希表不支持append

  • 追加一条数据

    append line TO itab.
    *追加成功后,系统变量SY-TABIX中保存追加数据的内表行,即索引编号。
    
  • 追加多条数据

    APPEND LINES OF itab1 [FROM n1] [TO n2] TO itab2.
    
  • 对于排序表,也必须按原定顺序插入,否则会发生错误

  • APPEND INITIAL LINE

    APPEND INITIAL LINE TO itab."创建一个空内表"
    
    
  • APPEND SORTED BY 自动以字段F为基准降序排序descending 后追加数据,仅仅适合标准表,另外还需要在创建内表变量的时候INITIAL SIZE 指定大小。

    由于会对表内数据进行排序,所以可能会因为initial size 的大小使得插入时截掉原有数据

    APPEND wa TO itab SORTED BY f
    

COLLECT:

collect在非数值字段相同的情况下,起到了数值字段汇总作用。

  • 非数值字段不同的情况下,效果和append相同执行插入内表操作
  • 当非数值字段相同的时候,则相当于modify的效果,只不过是将数值字段进行汇总相加后更新。汇总非数值字段,把相同非数值字段的数值加起来。
  • 操作时,内表除了关键字以外的必须是数字类型才可以正常操作。
COLLECT wa INTO itab.
TYPES:BEGIN OF TY_TEST,
ID(3) TYPE C,
MENGE TYPE I,
END OF TY_TEST.

DATA:I_TEST TYPE TABLE OF TY_TEST,
     W_TEST TYPE TY_TEST.
DATA:I_TEST2 TYPE TABLE OF TY_TEST.

W_TEST-ID = '001'.
W_TEST-MENGE = 10.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '001'.
W_TEST-MENGE = 70.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '002'.
W_TEST-MENGE = 20.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '002'.
W_TEST-MENGE = 50.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '002'.
W_TEST-MENGE = 80.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '003'.
W_TEST-MENGE = 30.
APPEND W_TEST TO I_TEST.

W_TEST-ID = '003'.
W_TEST-MENGE = 90.
APPEND W_TEST TO I_TEST.


LOOP AT I_TEST INTO W_TEST.
  COLLECT W_TEST INTO I_TEST2."关键一步。。。"
  CLEAR:W_TEST.
ENDLOOP.

WRITE:/ 'Collect前的内容:'  .
WRITE:/1(12) '编号' ,   '数量'.
LOOP AT I_TEST INTO W_TEST.
  WRITE:/ W_TEST-ID, ' ',W_TEST-MENGE.
  CLEAR:W_TEST.
ENDLOOP.


WRITE:/ .


WRITE:/ 'Collect后的结果:'  .
WRITE:/1(12) '编号' ,   '数量'.
LOOP AT I_TEST2 INTO W_TEST.
  WRITE:/ W_TEST-ID , ' ',W_TEST-MENGE.
  CLEAR:W_TEST.
ENDLOOP.

4.4.6:修改内表数据

MODIFY语句可以修改内表内的一条数据。

LOOP AT i_list.
 IF i_list-werks = '1000'.
 	i_list-matnr = '4001'.
 ENDIF.
MODIFY i_list.
CLEAR i_list.
ENDLOOP.
MODIFY itab2 FROM ls_itab1 INDEX 3 TRANSPORTING field2 WHERE field1 = 'a'.
"不循环的方式,操作工作区"
"INDEX 3 只修改表itab2的第3行"
"只修改field2的值,不修改field1"
"当field1=a时才执行操作"
*transporting 修改指定字段。
SELECT carrid connid INTO CORRESPONDING FIELDS OF TABLE gt_itab FROM sflight.
*CORRESPONDING FIELDS OF 匹配select 后面字段与into table后面的字段,名字不对应就没有值
*from 是指定从哪张数据库表中取数据

4.4.7:AT NEW & AT END OF & AT FIRST & AT LAST

  • AT NEW t:t以及t左边的列为一组,一旦与上一条比值发生改变发生改变,那么执行随后的语句。
  • AT END OF t:t以及t左边的列为一组,一旦与下一条比值发生改变,那么执行随后的语句。
at new col2.
	语句."以col1 和col2 两列为一组 如果与上一条数据比有变化,那么就执行"
endat.
  • AT FIRST.:一是内表第一条数据时执行。
  • AT LAST.:是内表的最后一条数据时执行。

4.4.8:删除内表数据

  • 利用表关键字删除一条数据

    在关键字不唯一的标准表中使用with table key

    delete table itab [from wa] with key k1=f1.
    delete table itab with table key k1=f1....
    
  • 利用where条件删除多条数据

    delete itab where cond.
    
  • 利用索引删除内表数据

    delete itab [index idx].
    delete itab from n1 to n2.
    delete itab form n1. "从n1开始到结束"
    delete itab to n2."从开始到n2"
    
  • 利用ADJACENT DUPLICATE

    需要先用sort 语句排序内表,才能有删除重复行的效果。

    delete adjacent duplicate entries from itab[comparing f1 f2....]."不使用comparing的话,默认是删除关键字重复的数据"
    

4.4.9:读取内表数据

  • 利用关键字读取数据

    READ TABLE <EMPTAB>.
    READ TABLE <EMPTAB> WITH KEY <k1> = <v1>… <kn> = <vn>.
    READ TABLE <EMPTAB> WITH TABLE KEY <k1> = <v1> … <kn> =<vn>.
    READ TABLE <EMPTAB> WITH KEY = <value>.
    READ TABLE <EMPTAB> WITH KEY . . . BINARY SEARCH.
    READ TABLE <EMPTAB> INDEX <i>.
    READ TABLE <EMPTAB> COMPARING <f1> <f2> . . . .
    READ TABLE <EMPTAB> COMPARING ALL FIELDS.
    READ TABLE <EMPTAB> TRANSPORTING <f1> <f2> . . . .
    READ TABLE <EMPTAB> TRANSPORTING NO FIELDS.
    
    KEY|TABLE KEY: 通过内表的主键字段查找
    BINARY SEARCH: 二分法查找,使用该方法时,在READ TABLE之前,必须对内表排序
    INDEX: 根据内表索引查找
    设置查找:
    COMPARING:只查找设置的字段
    COMPARING ALL FIELDS:查找内表所有的字段
    
    设置输出:
    TRANSPORTING: 只输出设置的字段数据
    TRANSPORTING NO FIELDS: 不输出任何数据
    
  • 利用索引读取数据

    READ TABLE itab INDEX idx INTO result.
    *成功SY-SUBRC 返回0 失败返回4
    *同时成功后 SY-TABIX保存内表的index序号
    

5:模块化程序

5.1:Form

子例程 FORM

使用 PERFORM frm_formname 调用

5.2:Function

函数事物代码: SE37

FUNCTION:
是具有全局可见性的特殊程序。
只能在fuction group中定义并使用。

FUNCTION GROUP:
包含一个以上的函数,是对某一类对象的操作。
专门用作function的主程序。
函数组 T-CODE: SE37

使用 CALL FUNCTION 'FUNCTION_NAME'来调用

5.3:USING 和 CHANGING

orm、Function中的TABLES参数,TYPE与LIKE后面只能接标准内表类型或标准内表对象,如果要使用排序内表或者哈希内表,则只能使用USING(Form)与CHANGING方式来代替。当把一个带表头的实参通过TABLES参数传递时,表头也会传递过去,如果实参不带表头或者只传递了表体(使用了[]时),系统会自动为内表参数变量创建一个局部空的表头

不管是以TABLES还是以USING(Form)非值、CHANGE非值方式传递时,都是以**引用方式(即别名,不是指地址,注意与Java中的传引用区别:Java实为传值,但传递的值为地址的值,而ABAP中传递的是否为地址,则要看实参是否是通过Type ref to定义的)**传递;

三种方式

1.引用传递(CALL BY REFERENCE)

传递参数时将参数的地址(ADDRESS)传至子程序中,也就是子程序中的参数变量与外部程序的参数变量共享地址内的值。又叫CALL BY ADDRESS,若子程序中的参数变量的值发生了改变,那么,外部程序的实际变量的值也发生改变。

FORM CALCULATOR USING NUM1 NUM2 CHANGING NUM3.在这里插入代码片
PERFORM CALCULATOR USING i_num1 i_num2 CHANGING i_num3.`在这里插入代码片`

此时PERFORM 后 在from内部修改NUM值会修改外部值 无论是USING 还是CHANGING的参数

2.值传递(CALL BY VALUE)

FORM <subform> [USING VALUE(f1) VALUE(f2)...]...在这里插入代码片
PERFORM <subform> [USING VALUE(f1) VALUE(f2)...]...

用USING VALUE(NUM)的方法可以只单向传值

3.值传递参数并返回最终值(CALL BY VALUE AND RETURN RESULT)

FORM <subform> [.....] [CHANGING VALUE(f1)...]
PERFORM <subform> [.....] [CHANGING VALUE(f1)...]

用CHANGING VALUE(NUM)的方法传递的虽然是值 但是在子程序结束的时候会返回值给外部变量 不同于地址传递的实时同步数据

5.3:USING 和 CHANGING

orm、Function中的TABLES参数,TYPE与LIKE后面只能接标准内表类型或标准内表对象,如果要使用排序内表或者哈希内表,则只能使用USING(Form)与CHANGING方式来代替。当把一个带表头的实参通过TABLES参数传递时,表头也会传递过去,如果实参不带表头或者只传递了表体(使用了[]时),系统会自动为内表参数变量创建一个局部空的表头

不管是以TABLES还是以USING(Form)非值、CHANGE非值方式传递时,都是以**引用方式(即别名,不是指地址,注意与Java中的传引用区别:Java实为传值,但传递的值为地址的值,而ABAP中传递的是否为地址,则要看实参是否是通过Type ref to定义的)**传递;

三种方式

1.引用传递(CALL BY REFERENCE)

传递参数时将参数的地址(ADDRESS)传至子程序中,也就是子程序中的参数变量与外部程序的参数变量共享地址内的值。又叫CALL BY ADDRESS,若子程序中的参数变量的值发生了改变,那么,外部程序的实际变量的值也发生改变。

FORM CALCULATOR USING NUM1 NUM2 CHANGING NUM3.
PERFORM CALCULATOR USING i_num1 i_num2 CHANGING i_num3.

此时PERFORM 后 在from内部修改NUM值会修改外部值 无论是USING 还是CHANGING的参数

2.值传递(CALL BY VALUE)

FORM <subform> [USING VALUE(f1) VALUE(f2)...]...
PERFORM <subform> [USING VALUE(f1) VALUE(f2)...]...

用USING VALUE(NUM)的方法可以只单向传值

3.值传递参数并返回最终值(CALL BY VALUE AND RETURN RESULT)

FORM <subform> [.....] [CHANGING VALUE(f1)...]
PERFORM <subform> [.....] [CHANGING VALUE(f1)...]

用CHANGING VALUE(NUM)的方法传递的虽然是值 但是在子程序结束的时候会返回值给外部变量 不同于地址传递的实时同步数据

6:字段符号FIELD-SYMBOLS

字段符号FIELD-SYMBOLS 可以看作仅是已经被解引用的指针 是变量的别名 并非真正的指针

在ABAP中引用变量(通过TYPE REF TO定义的变量)才好比C语言中的指针

ASSIGN … TO :将某个内存区域分配给字段符号,这样字段符号就代表了该内存区域,即该内存区域别名

FIELD-SYMBOLS: <FS>   [<TYPE>] 

当不输入时,继承赋给它的变量的所有属性
当输入时,赋给它的变量必须与同类型

FIELD-SYMBOLS:<F1>.
DATA: DAT(8) VALUE '19920108'.
ASSIGN DAT TO <F1>.
WRITE:/ <F1>.
"<f1> 继承dat属性,为C类型,值为19920108 。"

FIELD-SYMBOLS:<F2> TYPE D.
  DATA:DAT(5) TYPE C VALUE '12345'.
  ASSIGN DAT TO <F2>. "会直接报错 类型不兼容"
  WRITE:/ <F2>.
  
FIELD-SYMBOLS:<F3> TYPE D.
 DATA:DAT(8) VALUE '19920108'.
ASSIGN DAT TO <F3> TYPE 'D'. "会把DAT 先转换成D类型 再分配给<F3>"
WRITE:/ <F3>.

6.1:ASSIGN

6.1.1:隐式转换

Catsing分为隐式型变化和显示型变化两种

ASSSIGN <var> TO <fs> CASTING.

TYPES: BEGIN OF t_line,
         col1 TYPE char5,
         col2 TYPE char10,
         col3 TYPE char15,
        END OF t_line.
DATA: gv_addr(30) TYPE c VALUE 'CHINA BEIJING TWIN BUILDING'.

FIELD-SYMBOLS: <fs> TYPE t_line.
ASSIGN gv_addr TO <fs> CASTING.
WRITE: <fs>-col1, <fs>-col2, <fs>-col3.
"运行结果 CHINA  BEIJING TWIN BUILDING

在这个例子中,若不使用Casting,则会产生数据类型不一致的错误,因为是结构类型,gv_addr是字符类型。

6.1.2:显式转换

FIELD SYMBOLS 定义为Generic Type(不指定类型)

FIELD-SYMBOLS: <fs> TYPE ANY. "由于定义时未指定具体的类型"
ASSIGN gv_addr TO <fs> CASTING TYPE t_line.
WRITE: <fs>. 
"运行结果 CHINA  BEIJING TWIN BUILDING
6.1.3:ASSIGN动态分配
FIELD-SYMBOLS:<fs>.
DATA:str(20) TYPE c VALUE 'Output String',
     name(20) TYPE c VALUE 'STR'. "str刚好已经定义过"
     
"静态分配:编译时就知道要分配的对象名
ASSIGN name TO <fs>."结果是<fs>与name变量等同
ASSIGN (name) TO <fs>."动态分配 先找到name的值 name的值如果刚好是已经定义过的变量 那么就将那个已经定义的变量分配给<fs> 
FIELD-SYMBOLS:<fs>.

DATA:str(20) TYPE c VALUE 'Output String',
     name(20) TYPE c VALUE 'ST',
     ST(20) TYPE c VALUE 'Input String'.

"静态分配:编译时就知道要分配的对象名
ASSIGN name TO <fs>."结果是<fs>与name变量等同

WRITE:/ <fs>.

"通过变量名动态访问变量
DO 3 TIMES.
  ASSIGN (name) TO <fs>."结果是是<fs>的值为ST变量值

  WRITE:/ <fs>.
ENDDO.

6.2:UNASSIGN、CLEAR

UNASSIGN:该语句是初始化字段符号,执行后字段符号将不再引用内存区域, is assigned返回假

CLEAR:与UNASSIGN不同的是,只有一个作用就是初始化它所指向的内存区域,而不是解除分配

7:数据引用

TYPE REF TO data 数据引用data references

TYPE REF TO object 对象引用object references “object不能直接跟在TYPE后面,只能跟在TYPE REF TO后面

TYPE REF TO 后面可接的通用类型只能data(数据引用)或者是object(对象引用)通用类型,其他通用类型不行

TYPES: BEGIN OF t_struct,
         col1 TYPE i,
         col2 TYPE i,
       END OF t_struct. "定义一个结构体类型作为参考"
DATA: LS_STRUCT TYPE T_STRUCT. "定义一个结构体变量做参考"
       
DATA: dref TYPE REF TO DATA .   "dref即为数据引用,即数据指针,指向某个变量或常量,存储变量地址     用DATA 作为参考就是暂时不指定类型
DATA: ref TYPE REF TO t_struct ."ref以结构体作为参考
FILED-SYMBOLS <FS> TYPE ANY.    "参考任意类型"
FILED-SYMBOLS <FS> TYPE t_struct . 

7.1.数据引用 Data References

  • Type Ref To 有两种初始化的方法: 必须初始化

    ​ 1:第一种是用 CREATE DATA 动态开辟内存; (类似C语言定义指针会默认分配一个空间也可以用malloc分配一块空间给指针[指针值就是这块空间的首地址] abap指针必须要手动’malloc’ 一下内存空间)

      如果定义 ref 是指定特定的类型或者结构的,那么 CREATE DATA 时 TYPE 可以省略。
    

    ​ 无论定义时 ref 是否有特定的类型或者结构,CREATE DATA 时必须指定特定的类型或者结构,不能是data这种泛型的。

    一般来说为了使用方便,还是应该指定 Field Symbol 或者 Type Ref To 的类型或者结构,以便之后直接使用。

    CREATE DATA dref TYPE C.  "dref由于没有定义类型 所以初始化时必须指定类型 此时的类型可以是随便什么的 没有限制
    CREATE DATA ref .         "ref在定义时就指定了类型 初始化时无需再次指定类型"
    

    ​ 2:第二种是用 GET REFERENCE OF 指向已经存在的内存变量.

    GETREFERENCE OF LS_STRUCT INTO ref. "效果相当于ref指向变量LS_STRUCT
    
  • Field Symbol 的初始化,则只能指向已经存在的内存变量

    FS是已经解引用的指针(类似C语言有指针p,FS就是*p,其本质已经是变量不是地址,而上述TYPE REF TO 得来的引用本质是地址)

    ASSIGN LS_STRUCT TO <FS>         "初始化FS 必须是已有的变量 而不是类型"
    
  • 两者区别

    Type Ref To 和 Field Symbol 在用法上目前发现的主要区别:

    ​ 1) Type Ref To 可以动态开辟内存,在动态内表时,可以等在程序运行时获得结构后再开辟内存,并且赋值给某个 Field Symbol。而光用 Field Symbol 是做不到的,因为 Field Symbol 的初始化需要“挂”在已知结构上。

    ​ 2)Type Ref To 不像 Field Symbol 那样有LOOP AT it_tab ASSIGNING < fs >的写法,ref->不是指向内表数据,而是类似工作区指向某块内存,所以更改数据后需要 modify 到内表,如果不需要数据了要clear*。而 Field Symbol 则不需要考虑 modify 和 clear。

    ​ 3)IF = 是比较内存里的值,相对应的是IF ref1-> = ref2->**,而不能判断比较 IF ref1 = ref2 。

  • 使用数据引用 包含二级指针使用

    DATA: ref1 TYPE REF TO t_struct . "定义指针 指定类型"
    DATA: ref2 LIKE REF TO ref1.      "二级指针
    CREATE DATA ref1 .                "初始化 分配新的内存空间"
    CREATE DATA ref2 .
    ref1       "指针 类似指针p"
    ref2       "指针的指针 类似q 本质是&p"
    ref1->*    "解引用 一级指针的使用 类似*p"
    ref2->*    "解引用 二级指针的使用 类似*q 本质是p"
    ref2->*->* "解引用 二级指针的使用 类似**q 本质是*p"
    

如果定义时指定了特定的类型或者结构,那么 Field Symbol 和 Type Ref To 都可以直接使用

如果定义时没有指定类型或者结构,那么 Type Ref To 必须 ASSIGN 到另外一个 Field Symbol 里间接使用

TYPES: BEGIN OF t_struct,
         col1(6) TYPE C,
       END OF t_struct.


DATA: dref TYPE REF TO DATA ."dref即为数据引用,即数据指针,指向某个变量或常量,存储变量地址
DATA: ref TYPE REF TO t_struct .     "定义一个p指针"

CREATE DATA dref TYPE C LENGTH 6.        "使用前必须先指定类型"
FIELD-SYMBOLS <FS> TYPE any.             "泛用型类型
ASSIGN dref->* TO <FS>.      
<FS> = 'abc'.

CREATE DATA ref .             "无需再次指定类型   初始化p指针内存空间"
ref->*-col1 = 'abcd'.         "类似 *p-col1 = xx"          

WRITE:/ <FS>,
        ref->*.
  • 25
    点赞
  • 158
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
ABAP(Advanced Business Application Programming)是一种在SAP系统中使用的编程语言,用于开发企业级应用程序。而ABAP Eclipse是一个在Eclipse集成开发环境(IDE)中专门用于ABAP开发的插件。 ABAP Eclipse提供了多种功能和工具,使开发人员能够更高效地编写和调试ABAP程序。首先,它通过代码自动完成和建议功能,提供了更快速的编码体验。开发人员可以通过输入几个字符即可自动补全代码段,减少了手动输入代码的时间和努力。 其次,ABAP Eclipse还提供了强大的调试功能,使开发人员能够更快地找到和解决程序中的问题。调试器允许开发人员逐行执行代码,并查看变量的值和程序的执行路径。这样,开发人员可以更好地理解程序的执行过程,并找到其中的错误或潜在问题。 此外,ABAP Eclipse还具有版本管理和团队合作的功能。开发人员可以将代码上传到版本控制系统,并与其他团队成员合作开发同一个项目。通过协同工作的功能,不同开发人员可以同时编辑同一个代码文件,避免了代码冲突和重复的工作。 总而言之,ABAP Eclipse是一个强大而实用的工具,为ABAP开发人员提供了更高效、准确和愉快的开发环境。它提供了丰富的功能和工具,使开发人员能够更好地编写、调试和管理ABAP程序。无论是初学者还是有经验的开发人员,都可以受益于ABAP Eclipse的使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值