ABAP 开发系列(08): SAP Open SQL在前面我们介绍 ABAP WorkBench时了解到 SAP 的三层架构: – 表现层(Presentation),应用层(Application),数据层(Database) SAP Application将发送的 Open SQL请求,与Database进行匹配,转换成接受的SQL语句, DB再执行SQL,将结果返回给Application。 在 ABAP程序中有两种方式访问数据库: Open SQL 和 Native SQL1.1 Open SQL 是完全集成到 ABAP语言中的Standard SQL的子集。它通过数据库接口将 Open SQL 转换成 Standard SQL, 所以它可以用相同的方式访问不同的数据库系统,然后由该接口把 SAP的Open SQL自动转换为相应数据库的特定SQL语句。 Open SQL 包含Standard SQL的数据操作语言Data Manipulation Language (DML)部分,允许你读取和修改数据。 Data Definition Language (DDL) 和 Data Control Language (DCL) 部分使用ABAP Dictionary处理。
1.2 Native SQL 语法不会使用数据库接口进行转换,它直接访问数据库,所以一个SQL只能访问一个指定数据库, 且具有一定的安全风险,对SAP执行效率也会有较大影响,所以一般不推荐使用。
2. Open SQL 语句 Open SQL包含的DML語法有4种:SELECT, INSERT, UPDATE, DELETE, MODIFY SELECT: 查询语法 INSERT: 插入数据语法 UPDATE: 更新数据语法 DELETE: 删除数据语法 MODIFY: 修改数据语法,相当于 INSERT 和 UPDATE 修改数据前会先在数据库查询是否存在该记录,如果存在则修改,不存在则插入新的数据 Open SQL执行成功后,会返回代码 SY-SUBRC = 0, 如果失败 SY-SUBRC <> 0 除 SELECT 以外的命令,其他都会涉及到数据的修改,要谨慎使用。 在系统标准表中,我们只允许用 SELECT 命令去查询数据,其他命令语句只能用于自建表, 如若要修改系统标准表,只能通过系统标准程序去操作。
3. SELECT SELECT 命令包含如下从句: SELECT: 需要查询资料库指定表的那些列,是一行还是多行 INTO: 查询的结果保存在哪里 FROM: 从哪些表查询数 WHERE: 指定查询条件 GROUP BY: 以哪些栏位进行分組 ORDER BY: 以哪些栏位进行排序.
3.1 SELECT SINGLE 命令 SELECT SINGLE 命令允许你查询一条记录 ,为了确保你查询的记录是唯一的,你必须在你的 WHERE 子句指定所有KEY值, 如若查询的记录不止一条,系统会返回代码 SY-SUBRC = 8,查询结果为空; SELECT SINGLE <F1> <F2> FROM <dbtab> INTO <work area> INTO (<f1>, <f2>, <f3> … ) INTO CORRESPONDING FIELDS OF <work area> WHERE <Key1> <op> AND <Key2> <op> …
在INTO中使用 CORRESPONDING FIELDS OF,系统只填充与你的Work Area相同名称的栏位值; 执行成功返回代码 SY-SUBRC = 0,如果失敗SY-SUBRC <> 0。 示例: [size=1em][size=1em]1
[size=1em]2
[size=1em]3
[size=1em]4
[size=1em]5
[size=1em]6
[size=1em]7
[size=1em]8
| [size=1em][size=1em]DATA wa_spfli LIKE spfli.
[size=1em]SELECT SINGLE
[size=1em] carrid connid airpfrom airpto
[size=1em] FROM apfli
[size=1em] INTO CORRESPONDING FIELDS OF wa_spfli
[size=1em] WHERE carrid = 'LH'
[size=1em] AND connid = '400'.
|
3.2 SELECT 查询多条记录 SELECT 查询多条记录有两种方式: 1.使用SELECT … ENDSELECT命令,进行循环处理; 2.一次性读取多笔记录到内表中,在 INTO 使用TABLE附加字
第一种方式语法格式: SELECT <F1> … <Fn> FROM <dbtab> INTO <work area> INTO (<f1>, <f2>, <f3> … ) INTO CORRESPONDING FIELDS OF <work area> WHERE <tabfield> <operator> <value>. ENDSELECT.
第二种方式语法格式: SELECT <f1> … <fn> FROM <dbtab> INTO TABLE <itab> WHERE …
示例: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
[size=1em]12
[size=1em]13
[size=1em]14
[size=1em]15
| [size=1em][size=1em]DATA tab_spfli TYPE STANDARD TABLE OF spfli.
[size=1em]DATA wa_spfli LIKE spfli.
[size=1em]SELECT carrid connid airpfrom airpto
[size=1em] FROM apfli
[size=1em] INTO wa_spfli
[size=1em] WHERE carrid = 'LH'
[size=1em] AND connid = '400'.
[size=1em]ENDSELECT.
[size=1em]SELECT carrid connid airpfrom airpto
[size=1em] FROM apfli
[size=1em] INTO CORRESPONDING TABLE OF tab_spfli
[size=1em] WHERE carrid = 'LH'
[size=1em] AND connid = '400'.
|
注意:使用 SELECT… ENDSELECT 语法中不能加入 SINGLE、INTO CORRESPONDING FIELDS 、TABLE等关键字, 中间可以使用 CHECK 语法来判断查询值。
3.3 SELECT 附加选项 SINGLE [FOR UPDATE]: 使用它会产生一个排他锁,其他程序不能查询此笔记录。
示例: [size=1em][size=1em]1
[size=1em]2
[size=1em]3
[size=1em]4
[size=1em]5
[size=1em]6
| [size=1em][size=1em]* 星号表示查询所有栏位
[size=1em]SELECT SINGLE FOR UPDATE *
[size=1em] FROM SCARR
[size=1em] WHERE currcode = 'USD'.
[size=1em]WRITE : / scarr-CARRID.
|
DISTINCT:查询非重复记录,需要使用ORDER BY排序
在使用 SELECT 语句时,可以直接使用Open SQL提供的标准 函数进行相关操作,常用的标准 函数有以下几种: 1.COUNT(): 统计查询记录总数 2.SUM(): 汇总某查询数字字段数量 3.AVG():计算某查询数字字段平均值 4.MAX():查询表中记录最大值 5.MIN():查询表中记录最小值 使用这些函数时,如果要包含其他栏位,必须使用GROUP BY命令
3.5 FROM 子句 1. FROM dbtab [AS alias] - AS 附加字,用于对 Table另起别名 2. JOIN 联合查询 JOIN的联合查询有两种, INNER JOIN 和 LEFT/RIGHT [OUTER] JOIN 通过ON 语句关联2个或2个以上的表,且必须至少指定一个连接条件;在多个连接条件时,可以使用AND; ON左右的条件只能使用 = (EQ) 进行连接。 示例: [size=1em][size=1em]1
[size=1em]2
[size=1em]3
| [size=1em][size=1em]SELECT SINGLE B~BUKRS
[size=1em] FROM BSEG AS B
[size=1em] INNER JOIN T001 AS T ON B~BUKRS = T~BUKRS.
|
其中,INNER JOIN 与 LEFT/RIGHT JOIN 的区别: INNER JOIN的 ON 条件下,两个表数据必须完全匹配; LEFT JOIN 的 ON 条件下,左边的表需满足,右边的表不用完全匹配。 3. BYPASSING BUFFER - 绕过 Application Buffer,直接读取数据库。 4. UP TO n ROWS - 查询n 笔记录,限制读取数据的条数,即只读取查询数据的前5条记录。
3.6 WHERE 子句 WHERE 关键字后,可带子句包括: 1. <field> OP g OP包括:=, EQ, <>, NE, <, LT, >, GT, <, LE, >=, GE, <=, LE等关系操作符 2. <field> [NOT] BETWEEN g1 AND g2 : 包含 g1 和 g2
示例: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
| [size=1em][size=1em]* Between 的演示
[size=1em]SELECT carrid
[size=1em] INTO TABLE itab
[size=1em] FROM scarr
[size=1em] WHERE carrid BETWEEN 'AA' AND 'AZ'.
[size=1em]LOOP AT ITAB.
[size=1em] WRITE : / ITAB-CARRID.
[size=1em]ENDLOOP.
|
3. <field> [NOT] LIKE g :通过通配符(‘_’, ’%’)模糊查询
示例: [size=1em][size=1em]1
[size=1em]2
[size=1em]3
[size=1em]4
[size=1em]5
[size=1em]6
[size=1em]7
[size=1em]8
| [size=1em][size=1em]SELECT *
[size=1em] FROM mara
[size=1em] WHERE matnr LIKE ‘101-%’.
[size=1em]* WHERE matnr LIKE ‘101-___’.
[size=1em]WRITE : / mara-matnr.
[size=1em]ENDSELECT.
|
这里强烈建议,尽量避免使用LIKE语法作为条件筛选,因为模糊查询的数据量多数时候会非常庞大; 这样会直接消耗系统资源,影响系统性能。
4. <field> [NOT] IN ( g1, …, gn ) : 多个组合作为筛选条件 5. <field> [NOT] IN itab : 使用Range table作为筛选条件 6. <field> IS [NOT] NULL :筛选某字段是否为空
相当于使用 INNER JOIN 连接两个表一样,然后在数据量庞大的时候, FOR ALL ENTRIESIN 语句会比 INNER JOIN的查询快捷。 两者各有优缺点,视具体情况而定。
示例: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
[size=1em]12
[size=1em]13
[size=1em]14
[size=1em]15
[size=1em]16
[size=1em]17
[size=1em]18
[size=1em]19
[size=1em]20
| [size=1em][size=1em]* INNER JOIN 用法:
[size=1em]SELECT DISTINCT knb1~bukrs t001~butxt
[size=1em] FROM knb1 INNER JOIN t001
[size=1em] ON knb1~bukrs = t001~bukrs
[size=1em] INTO CORRESPONDING FIELDS OF TABLE tb_bukrs
[size=1em] WHERE kunnr IN rn_kunnr.
[size=1em]* FOR ALL ENTRIES IN用法:
[size=1em]SELECT DISTINCT bukrs
[size=1em] INTO CORRESPONDING FIELDS OF TABLE gt_knb1
[size=1em] FROM knb1.
[size=1em]
[size=1em]IF gt_knb1[] IS NOT INITIAL.
[size=1em] SELECT DISTINCT butxt FROM t001
[size=1em] INTO CORRESPONDING FIELDS OF TABLE gt_too1
[size=1em] FOR ALL ENTRIES IN gt_knb1
[size=1em] WHERE bukrs = gt_knb1-bukrs.
[size=1em]END IF.
|
注意事项: 1.使用该语句,对于最后得到的结果集,系统会自动删除重复行。 因此如果你要保留重复行记录时,记得在 SELECT 语句中添加足够键值项目(有必要时,增加全部键值项目), 以保证结果集中所需重复项目不会被删除。 (例如选取支付金额时,支付事件可能不同,但金额可能相同,此时一定要注意,以避免错误删除结果记录。) 因此为避免无意义的检索,在使用该语句前一定要判断内部表 itab 是否为空,为空时不执行包含该语句的数据库检索处理。 3.由于 itab-f 实际上是作为占位符被替换,所以内部表 itab 中不要包含 HEADER 行(项目标识名称行),以免造成混淆,检索出错。 4.内部表itab中作为条件替换用项目的类型和长度,一定要和检索数据库中对应的项目相同,否则编译不能通过。 5.对于内部表 itab中 作为条件替换用项目,不能使用 LIKE,BETWEEN,IN 比较操作符。 6.使用该语句时,ORDER BY 语句和 HAVING 语句将不能使用。 7.使用该语句时,除COUNT( * )以外的所有标准合计函数(MAX,MIN,AVG,SUM)都不能使用。
4. INSERT 语句 INSERT语法结构: INSERT INTO <dbtab> VALUES wa. INSERT <dbtab> FROM TABLE itab. 示例1: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
| [size=1em][size=1em]TABLES scustom.
[size=1em]scustom-mandt = '002'.
[size=1em]scustom-id = '12400177'.
[size=1em]scustom-name = 'Robinson'.
[size=1em]scustom-postcode = '69542'.
[size=1em]scustom-city = 'Heidelberg'.
[size=1em]scustom-custtype = 'P'.
[size=1em]scustom-discount = '003'.
[size=1em]scustom-telephone = '01234/56789'.
[size=1em]INSERT INTO scustom CLIENT SPECIFIED VALUES scustom.
|
CLIENT SPECIFIED: 是否指定 CLIENT 如果指定CLIENT,则只插入指定CLIENT的相关数据; 如果用在WHERE语句,则是抽取指定CLIENT的相关数据;如若没有指定CLIENT,则抽取所有CLIENT的数据。
示例2: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
[size=1em]12
[size=1em]13
[size=1em]14
[size=1em]15
[size=1em]16
[size=1em]17
[size=1em]18
[size=1em]19
[size=1em]20
[size=1em]21
[size=1em]22
[size=1em]23
[size=1em]24
| [size=1em][size=1em]TABLES SPFLI.
[size=1em]DATA ITAB LIKE SPFLI OCCURS 10 WITH HEADER LINE.
[size=1em]ITAB-CARRID = 'UA'. ITAB-CONNID = '0011'. ITAB-CITYFROM = ..
[size=1em]APPEND ITAB.
[size=1em]ITAB-CARRID = 'LH'. ITAB-CONNID = '1245'. ITAB-CITYFROM = ..
[size=1em]APPEND ITAB.
[size=1em]ITAB-CARRID = 'AA'. ITAB-CONNID = '4574'. ITAB-CITYFROM = ..
[size=1em]APPEND ITAB.
[size=1em]................
[size=1em]INSERT SPFLI FROM TABLE ITAB ACCEPTING DUPLICATE KEYS.
[size=1em]IF SY-SUBRC = 0.
[size=1em] .....
[size=1em]ELSEIF-SUBRC = 4.
[size=1em] .....
[size=1em]ENDIF.
|
5.UPDATE语句 1. UPDATE <dbtab> SET f1 … fn [WHERE sql_cond] . 2. UPDATE <dbtab> FROM TABLE itab [WHERE sql_cond] . 示例: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
[size=1em]11
| [size=1em][size=1em]UPDATE scustom SET: DISCOUNT = '003',
[size=1em] TELEPHONE = '0621/444444'
[size=1em] WHERE ID = '00017777'.
[size=1em]TABLES scustom.
[size=1em]DATA wa LIKE scustom.
[size=1em]wa-id = '12400177'.
[size=1em]wa-telephone = '06201/44889'.
[size=1em]UPDATE scustom FROM wa.
|
6. MODIFY语句 1.MODIFY <dbtab>. (相当于INSERT 和UPDATE) 2.MODIFY <dbtab> FROM TABLE itab. 示例: [size=1em][size=1em]01
[size=1em]02
[size=1em]03
[size=1em]04
[size=1em]05
[size=1em]06
[size=1em]07
[size=1em]08
[size=1em]09
[size=1em]10
| [size=1em][size=1em]TABLES scustom.
[size=1em]scustom-id = '12400177'.
[size=1em]scustom-name = 'Robinson'.
[size=1em]scustom-postcode = '69542'.
[size=1em]scustom-city = 'Heidelberg'.
[size=1em]scustom-custtype = 'P'.
[size=1em]scustom-discount = '003'.
[size=1em]scustom-telephone = '06201/44889'.
[size=1em]MODIFY scustom.
|
7. DELETE语句 1. DELETE FROM <dbtab> WHERE cond. 2. DELETE <dbtab> FROM TABLE itab.
Delete 最好有条件限定,谨慎使用,避免误删数据 [size=1em] | [size=1em][size=1em]DELETE FROM SBOOK WHERE CARRID = 'LH' AND CONNID = '0400' AND FLDATE = '19950228'.
|
|