一、ABAP与SQL
ABAP编程环境中,SQL被广泛应用,特别是在需要对数据库进行查询、插入、更新或删除操作时,ABAP SQL Functions允许开发者在对数据库进行查询时使用SQL语言内置的函数,从而实现更加复杂和高效的数据处理。在ABAP中使用SQL时对于结构体和内表也有大量使用,可以先进行了解。下面就通过具体例子来演示ABAP中对SQL的使用。
由于博主也是初学者,有些不完善的地方后续会进行补充,不正确的地方还请留言。
二、例子中涉及到的表结构
若不知道怎么创建表,可以参考博文数据库表、数据元素、域创建。
1、学生表ZVIA_STU
2、学校表ZVIA_SCH
3、考勤表ZVIA_CHE
三、查询数据-SELECT
1、基础语句
若只有一条数据INTO结构体就行,但是若有多条数据则INTO TABLE 内表,条件之间以OR/AND进行连接。
SELECT 字段名1 (字段名2 字段名3...)
FROM 表名
INTO (TABLE) 内表名/结构体
WHERE 条件1 (OR/AND 条件2 OR/AND 条件三...).
举例,在学生表中找到gender = 'F' 的学生。很简单的查询语句,不做过多解释。
DATA : lt_stu TYPE TABLE OF zvia_stu."用表来定义结构
SELECT * FROM zvia_stu INTO TABLE lt_stu WHERE gender = 'F'."查询
cl_demo_output=>display( lt_stu )."输出内表
这里的 cl_demo_output=>display( 表名 ).用来输出,括号之中的表名前后需要留有空格,可以去了解其用法。 结果输出显示:
2、连表查询
与其他SQL一样,ABAP中的SQL也有内连接、外连接(左连接、右连接),下面通过几个例子来进行介绍。基础语法和演示用的表数据如下。也可以用 表名 AS 别名 的方式简化书写,可以自行尝试。
1)如果SELECT语句里面出现的字段在多个表中存在,则需要用表名~字段名的写法来指定是哪张表里面的字段,后续的代码中有演示。
2)每JOIN一张表后面都需要有ON条件,ON条件里面的字段也需要用表名1~字段名1=表名2~字段名2的写法来表示。
SELECT 字段名1 (字段名2 字段名3...)
FROM 表名1 JOIN 表名2 ON 连接字段条件
表名x JOIN 表名y ON 连接字段条件
........
INTO (TABLE) 内表名/结构体
WHERE 条件1 (OR/AND 条件2 OR/AND 条件三...).
标红的数据在另一张表中没有匹配的数据。
a、内连接INNER JOIN
内连接只有当两个或多个表中的某一列或某些列的值相等时,相应的行才会出现在结果集中。不满足的不会出现在结果中。
在ABAP中,当使用Open SQL语句时,如果要在SQL语句中引用程序声明(非数据库层级)的变量,比如本地变量、工作区变量或内表等,这些变量名前需要加上@
符号作为转义符。
*定义一个类型*
TYPES : BEGIN OF ty_stu,
stuid TYPE zde_via_stuid, "用数据元素来定义类型
stuname TYPE zde_via_stuname,
schid TYPE zde_via_schid,
schname TYPE zde_via_schname,
gender TYPE zde_via_gender,
END OF ty_stu.
DATA : lt_stu TYPE TABLE OF ty_stu."定义用来存储数据的内表
SELECT stuid,stuname,zvia_stu~schid,schname,gender
FROM zvia_stu INNER JOIN zvia_sch"内连接
ON zvia_stu~schid = zvia_sch~schid"JOIN的条件
INTO TABLE @lt_stu.
cl_demo_output=>display( lt_stu )."输出显示
这段代码运行结果如下,可以看到SCHID为0003的大学没有显示,SCHID为0000的两个学生也没有出现在查询结果中。因为它们的匹配条件SCHID相等在对方表中没有匹配的项所以不会出现在结果中。
b、左连接LEFT (OUTER) JOIN
左连接会返回左表中的所有记录,以及右表中满足连接条件的记录。如果右表中没有满足连接条件的记录,则结果集中的这些记录对应的右表字段将包含NULL值。
同样的两个表,只修改连接方式为左连接,查看结果。
SELECT stuid,stuname,zvia_stu~schid,schname,gender
FROM zvia_stu LEFT JOIN zvia_sch"左连接
ON zvia_stu~schid = zvia_sch~schid
INTO TABLE @lt_stu.
运行结果如下,可以看到左连接时候,左表虽然SCHID在右表中没有对应数据,但是会显示出来NULL,保留在查询结果里。
c、右连接RIGHT (OUTER) JOIN (不常用,这种情况下一般主表会放在左边用左连接)
右连接会返回右表中的所有记录,以及左表中满足连接条件的记录。如果左表中没有满足连接条件的记录,则结果集中的这些记录对应的左表字段将包含NULL值。
同样的两个表,只修改连接方式为右连接,查看结果。
*这里为了查看结果,搜索的SCHID改成了学校表中的*
SELECT stuid,stuname,zvia_sch~schid,schname,gender
FROM zvia_stu RIGHT JOIN zvia_sch"右连接
ON zvia_stu~schid = zvia_sch~schid
INTO TABLE @lt_stu.
运行结果如下,可以看到右连接时候,虽然左表里面没有学生的SCHID为0003,但是还是会在查询结果里面将右表里面的0003进行保留。
d、总结
1)内连接:根据条件进行匹配,两张表中都有的才加入查询结果。
2)左连接:根据条件进行匹配,如果有左表里面存在但在右表里没有匹配的数据也会进行保留。
3)右连接:根据条件进行匹配,如果有右表里面存在但在左表里没有匹配的数据也会进行保留。
四、插入数据-INSERT
1、插入一条数据
a、直接插入
INSERT INTO 表名 VALUES @( VALUE #( 字段名1 = 值1 字段名2 = 值2 字段名3 = 值3 字段名4 = 值4) ).
例子:
INSERT INTO zvia_stu VALUES @( VALUE #( stuid = 17 stuname = 'KJ' schid = 1 gender = 'M') ).
*判断插入数据结果*
IF sy-subrc <> 0.
WRITE: / '插入失败.'.
ELSE.
WRITE: / '插入成功.'.
ENDIF.
运行结果 :
b、通过结构体进行插入
INSERT 表名 FROM 结构体.
*定义结构体类型*
TYPES : BEGIN OF ty_stu,
mandt TYPE mandt,"结构体类型定义时需要加上
stuid TYPE zde_via_stuid, "用数据元素来定义类型
stuname TYPE zde_via_stuname,
schid TYPE zde_via_schid,
gender TYPE zde_via_gender,
END OF ty_stu.
DATA : ls_stu TYPE ty_stu.
*给结构体字段赋值*
ls_stu-stuid = 18.
ls_stu-stuname = 'LINDA'.
ls_stu-schid = 2.
ls_stu-gender = 'F'.
*插入数据*
INSERT zvia_stu FROM ls_stu.
*插入结果判断*
IF sy-subrc <> 0.
WRITE: / '插入失败.'.
ELSE.
WRITE: / '插入成功.'.
ENDIF.
2、插入多条数据
插入多条数据的时候可以通过内表进行。
INSERT 表名 FROM TABLE 内表名.
TYPES : BEGIN OF ty_stu,
mandt TYPE mandt, "结构体类型定义时需要加上
stuid TYPE zde_via_stuid, "用数据元素来定义类型
stuname TYPE zde_via_stuname,
schid TYPE zde_via_schid,
gender TYPE zde_via_gender,
END OF ty_stu.
DATA : ls_stu TYPE ty_stu,
lt_stu TYPE TABLE OF ty_stu.
ls_stu-stuid = 19.
ls_stu-stuname = 'MIAO'.
ls_stu-schid = 4.
ls_stu-gender = 'F'.
APPEND ls_stu to lt_stu."数据添加至内表
ls_stu-stuid = 20.
ls_stu-stuname = 'WANG'.
ls_stu-schid = 2.
ls_stu-gender = 'M'.
APPEND ls_stu to lt_stu."数据添加至内表
*通过内表插入多条数据*
INSERT zvia_stu FROM TABLE lt_stu.
*插入结果判断*
IF sy-subrc <> 0.
WRITE: / '插入失败.'.
ELSE.
WRITE: / '插入成功.'.
ENDIF.
五、更新数据-UPDATE/MODIFY
1、总的过程
a、UPDATE:
判断是否存在数据->修改结构体中的数据->依据结构体来UPDATE表
UPDATE 表名 SET 字段名1=值1 字段名2=值2 .... (WHERE 条件).
b、MODIFY:不用进行判断,反正有则改没有则加。
2、更新的是主键的时候。在UPDATE的WHERE条件里面需要加上主键字段名 = 之前主键值的条件判断,否则会找不到数据,因为UPDATE是依据主键来查找数据修改的。
TYPES : BEGIN OF ty_stu,
mandt TYPE mandt, "结构体类型定义时需要加上
stuid TYPE zde_via_stuid, "用数据元素来定义类型
stuname TYPE zde_via_stuname,
schid TYPE zde_via_schid,
gender TYPE zde_via_gender,
END OF ty_stu.
*修改主键*
DATA : ls_stu TYPE ty_stu.
SELECT SINGLE *
FROM zvia_stu
INTO ls_stu
WHERE stuid = '0001'.
WRITE : / '修改前数据:',ls_stu.
IF sy-subrc <> 0."判断是否存在该数据
WRITE : / '不存在该数据'.
ELSE.
UPDATE zvia_stu
SET stuid = '0099'
********主键条件判断********
WHERE stuid = '0001'.
***************************
IF sy-subrc = 0."判断UPDATE的结果
WRITE : / '更新成功'.
else.
WRITE : / '更新失败'.
ENDIF.
SELECT SINGLE * from zvia_stu INTO ls_stu WHERE stuid = '0099'.
WRITE : / '修改后数据:',ls_stu.
ENDIF.
3、更新的数据非主键。如果更新的数据不是主键,不一定需要加上主键 = 之前主键值的条件。但是请一定注意条件判断,否则将会修改很多数据!
下面的代码将姓名为JASMINE的学生姓名改成了LEO。
TYPES : BEGIN OF ty_stu,
stuid TYPE zde_via_stuid, "用数据元素来定义类型
stuname TYPE zde_via_stuname,
schid TYPE zde_via_schid,
gender TYPE zde_via_gender,
END OF ty_stu.
*修改的是非主键的时候*
DATA : ls_stu TYPE ty_stu.
SELECT SINGLE *
FROM zvia_stu
INTO ls_stu
WHERE stuname = 'JASMINE'.
WRITE : / '修改前数据:',ls_stu.
IF sy-subrc <> 0.
WRITE : / '不存在该数据'.
ELSE.
UPDATE zvia_stu
SET stuname = 'LEO'
WHERE stuname = 'JASMINE'.
IF sy-subrc = 0.
WRITE : / '更新成功'.
else.
WRITE : / '更新失败'.
ENDIF.
SELECT SINGLE * from zvia_stu INTO ls_stu WHERE stuname = 'LEO'.
WRITE : / '修改后数据:',ls_stu.
ENDIF.
运行结果:
4、MODIFY。与内表中的MODIFY一样,数据库语句里面的MODIFY也有有则改,没有则加的特性。
MODIFY 表名 FROM 结构体.
六、删除数据
1、通过结构体进行删除。结构体定义里面必须包含有主键,才能够找到对应数据。
DELETE 表名 FROM 结构体名.
ls_stu-stuid = '0001'."主键
ls_stu-stuname = 'BETTY'.
ls_stu-schid = '0001'.
ls_stu-gender = 'F'.
*若使用结构体:ls_stu所定义的字段包含有主键,则可以删除,不然不可以删除,不知道删哪一个*
DELETE zvia_stu FROM ls_stu.
IF sy-subrc = 0 .
WRITE : / '删除成功'.
ELSE.
WRITE : / '删除失败'.
ENDIF.
2、通过WHERE条件删除,会删除所有符合条件的行。所以删除一条数据的时候最好选择主键作为条件进行删除。
DELETE FROM 表名 WHERE 条件1 AND/OR 条件2 ...
DELETE FROM zvia_stu WHERE schid = '0003'."主键
IF sy-subrc = 0 .
WRITE : / '删除成功'.
ELSE.
WRITE : / '删除失败'.
ENDIF.