[SAP ABAP开发技术总结]OPEN SQL

OPEN SQL也是ABAP开发人员必备的知识,虽然可以使用原生的SQL来写,但不建议,就像JDBC与Hibernate的关系,性能与跨数据库的选择。但为了开发的简便与可移值性,还是使用Open SQL吧!这里贴出一些常用的操作,做项目时我也经常翻出来看一眼再写。

4.    OPEN SQL

4.1.   SELECT 、 INSERT 、 UPDATE 、 DELETE 、 MODIFY

如果从数据库读出来的数据存在重复时 , 不能存储到 Unique 内表中去 —— 如 Unique 的排序表与哈希表

SELECT   SINGLE ... INTO   [ CORRESPONDING   FIELDS OF ] wa WHERE ...
SELECT SINGLE <cols> ... INTO ( dobj1 , dobj2 , ... ) WHERE
...

SELECT ... FROM <tables> UP TO <n> ROWS ...

SELECT ... INTO | APPENDING   CORRESPONDING   FIELDS OF TABLE   <itab> ...

 

单条插入 :在插入时是按照数据库表结构来解析 <wa> 结构,与 <wa> 中的字段名无关,所以 <wa> 的长度只少要等于或大于所对应表结构总长度

INSERT INTO <tabname> VALUES <wa>

INSERT <tabname> FROM <wa>

多条插入 : itab 内表的行结构也必须和数据库表的行结构一致; ACCEPTING DUPLICATE KEYS :如果现出关键字相同条目,系统将 SY-SUBRC 返回 4 ,并跳过该条目,但其他数据会插入进去

INSERT <tabname> FROM TABLE < itab > [ ACCEPTING DUPLICATE KEYS ]

 

单条更新: 会根据数据库表关键字来更新其他非关键字段。如果 WA 工作区是自己定义的且未参照数据库表,则 WA 的结构需要与数据库表相一致,且不能短于数据库表结构,但字段名可任意取

UPDATE dbtab FROM wa

多条更新: 主键不会被更新,即使在 SET 后面指定后也不会被更改

UPDATE dbtab SET f1 = g1 … fi = gi WHERE <conditions>

UPDATE dbtab FROM TABLE itab 与从 WA 工作区单条更新原理一样,根据数据表库关键字段来更新,且行结构要与数据库表结构一致,并且不能短于数据库表结构,一样内表行结构组件名可任意

 

单条删除: 下面的 WA 与 Itab 原理与 Update 是一样的

DELETE dbtab FROM wa

多条删除:

DELETE dbtab FROM TABLE itab

DELETE FROM dbtab WHERE <conditions>

 

插入或更新: 下面的 WA 与 Itab 原理与 Update 是一样的

MODIFY dbtab FROM wa  单行

MODIFY dbtab FROM TABLE itab 多行,有就修改,没有就插入

4.2.   条件操作符

= 、 <> 、 < 、 <= 、 > 、 >=

[ NOT ] BETWEEN ... AND
[
NOT ] LIKE
[
NOT ] IN
IS [ NOT ] NULL

4.3.   RANG 条件内表

两种定义方式:

RANGES seltab FOR dobj [ OCCURS n]. 其中 dobj 为 自定义变量 或者是参照某个 表字段

SELECT-OPTIONS selcrit FOR {dobj|(name)}

上面两个语句会生成如下结构的内表,该条件内表的每一行都代表一个逻辑条件 :

DATA : BEGIN   OF   seltab   OCCURS   0 ,
        sign  
TYPE   c LENGTH 1
,
允许值为 I 和 E , I 表示包含 Include , E 表示排除 Exclude
        option
TYPE   c LENGTH 2 , OPTION 表示选择运算符 ,
        low   
LIKE   dobj , 下界 ,相当于 前面文本框 中的值
        high  
LIKE   dobj , 上界 ,相当于 后面文本框中的值
     
END   OF rtab.

option : HIGH 字段为空,则取值可以为: EQ ( = )、 NE ( <> )、 GT ( > )、 GE ( >= )、 LE ( <= )、 LT ( < )、 CP 、 NP , CP (集合之内的数据)和 NP (集合之外数据)只有当在输入字段中使用了通配符(“ * ”或“ + ”)时它们才是有效的

