OPEN SQL
文章目录
1.1 概要
R/3 体系结构
-
SAP R/3 分为 表示层、应用层、数据库层。
-
表示层
就是个人PC(计算机),用于保存构成 SAP GUI 的软件组件,提供 R/3 系统与用户之间的接口。
SAP GUI 相当于手机上的 APP ,用户可以通过此输入或者查询数据。
-
应用层
SAP 中所有程序都在应用层上执行。应用层上存在本地缓冲器,可以通过在数据字典中的数据表中设置缓冲器,访问数据库的请求都会直接在缓冲器中读取数据,用来提高 SAP 的性能,只适用于 OPEN SQL 。
-
数据库层
SAP 中所有数据都存储在本层,例如:画面、函数、数据库表、事务码以及 R/3 系统的所有数据。
SAP 禁止一般用户直接连接数据库修改数据。
ABAP 程序中使用的对象那个(数据表、视图、结构体、类型等)统称为 ABAP 数据字典。
1.2 SQL 定义
SQL 语言分为 三种 :
- DML 用于查询、插入、删除、更新数据库 。
- DDL 用于创建数据库。
- DCL 保证数据完整性、安全性及权限控制。
ABAP 程序中 OPEN SQL 里只允许使用 DML 语言。
SQL 语言包含 OPEN SQL 和 NATIVE SQL 两种,OPEN SQL 只在 ABAP 程序中使用,通过数据库接口解析成 NATIVE SQL 后才能连接到数据库中。
1.2.1 OPEN SQL 和 NATIVE SQL
-
OPEN SQL
由创建数据库数据的 ABAP 命令构成的,不能使用 DDL 、 DCL ,只能使用 DML 语言。而且还可以使用本地缓冲器。
-
NATIVE SQL
可以直接连接数据库使用 DML 、DDL语言,无法使用 OPEN SQL 解决的问题可以通过 NATIVE SQL 解决。
1.2.2 SQL本地缓冲器
作用是减小数据库负荷。得在数据库表的设置里使用缓冲器。
OPEN SQL 依赖于客户(Client),R/3 系统是由多个独立的客户组成的,数据库表是依赖于客户独立存在的对象,一般表中都会存在 MANDT 字段,MANDT字段通常代表客户端(Client)。客户端是SAP系统中的一种数据隔离机制,允许在同一系统中存储多个不同的业务数据环境。每个客户端的数据相互独立,可以为不同的组织、部门、客户等提供服务,而不必担心数据之间的干扰。
- MANDT是一个3位数的字段,表示客户端的唯一标识符(Client ID)。
- 客户端是SAP系统中的一个数据分区,每个客户端具有自己的数据和设置。
- 通过MANDT字段,SAP系统能够区分和存储不同客户端的数据。一个SAP系统通常可以配置多个客户端,在这些客户端中,业务数据是互不干扰的。
- MANDT字段出现在大多数SAP数据库表中,作为区分不同客户端数据的标识。
假设SAP系统中有多个客户端:
客户端 100:用于开发环境
客户端 200:用于测试环境
客户端 300:用于生产环境
每个客户端的数据将存储在相应的表中,并且通过MANDT字段加以区分。
总之,MANDT字段在SAP中用于标识和管理客户端,是多客户端环境下数据隔离和管理的关键。
OPEN SQL 命令语句:
关键字 | 功能 |
---|---|
SELECT | 从数据库中查询数据 |
INSERT | 往数据库中添加数据 |
UPDATE | 修改数据库表的数据 |
MODIFY | 具有 INSERT 和 UPDATE 两种功能,数据库中存在该数据时则修改数据,反之,则直接插入数据。 |
DELETE | 删除数据库表数据 |
1.3 OPEN SQL——SELECT
- 读取数据库表中所有字段时使用星号(*)。
-
SELECT
表示查询数据的个数,SINGLE 代表只读取一条数据。
表示要查询的字段。
SELECT <lines> <columns> ...
-
读取一条数据
使用 SINGLE 语句。只会取得一条数据,因此要正确的给出要查询数据的条件。即在 WHERE 条件里附带所有的 key 值。当没有指明所有 key 值时,就会返回多条数据中的任意一条。
KEY值是由一组字段或字段组合构成的主键,用于唯一标识每一条记录。通过使用主键,SAP系统可以确保数据的一致性、唯一性和完整性。
SELECT SINGLE <columns> WHERE ...
-
DISTINCT 去重
SELECT DISTINCT <columns> WHERE ...
SELECT 语句中还有 ENDSELECT 语句,用于结束 SELECT 语句。
SELECT 语句的使用和 ENDSELECT 语句的必要性,取决于你查询数据的方式和你如何处理查询结果。
-
SELECT 单条数据
如果你使用的是普通的 SELECT SINGLE 或者是 SELECT INTO,那么查询将只返回一个结果,不需要使用 ENDSELECT。
例如:SELECT SINGLE * FROM mara WHERE matnr = '1000001'.
在这个例子中,SELECT SINGLE 只会返回一行数据,因此不需要 ENDSELECT。
-
SELECT 多条数据
当你使用 SELECT … INTO TABLE 或者直接查询多条记录时,通常会使用循环 (LOOP) 结构来处理查询结果。在这种情况下,必须使用 ENDSELECT 来标识查询结束。
例如:SELECT * FROM mara WHERE matnr LIKE '100%' INTO TABLE tableName.
这里,数据会被查询并存储到内表 tableName 中,你通常会继续处理这些数据。如果你需要通过循环去逐行处理查询结果,可以结合 LOOP 和 ENDSELECT。
SELECT * FROM mara WHERE matnr LIKE '100%' INTO TABLE tableName. LOOP AT result INTO lineName. WRITE: / lineName-matnr, lineName-werks. ENDLOOP. ENDSELECT.
需要注意的是 INTO 语句可以写在 WHERE 之前,也可以写在之后。
-
ENDSELECT 的应用
ENDSELECT 只在使用 SELECT 与 LOOP 结合时需要,或者在用 SELECT … INTO 时需要逐行处理每一条结果。ENDSELECT 是为了在读取每一行数据时结束查询结果的循环。
**示例:**SELECT 多条数据与 ENDSELECT 结合
假设你想查询并逐行处理一个表中的多个记录:DATA: lv_matnr TYPE mara-matnr. SELECT matnr FROM mara WHERE matnr LIKE '100%'. WRITE: / lv_matnr. ENDSELECT.
在这个例子中,ENDSELECT 是必需的,它标志着查询结束并表示读取数据行的循环。
总结:
无需 ENDSELECT:当你使用 SELECT SINGLE 或 SELECT INTO 查询单条数据时,不需要 ENDSELECT。
需要 ENDSELECT:当你在使用 SELECT 查询多条记录时,并且没有将结果直接存储到内表,而是需要逐条处理查询结果时,必须使用 ENDSELECT。
-
AS(别名)
类似于 MYSQL 一样,我们可以为字段或者数据库表设置别名。
SELECT a.matnr AS Material a.werks AS Plant b.lifnr AS Supplier INTO (structure|table) FROM mara AS a WHERE a.matnr = '1000001'.
-
动态 SELECT 语句
可以动态的定义 SELECT 语句要查询的字段。保存动态语句的结构体最多可以容纳72位的 char 类型。当结构体为 null 时,与 * 意义相同。
DATA: gt_itab TYPE STANDARD TABLE OF sflight, '定义了一个与sflight结构相同的标准表gt_itab '表分为三类:标准表 排序表 哈希表 (之后会分析,可能不在本篇文章内)gs_wa gs_wa LIKE LINE OF gt_itab. '创建了一个变量gs_wa,与gt_itab表中的行结构相同 DATA: gs_line(72) TYPE c. gt_list LIKE TABLE OF gs_line(72)。 gs_line = 'CARRID CONNID'. SELECT DISTINCT (gs_line) INTO TABLE gt_itab FROM sflight. IF sy-subrc EQ 0. 'sy-subrc = 0 说明 SELECT 语句执行成功 LOOP AT gt_itab INTO gs_wa. '将gt_itab表中的每一行数据抽取出来赋值给 gs_wa WRITE: / gswa-carrid , gs_wa-connid. '从 gs_wa 中取相应字段的值 之间用 - 进行连接 ENDLOOP. ENDIF. '也可以这么写 SELECT DISTINCT (gs_line) INTO TABLE gt_itab FROM sflight. IF sy-subrc EQ 0. 'sy-subrc = 0 说明 SELECT 语句执行成功 LOOP AT gt_itab INTO gs_wa. '将gt_itab表中的每一行数据抽取出来赋值给 gs_wa WRITE: / gswa-carrid , gs_wa-connid. '从 gs_wa 中取相应字段的值 之间用 - 进行连接 ENDLOOP. ENDIF. ENDSELECT.
-
INTO 语句
指定将查询到值存储到目的地。
-
结构体
查询一条语句时使用结构体,使用星号取所有字段之后使用 CORRESPONDING FIELDS OF语句会自动找到相同字段名的值匹配赋值。
SELECT * INTO CORRESPONDING FIELDS OF gs_sfl from sflight WHERE CONNID = '1001'.
-
内表
当查询多条数据时使用内表。
往内表中插入数据有 APPENDING 和 INTO, APPENDING 是往内表中追加数据,而 INTO 是删除数据库表的数据后插入数据时使用的。
SELECT ... INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE <itab> [PACKAGE SIZE <n>]...
使用PACKAGE SIZE可以指定添加到内表里的数据条数,注意要使用 ENDSELECT 语句。
例:
SELECT * INTO CORRESPONDING FIELDS OF TABLE ITAB PACKAGE SIZE 5 FROM SPFLI ENDSELECT.
-
-
单条语句
查询单条数据,添加进指定字段。可以如下写:
SELECT ... INTO (f1,f2,f3...) '查询几个字段,INTO 后面就要跟几个字段,若存在空白,则会报语法错误。 SELECT carrid connid INTO (gv_carrid,gv_connid) FROM SFLIGHT.
-
FROM 语句
指定要查询的数据库表或者视图。 该语句有两个选项,一个是定义表的选项,另一个是控制访问数据库表的选项。
FROM 语句的选项
语句 说明 CLIENT SPECIFIED 解除自动 client 设置 BYPASSING BUFFER 不会从 SAP 本地缓冲器中读取数据,即使数据库中设置了 Buffering 也会直接访问数据库读取数据。 UP TO n ROWS 限制查询数据的个数,可以预防由于用户使用问题而导致的降低数据库性能的问题。例如:由于在选择条件中没有指定日期而导致查询大批量数据的情况。 -
选择静态表
定义静态表时可以指定别名,当指定了别名后,不能使用原来的表名了,只能使用别名。
-
选择动态表
SELECT ... FROM (dbtab)
PARAMETERS p_tname TYPE char10. 'PARAMETERS 是用于声明 输入参数 的关键字。它通常用于在 选择屏幕(selection screen)中定义用户输入的字段,并为程序提供输入数据。定义的参数可以用于后续的处理逻辑中。 '程序会在选择屏幕上生成一个输入框,让用户输入一个 10 字符长度的文本数据。用户输入的数据将被存储在变量 p_tname 中,并可以在程序中使用。 DATA GS_WA TYPE SFLIGHT. SELECT SINGLE * INTO gs_wa FROM (p_tname) WHERE carrid = 'AA'.
-
-
JOIN 语句
由 INNER JOIN 和 OUTER JOIN 两种。
用 ON 指定两个表连接的条件。
使用 INNER JOIN ON 连接条件左右表的字段都不为 null 时,才会查出数据。
而使用 LEFT OUTER JOIN ON 时,一定会显示完整的左表数据,如果右表没有相应的值,则会显示 null 值。
SELECT ... FROM <tab> [INNER] JOIN <dbtab> ON <option> WHERE ... SELECT ... FROM <tab> LEFT OUTER JOIN <dbtab> ON <option> WHERE ...
OPEN SQL 中只能使用 LEFT OUTER JOIN ON
-
限制查询个数
SELECT ... FROM <tab> UP TO <n> ROWS...
-
WHERE 语句
SELECT ... WHERE ...
WHERE 中使用的运算符类型
运算符 意义 运算符 意义 EQ 等于 LE 小于或等于 = 等于 <= 小于或等于 NE 不等于 GT 大于 <> 不等于 > 大于 >< 不等于 GE 大于或等于 LT 小于 >= 大于或等于 < 小于 -
BETWEEN … AND …
取得范围内的数据
-
LIKE 模糊匹配
( _ ) 表示任意一个字符,( % )表示多个任意字符
在 WHERE 中使用 LIKE 关键字 ,之后使用单引号引起来。
-
IN
获取符合条件的多种情况。
-
动态条件
DATA gs_where TYPE c LENGTH 72. gs_where = 'slight'. SELECT * INTO gv_carrname FROM scarr WHERE (gs_where).
-
-
FOR ALL ENTRIES IN
-
internal_table 中的字段要与比较对象的表字段类型一致。
-
internal_table 中自动删除重复数据。
-
internal_table 为空则会取到所有的数据。
-
internal_table 中数据多少会增加 LOOP 循环次数。
SELECT <field_list> FROM <database_table> INTO <target_table> FOR ALL ENTRIES IN <internal_table> WHERE <database_table_field> = <internal_table_field>.
-
-
GROUP BY
对字段进行分组,相同字段则会显示在同一行中。
GROUP BY 进行分组的语句一定要在 SELECT 语句中查询出来。
SELECT 中可以使用的函数
函数 功能 AVG 取平均值 COUNT 取数据的总数 MAX 取最大值 MIN 取最小值 STDDEV 取标准偏差 SUM 取合计 举个例子:
DATA: gv_carrid TYPE sflight-carrid, gv_connid TYPE sflight-connid, gv_paymentsum TYPE i, SELECT carrid connid AVG(paymentsum) INTO (gv_carrid,gv_connid,gv_paymentsum) FROM sflight GROUP BY carrid connid. WRITE: / gv_carrid,gv_connid,gv_paymentsum. ENDSELECT.
注意:使用 SUM 函数时,使用 CORRESPONDING FIELDS OF 语句会取不到预期的效果。此时需要 AS 起别名。
SELECT CARRID SUM( PRICE ) AS PRICE FROM SFLIGHT INTO CORRESPONDING FIELDS OF TABLE GT_GLT WHERE CARRID = 'AA'.
-
HAVING
对 GROUP BY 分组后的数据进行过滤。
-
SORT 语句
对指定字段进行排序。
例如:
ORDER BY PRIMARY KEY
- 根据表的 KEY 进行排序。
- 只适用于 SELECT * 语句
- 在 JOIN 语句和视图中无法使用。
ORDER BY 使用 ASCENDING , DESCENDING 语句可以指定排序类型。
也可以动态的定义要排序的字段,和 SELECT 要动态查询的字段一样,类型为 char 且长度不能超过 72 位。
-
嵌套语句
使用 IN 时,嵌套的 SELECT 语句只能返回一个字段,嵌套的语句以嵌套循环的方式执行,执行的次数时嵌套语句执行的行数。
使用 EXISTS 时,存在数据返回 TRUE ,不存在返回 FALSE。
1.4 OPEN SQL——INSERT/MODIFY
1.4.1 INSERT 语句
往数据库里追加一个或者多个数据。
'格式
INSERT INTO <target> <lines>.
指定客户( Client ),可以静态和动态的定义表名。
'格式
INSERT INTO dbtab [CLIENT SPECIFIED] <lines>.
INSERT INTO <name> [CLIENT SPECIFIED] <lines>.
'例如
INSERT INTO ZCUSTOMERS
CLIENT SPECIFIED
(CustomerID, FirstName, LastName, Email)
VALUES ('C002', 'Alice', 'Smith', 'alice.smith@example.com').
-
追加一条数据, 结构要与表中的表结构相同。
' 将 <wa> 插入到<target>中 INSERT INTO <target> VALUES <wa>. INSERT <target> FROM <wa>. '<dbtab> 要事先以TABLES: <dbtab> INSERT <dbtab>.
-
多条数据
往数据库中一次性插入内表所有值。插入相同主键会发生 dump error,为了避免这种错误需要使用 ACCEPTING DUPLICATE KEYS 语句。INSERT 语句执行错误系统变量 SY-SUBRC 会返回 4。
INSERT spfli FROM TABLE gt_spfli ACCEPTING DUPLICATE KEYS.
1.4.2 MODIFY 语句
存在数据就会修改,不存在就会插入。
'格式
MODIFY <target> <lines>.
指定客户( Client ),可以静态和动态的定义表名。
'格式
MODIFY dbtab [CLIENT SPECIFIED] <lines>.
MODIFY <name> [CLIENT SPECIFIED] <lines>.
-
一条数据
工作区 要与表
MODIFY <target> FROM <lines>. '<dbtab> 要事先以TABLES: <dbtab>定义好表 MODIFY <dbtab>.
-
多条数据
可以一次性修改或追加内表的所有值。
MODIFY <target> FROM TABLE <itab>.
'下面是一个例子 DATA: gt_spfli TYPE TABLE OF spfli, gs_spfli TYPE spfli. gs_spfli-carrid = 'CN'. gs_spfli-connid = '0001'. gs_spfli-cityfrom = 'Beijing'. MODIFY spfli FROM gs_spfli. gs_spfli-carrid = 'CN'. gs_spfli-connid = '0001'. gs_spfli-cityfrom = 'Shanghai'. APPEND gs_spfli TO gt_spfli. gs_spfli-carrid = 'CN'. gs_spfli-connid = '0003'. gs_spfli-cityfrom = 'Shanghai'. APPEND gs_spfli TO gt_spfli. MODIFY spfli FROM TABLE gt_spfli.
1.5 UPDATE 语句
UPDATE 语句用于修改数据库表中的一条或多条数据。
用于指定数据库表名,还可以动态的定义。
UPDATE INTO <target> <lines>.
'指定客户( Client ),可以静态和动态的定义表名
UPDATE <dbtab> [CLIENT SPECIFIED] <lines>.
-
一条数据
UPDATE <target> FROM <wa>. '工作区 <wa> 要与表 <target> 结构相同 '<dbtab> 要事先以TABLES: <dbtab>定义好表 UPDATE <dbtab>.
-
多条数据
'将多条数据在数据库表中修改 UPDATE <target> FROM TABLE <itab>. '修改指定字段 使用 set 语句 UPDATE <target> SET <set1> <set2> WHERE <itab>.
1.6 DELETE 语句
删除数据库中的一个或者多条数据。
DELETE <target> <lines>.
'指定客户( Client ),可以静态和动态的定义表名。
DELETE [FROM](<name>) [CLIENT SPECIFIED] <lines>.
DELETE <dbtab> [CLIENT SPECIFIED] <lines>.
-
删除一条数据
DELETE <target> FROM <wa>. '工作区 <wa> 要与表 <target> 结构相同 '<dbtab> 要事先以TABLES: <dbtab>定义好表 DELETE <dbtab>.
-
删除多条数据
DELETE FROM <target> WHERE <cond>.
'修改指定字段 使用 set 语句
UPDATE SET WHERE .
1.6 DELETE 语句
删除数据库中的一个或者多条数据。
DELETE <target> <lines>.
'指定客户( Client ),可以静态和动态的定义表名。
DELETE [FROM](<name>) [CLIENT SPECIFIED] <lines>.
DELETE <dbtab> [CLIENT SPECIFIED] <lines>.
-
删除一条数据
DELETE <target> FROM <wa>. '工作区 <wa> 要与表 <target> 结构相同 '<dbtab> 要事先以TABLES: <dbtab>定义好表 DELETE <dbtab>.
-
删除多条数据
DELETE FROM <target> WHERE <cond>.