SELECT ...   WHERE ... field [NOT] IN   seltab ...

如果 RANG 条件内表为空 , 则 IN seltab 逻辑表达试恒为真 , XX NOT IN seltab 恒为假

注: 不会像 FOR ALL ENTRIES 那样 , 忽略其他的条件表达式 , 其他条件还是起作用

4.4.   FOR ALL ENTRIES

1、 使用该选项后,对于最后得出的结果集系统 会自动删除重复行 。因此如果你要保留重复行记录时,记得在 SELECT 语句中添加足够字段

2、 FOR ALL ENTRIES IN 后面使用的内部表 itab 如果 为空 ,将查出 当前 CLIENT 端 所有数据( 即忽略整个 WHERE 语句 ,其他条件都会被忽略)

3、 内表中的条件字段 不能使用 BETWEEN 、 LIKE 、 IN 比较操作符

4、 使用该语句时, ORDER BY 语句和 HAVING 语句 将 不能使用

5、 使用该语句时, 除 COUNT ( * ) (并且如果有了 COUNT 函数,则不能再选择其他字段,只能使用在 Select ... ENDSelect 语句中了)以外的 所有合计函数( MAX,MIN,AVG,SUM )都不能使用

即使 Where 后面还有其它条件,所有的条件都会忽略 :

SELECT vbeln posnr pstyv werks matnr arktx lgort waerk kwmeng
   
FROM vbap INTO TABLE gt_so FOR ALL ENTRIES IN lt_matnr

   
WHERE matnr = lt_matnr - matnr AND vbeln IN s_vbeln AND posnr IN s_posnr .

如果上面的 lt_matnr 为空,则“ AND  vbeln IN s_vbeln AND posnr IN s_posnr ”条件也会忽略掉,即整个 Where 都会被忽略掉。

 

SELECT  matnr FROM mara INTO CORRESPONDING FIELDS OF TABLE strc
   
FOR ALL ENTRIES IN strc WHERE matnr = strc - matnr
.

生成的 SQL 语句: SELECT "MATNR" FROM "MARA" WHERE "MANDT" = '210' AND "MATNR" IN ( '000000000000000101' , '000000000000000103' , '000000000000000104' )

注 :这里看上去 FOR ALL ENTRIES 使用 IN 表达式来代替了,这是只有使用到内表中一个条件是这样的,如果使用多个条件时,不会使用 In 表达式,而是使用 OR 连接,像这样:

image039

image040

另外,在使用 FOR ALL ENTRIES 时,不管使用了条件内表中的一个还是多个条件字段,都会以 5 个 值为单位进行 SQL 发送

4.5.   INNER JOIN 、 LEFT OUTER JOIN 使用限制

ON 后面的条件与 Where 条件类似,但有以下不同:

2   必需有 ON 条件语句,且多个条件之间只能使用 AND 连接

2   每个条件表达式中 两个操作数之中必须有一个字段是来自于 JOIN 右表

2   如果是 LEFT OUTER JOIN ,则 至少有一个条件表达式的两个操作数一个是来自于左表,另一个来自右表

2   不能使用 NOT 、 LIKE 、 IN (但如果是 INNER JOIN ,则 > 、 < 、 BETWEEN …AND 、 <> 都可用)

2   如果是 LEFT OUTER JOIN ,则只能使用等号操作符: ( = 、 EQ )

2   如果是 LEFT OUTER JOIN , 同一右表不能多次出现在不同的 LEFT OUTER JOIN 的 ON 条件表达式中

2   LEFT OUTER JOIN 的右表所有字段不能出现在 WHERE 中

2   如果是 LEFT OUTER JOIN ,则在同一个 ON 条件语句中 只能与同一个左表进行关联

4.6.   动态 SQL

SELECT ( column_syntax ) FROM ...

column :可以是内表,也可以是字符串

TYPES : line_type TYPE c LENGTH 72 .
DATA : column_syntax TYPE TABLE OF line_type .
APPEND 'CARRID' TO column_syntax .
APPEND 'CITYFROM CITYTO' TO column_syntax
.

 

SELECT ... FROM (dbtab_syntax)...

PARAMETERS : p_cityfr TYPE spfli - cityfrom ,
            p_cityto
TYPE spfli - cityto .
DATA : BEGIN OF wa ,
         fldate
TYPE sflight - fldate ,
         carrname
TYPE scarr - carrname ,
         connid  
TYPE spfli - connid ,
      
END OF wa .
DATA itab LIKE SORTED TABLE OF wa
              
WITH UNIQUE KEY fldate carrname connid .
DATA : column_syntax TYPE string ,
      dbtab_syntax
TYPE string .
column_syntax
= `c~carrname p~connid f~fldate` .
dbtab_syntax
= `( ( scarr AS c `
  &
` INNER JOIN spfli AS p ON p~carrid  = c~carrid`
  &
` AND p~cityfrom = p_cityfr `
  &
` AND p~cityto   = p_cityto )`
  &
` INNER JOIN sflight AS f ON f~carrid = p~carrid `
  &
` AND f~connid = p~connid )` .
SELECT
( column_syntax ) FROM ( dbtab_syntax )
      
INTO CORRESPONDING   FIELDS OF TABLE itab
.

 

SELECT ... WHERE ( cond_syntax ) ...
SELECT ... WHERE <cond> AND/OR ( cond_syntax
) ...

DATA : cond ( 72 ) TYPE c ,
      itab
LIKE TABLE OF cond .
APPEND 'cityfrom = ''NEW YORK''' TO itab .
APPEND 'or cityfrom = ''SAN FRANCISCO''' TO itab .
SELECT * INTO TABLE itab_spfli FROM spfli
WHERE ( itab ) .

DATA : cond1 ( 72 ) TYPE c VALUE 'cityfrom = ''NEW YORK''' ,
     cond2
( 72 ) TYPE c VALUE 'cityfrom = ''SAN FRANCISCO''' .
SELECT * INTO TABLE itab_spfli FROM spfli
WHERE (cond1) OR (cond2) .

DATA : cond ( 72 ) TYPE c ,
      cond1
( 72 ) TYPE c VALUE 'cityfrom = ''NEW YORK''' ,
      itab
LIKE TABLE OF cond .
APPEND 'cityfrom = ''SAN FRANCISCO''' TO itab .
SELECT * INTO TABLE itab_spfli FROM spfli
WHERE   (itab)   OR (cond1) .

DATA : cond ( 72 ) TYPE c ,
      itab
LIKE TABLE OF cond .
APPEND 'cityfrom = ''SAN FRANCISCO''' TO itab .
SELECT * INTO TABLE itab_spfli FROM spfli
WHERE   (itab) OR cityfrom = 'NEW YORK'

4.7.   子查询

colum operator [ALL|ANY|SOME] 、 [NOT] EXISTS 、 [NOT] IN 连接至 WHERE 从句与 HAVING 从句中

4.7.1.    = 、 <> 、 < 、 <= 、 > 、 >= 子查询

子查询的 SELECT 中 只有 一个表字段 或者是 一个统计列 ,并且 只能返回一条数据

SELECT *  FROM sflight INTO wa_sflight
         
WHERE
seatsocc   =   ( SELECT   MAX ( seatsocc ) FROM sflight ).
ENDSELECT
.

操作符可以是: = 、 <> 、 < 、 <= 、 > 、 >=

4.7.1.1.             ALL 、 ANY 、 SOME

如果子查询 返回的是多条 ,则使用 ALL 、 ANY 、 SOME 来修饰

SELECT customid COUNT ( * ) FROM sbook INTO (id, cnt) GROUP   BY customid
      
HAVING   COUNT
( * )   >= ALL   ( SELECT   COUNT ( * ) FROM sbook GROUP   BY customid ).
ENDSELECT
.

2   ALL :主查询数据大于 所有 子查询返回的行数据时,才为真

2   ANY|SOME :主查询数据只要大于 任何 一条子查询返回的行数据时,才为真

2   = ANY|SOME :等效 IN 子查询

4.7.2.    [NOT] IN 子查询

此类子查询 SELECT 中也只有单独的 一列 选择列,但查询出的 结果可能有多条

SELECT   SINGLE city latitude longitude INTO (city, lati, longi) FROM sgeocity
 
WHERE
  city IN   ( SELECT cityfrom FROM spfli
                   
WHERE carrid = carr_id AND
connid = conn_id ).

4.7.3.    [NOT] EXISTS 子查询

这类 子查询没有返回值 ,也 不要求 SELECT 从句中只有一个选择列 ,选择列可以任意个数, WHERE 或者 HAVING 从句根据该子查询的是否查询到数据来决定外层主查询语句来选择相应数据

SELECT carrname INTO   TABLE name_tab FROM scarr
 
WHERE
 
EXISTS   ( SELECT * FROM spfli
                   
WHERE
carrid =   scarr~carrid AND cityfrom = 'NEW YORK' ).

4.7.4.    相关子查询

上面的示例子查询即为 相关子查询

如果某个子查的 WHERE 条件中引用了外层查询语句的列,则称此子查询为相关子查询。相关子查询对外层查询结果集中的每条记录都会执行一次,所以尽量少用相关子查询

4.8.   统计函数

MAX 、 MIN 、 AVG 、 SUM 、 COUNT ,聚合函数都可以加上 DISTINCT 选项

4.9.   分组过滤

如果将统计函数与 GROUP BY 子句一起使用,那么 Select 语句中未出现在统计函数的数据库字段都必须在 GROUP BY 子句中出现 。如果使用 INTO CORRESPONDING FIELDS 项,则需要在 Select 语句中通过 AS 后面的别名将统计结果存放到与之相应同名的内表字段中:

SELECT MIN ( price ) AS m INTO  price FROM sflight GROUP BY carrid
 
HAVING
  MAX( price ) > 10 . Having 从句中比较统计结果时,需要将统计函数重写一遍,而不能使用 Select 中定义的别名
ENDSELECT .

4.10.      游标

DATA : c   TYPE   cursor . [?k?:s?]  
DATA : wa TYPE spfli.
" 1
、 打开游标
OPEN CURSOR : c   FOR   SELECT carrid connid FROM spfli WHERE carrid = 'LH' .
DO
.
 
" 2
、读取数据
  FETCH NEXT CURSOR   c   INTO   CORRESPONDING   FIELDS   OF wa.
 
IF sy-subrc <> 0
.
   
" 3
、关闭游标
    CLOSE CURSOR   c .
   
EXIT
.
 
ELSE
.
   
WRITE
: / wa-carrid, wa-connid.
 
ENDIF
.
ENDDO
.

4.11.      三种缓存

l   单记录缓存 :从数据库中仅读取一条数据并存储到 table buffer 中。此缓存只对 SELECT SINGLE… 语句起作用

l   部分缓存 :需要在指定 generic key (即关键字段组合,根据哪些关键字段来缓存,可以是部分或全部关键字段)。 如果主键是由一个字段构成,则不能选择此类型缓存 。当你使用 generic key 进行数据访问时,则属于此条件范围的整片数据都会被加载到 table buffer 中

1 、 查询时如果使用 BYPASSING BUFFER 选项,除了绕过缓存直接到数据库查询外,查出的数据不会放入缓存

2 、 只要查询条件中出现了用作缓存区域的所有关键字段,则查询出所有满足条件全部数据进行缓存

3 、 如果查询条件中 generic key 只出现某个或者某部分,则不会进行缓存操作

4 、 如果主键是只由一个字段组成,则不能设定为此种缓存

5 、 如果有 MANDT 字段,则为 generic key 的第一个字段

image041   image042

l   全部缓存 :在第一次读取表数据时,会将整个表的数据都会缓存下来,不管 WHERE 条件

4.12.      Native SQL

4.12.1.            查询

DATA : BEGIN OF wa ,
  connid
TYPE spfli - connid ,
  cityfrom
TYPE spfli - cityfrom ,
  cityto
TYPE spfli - cityto ,
END OF wa .
DATA c1 TYPE spfli - carrid VALUE 'LH' .

" Native SQL 语句不能以句点号结尾 ;

" 不能在 EXEC SQL…ENDEXEC 间有注释 ,即不能有星号与双引号的出现;

" 参数占位符使用冒号,而不是问号;

EXEC SQL PERFORMING loop_output .
 
SELECT connid , cityfrom , cityto
    INTO : wa

" 或使用: INTO :wa-connid ,:wa-cityfrom ,:wa-cityto
   
FROM spfli
   
WHERE carrid
= : c1
ENDEXEC.

FORM loop_output .
 
WRITE : / wa - connid , wa - cityfrom , wa - cityto .
ENDFORM

4.12.2.            存储过程

EXEC SQL.
 
EXECUTE PROCEDURE proc1 ( IN : x, OUT : y, INOUT : z )
ENDEXEC .

4.12.3.            游标

DATA : arg1 TYPE string VALUE '800' .
TABLES : t001 .
EXEC SQL .

 
OPEN   c1 FOR SELECT MANDT , BUKRS FROM T001 " 打开游标
             
WHERE MANDT = : arg1 AND BUKRS >= 'ZA01'
ENDEXEC .
DO .
 
EXEC SQL .

   
FETCH NEXT   c1 INTO   : t001 - mandt , : t001 - bukrs " 读取游标
 
ENDEXEC .
 
IF sy - subrc <> 0 .
   
EXIT .
 
ELSE .
   
WRITE : / t001 - mandt , t001 - bukrs .
 
ENDIF .
ENDDO .
EXEC SQL .

 
CLOSE   c1 " 关闭游标
ENDEXEC .

4.13.      SAP 锁

通用数据库表锁函数: ENQUEUE_E_TABLE 、 DEQUEUE_E_TABLE 、 DEQUEUE_ALL (解锁所有) [kju:]  

特定数据库表锁函数: EN QUEUE _<LOCK OBJECT> 、 DENQUEUE _<LOCK OBJECT>

自定义的锁对象都必须以 EZ_ 或者 EY_ 开头来命名

 

允许第二次加锁模式

第一次加锁模式

S

E

X

S 共享锁

是 ( 是 )

否( 是 )

否(否)

E 可重入的排他锁

否( 是 )

否( 是 )

否(否)

X 排他锁

否(否)

否(否)

否(否)

括号内为同一程序(即同一事务内)内,括号外为非同一程序内

CALL FUNCTION 'ENQUEUE _EZ_ZSPFLI' " 加锁
 
EXPORTING
   mode_zspfli         
= 'E'
   mandt               
= sy - mandt
   carrid              
= 'AA'

   connid              
= '0011'
*   X_CARRID             = ' '" 设置字段初始值( Initial Value ),若为 X ,则当遇到与 CARRID 的初始值 Initial Value 相同值时才会设置锁对象。 CARRID 的初始值只需在数据库表字段中选择 Initial Value 选项 (SE11 中设置 ) 。当没有设置 X 时,则会用该锁函数所设置的 Default Value 指定初始值
*   X_CONNID             = ' '
*   _SCOPE               = '2'"
该选项只有在 UPDATE 函数( CALL FUNCTION FM IN UPDATE TASK )中才起作用,用来控制锁的传递。一般当调用解锁函数 DEQUEUE 或程序结束时( LEAVE PROGRAM 或者 LEAVE TO TRANSACTION )锁就会被自动解除,另外,遇到 A 、 X 消息时或用户在命令框中输入 /n 时锁也会被解除,但是,当事务码正在执行 UPDATE 函数时就不一样了,函数结束时是否自动解除锁则要看该选项 _SCOPE
了:

1- 表示程序内有效 2- 表示 update module 内有效 3- 全部
*   _WAIT                = ' '" 表示如果对象已经被锁定 , 是否等待后再尝试加锁
*   _COLLECT             = ' '"
参数表示是否收集后进行统一提交

 

程序锁定: ENQUEUE_ ES_PROG 和 DEQUEUE_ES_PROG

posted @ 2015-01-31 20:56  江正军  阅读(29408)  评论(3)    收藏  举报