声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4264698.html OPEN SQL也是ABAP开发人员必备的知识,虽然可以使用原生的SQL来写,但不建议,就像JDBC与Hibernate的关系,性能与跨数据库的选择。但为了开发的简便与可移值性,还是使用OpenSQL吧!这里贴出一些常用的操作,做项目时我也经常翻出来看一眼再写。
4. OPEN SQL.43
4.1. SELECT、INSERT、UPDATE、DELETE、MODIFY.43
4.2. 条件操作符...44
4.3. RANG条件内表...44
4.4. FOR ALL ENTRIES.45
4.5. INNER JOIN、LEFT OUTER JOIN使用限制...46
4.6. 动态SQL.46
4.7. 子查询...47
4.7.1. =、<>、<、<=、>、>=子查询...47
4.7.1.1. ALL、ANY、SOME.48
4.7.2. [NOT] IN子查询...48
4.7.3. [NOT] EXISTS子查询...48
4.7.4. 相关子查询...48
4.8. 统计函数...48
4.9. 分组过滤...48
4.10. 游标...49
4.11. 三种缓存...49
4.12. Native SQL.50
4.12.1. 查询...50
4.12.2. 存储过程...50
4.12.3. 游标...50
4.13. SAP锁...51
4. OPEN SQL
4.1. SELECT、INSERT、UPDATE、DELETE、MODIFY
如果从数据库读出来的数据存在重复时,不能存储到Unique内表中去——如Unique的排序表与哈希表
SELECT SINGLE...INTO [CORRESPONDING FIELDS OF] waWHERE...
SELECT SINGLE<cols>...INTO(dobj1,dobj2,...)WHERE...
SELECT...FROM<tables>UP TO<n>ROWS...
SELECT...INTO|APPENDING CORRESPONDING FIELDS OFTABLE <itab>...
单条插入:在插入时是按照数据库表结构来解析<wa>结构,与<wa>中的字段名无关,所以<wa>的长度只少要等于或大于所对应表结构总长度
INSERTINTO<tabname>VALUES<wa>
INSERT<tabname>FROM<wa>
多条插入:itab内表的行结构也必须和数据库表的行结构一致;ACCEPTING DUPLICATE KEYS:如果现出关键字相同条目,系统将SY-SUBRC返回4,并跳过该条目,但其他数据会插入进去
INSERT<tabname>FROMTABLE<itab>[ACCEPTING DUPLICATE KEYS]
单条更新:会根据数据库表关键字来更新其他非关键字段。如果WA工作区是自己定义的且未参照数据库表,则WA的结构需要与数据库表相一致,且不能短于数据库表结构,但字段名可任意取
UPDATEdbtabFROMwa
多条更新:主键不会被更新,即使在SET后面指定后也不会被更改
UPDATEdbtabSETf1 = g1 … fi = giWHERE<conditions>
UPDATEdbtabFROMTABLEitab与从WA工作区单条更新原理一样,根据数据表库关键字段来更新,且行结构要与数据库表结构一致,并且不能短于数据库表结构,一样内表行结构组件名可任意
单条删除:下面的WA与Itab原理与Update是一样的
DELETEdbtabFROMwa
多条删除:
DELETEdbtabFROMTABLEitab
DELETEFROMdbtabWHERE<conditions>
插入或更新:下面的WA与Itab原理与Update是一样的
MODIFYdbtabFROMwa 单行
MODIFYdbtabFROMTABLEitab多行,有就修改,没有就插入
4.2. 条件操作符
=、<>、<、<=、>、>=
[NOT]BETWEEN...AND
[NOT]LIKE
[NOT]IN
IS[NOT]NULL
4.3. RANG条件内表
两种定义方式:
RANGESseltabFORdobj [OCCURSn].其中dobj为自定义变量或者是参照某个表字段
SELECT-OPTIONSselcritFOR{dobj|(name)}
上面两个语句会生成如下结构的内表,该条件内表的每一行都代表一个逻辑条件:
DATA:BEGIN OF seltab OCCURS 0,
sign TYPE cLENGTH1,允许值为I和E,I表示包含Include,E表示排除Exclude
optionTYPE cLENGTH2,OPTION表示选择运算符,
low LIKE dobj,下界,相当于前面文本框中的值
high LIKE dobj,上界,相当于后面文本框中的值
END OFrtab.
option: HIGH字段为空,则取值可以为:EQ(=)、NE(<>)、GT(>)、GE(>=)、LE(<=)、LT(<)、CP、NP,CP(集合之内的数据)和NP(集合之外数据)只有当在输入字段中使用了通配符(“*”或“+”)时它们才是有效的
SELECT... WHERE...field[NOT]IN seltab...
如果RANG条件内表为空,则INseltab逻辑表达试恒为真,XX NOT INseltab恒为假
注:不会像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后面还有其它条件,所有的条件都会忽略:
SELECTvbeln posnr pstyv werks matnr arktx lgort waerk kwmeng
FROMvbapINTO TABLEgt_soFOR ALLENTRIESINlt_matnr
WHEREmatnr=lt_matnr-matnrANDvbelnINs_vbelnANDposnrINs_posnr.
如果上面的lt_matnr为空,则“AND vbeln IN s_vbeln AND posnr IN s_posnr”条件也会忽略掉,即整个Where都会被忽略掉。
SELECT matnrFROMmaraINTOCORRESPONDINGFIELDS OF TABLEstrc
FOR ALLENTRIESINstrcWHEREmatnr=strc-matnr.
生成的SQL语句:SELECT"MATNR"FROM"MARA"WHERE"MANDT" = '210' AND "MATNR" IN ( '000000000000000101' , '000000000000000103', '000000000000000104' )
注:这里看上去FOR ALL ENTRIES使用IN表达式来代替了,这是只有使用到内表中一个条件是这样的,如果使用多个条件时,不会使用In表达式,而是使用OR连接,像这样:
另外,在使用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_typeTYPE cLENGTH72.
DATA:column_syntaxTYPE TABLE OFline_type.
APPEND'CARRID'TOcolumn_syntax.
APPEND'CITYFROM CITYTO'TOcolumn_syntax.
SELECT...FROM(dbtab_syntax)...
PARAMETERS:p_cityfrTYPEspfli-cityfrom,
p_citytoTYPEspfli-cityto.
DATA:BEGIN OFwa,
fldateTYPEsflight-fldate,
carrnameTYPEscarr-carrname,
connid TYPEspfli-connid,
END OFwa.
DATAitabLIKE SORTED TABLE OFwa
WITH UNIQUE KEYfldate carrname connid.
DATA:column_syntaxTYPEstring,
dbtab_syntaxTYPEstring.
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 TABLEitab.
SELECT...WHERE(cond_syntax) ...
SELECT...WHERE<cond>AND/OR(cond_syntax) ...
DATA:cond(72)TYPE c,
itabLIKE TABLE OFcond.
APPEND'cityfrom = ''NEW YORK'''TOitab.
APPEND'or cityfrom = ''SAN FRANCISCO'''TOitab.
SELECT*INTO TABLEitab_spfliFROMspfliWHERE(itab).
DATA:cond1(72)TYPE c VALUE'cityfrom = ''NEW YORK''',
cond2(72)TYPE c VALUE'cityfrom = ''SAN FRANCISCO'''.
SELECT*INTO TABLEitab_spfliFROMspfliWHERE(cond1)OR(cond2).
DATA:cond(72)TYPE c,
cond1(72)TYPE c VALUE'cityfrom = ''NEW YORK''',
itabLIKE TABLE OFcond.
APPEND'cityfrom = ''SAN FRANCISCO'''TOitab.
SELECT*INTO TABLEitab_spfliFROMspfliWHERE (itab) OR(cond1).
DATA:cond(72)TYPE c,
itabLIKE TABLE OFcond.
APPEND'cityfrom = ''SAN FRANCISCO'''TOitab.
SELECT*INTO TABLEitab_spfliFROMspfliWHERE (itab)ORcityfrom='NEW YORK'
4.7. 子查询
columoperator[ALL|ANY|SOME]、[NOT]EXISTS、[NOT]IN连接至WHERE从句与HAVING从句中
4.7.1. =、<>、<、<=、>、>=子查询
子查询的SELECT中只有一个表字段或者是一个统计列,并且只能返回一条数据
SELECT* FROMsflightINTOwa_sflight
WHEREseatsocc = (SELECT MAX( seatsocc )FROMsflight ).
ENDSELECT.
操作符可以是:=、<>、<、<=、>、>=
4.7.1.1. ALL、ANY、SOME
如果子查询返回的是多条,则使用ALL、ANY、SOME来修饰
SELECTcustomidCOUNT( * )FROMsbookINTO(id, cnt)GROUP BYcustomid
HAVING COUNT( * ) >=ALL (SELECT COUNT( * )FROMsbookGROUP BYcustomid ).
ENDSELECT.
2 ALL:主查询数据大于所有子查询返回的行数据时,才为真
2 ANY|SOME:主查询数据只要大于任何一条子查询返回的行数据时,才为真
2 = ANY|SOME:等效IN子查询
4.7.2. [NOT] IN子查询
此类子查询SELECT中也只有单独的一列选择列,但查询出的结果可能有多条
SELECT SINGLEcity latitude longitudeINTO(city, lati, longi)FROMsgeocity
WHERE cityIN (SELECTcityfromFROMspfli
WHEREcarrid = carr_idANDconnid = conn_id ).
4.7.3. [NOT] EXISTS子查询
这类子查询没有返回值,也不要求SELECT从句中只有一个选择列,选择列可以任意个数,WHERE或者HAVING从句根据该子查询的是否查询到数据来决定外层主查询语句来选择相应数据
SELECTcarrnameINTO TABLEname_tabFROMscarr
WHERE EXISTS (SELECT*FROMspfli
WHEREcarrid = scarr~carridANDcityfrom ='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)ASmINTO priceFROMsflightGROUP BYcarrid
HAVING MAX(price)>10.Having从句中比较统计结果时,需要将统计函数重写一遍,而不能使用Select中定义的别名
ENDSELECT.
4.10. 游标
DATA:c TYPE cursor.[?k?:s?]
DATA: waTYPEspfli.
"1、打开游标
OPEN CURSOR:c FOR SELECTcarrid connidFROMspfliWHEREcarrid ='LH'.
DO.
"2、读取数据
FETCH NEXT CURSOR c INTO CORRESPONDING FIELDS OFwa.
IFsy-subrc <>0.
"3、关闭游标
CLOSECURSOR 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的第一个字段
l 全部缓存:在第一次读取表数据时,会将整个表的数据都会缓存下来,不管WHERE条件
4.12. Native SQL
4.12.1. 查询
DATA:BEGIN OFwa,
connidTYPEspfli-connid,
cityfromTYPEspfli-cityfrom,
citytoTYPEspfli-cityto,
END OFwa.
DATAc1TYPEspfli-carridVALUE'LH'.
"Native SQL语句不能以句点号结尾;
"不能在EXEC SQL…ENDEXEC间有注释,即不能有星号与双引号的出现;
"参数占位符使用冒号,而不是问号;
EXEC SQL PERFORMINGloop_output.
SELECTconnid,cityfrom,cityto
INTO:wa
"或使用:INTO :wa-connid ,:wa-cityfrom ,:wa-cityto
FROMspfli
WHEREcarrid=:c1
ENDEXEC.
FORMloop_output.
WRITE:/ wa-connid,wa-cityfrom,wa-cityto.
ENDFORM
4.12.2. 存储过程
EXEC SQL.
EXECUTE PROCEDUREproc1(IN:x,OUT:y,INOUT:z)
ENDEXEC.
4.12.3. 游标
DATA:arg1TYPEstringVALUE'800'.
TABLES:t001.
EXEC SQL.
OPEN c1FORSELECTMANDT,BUKRSFROMT001"打开游标
WHEREMANDT= :arg1ANDBUKRS >='ZA01'
ENDEXEC.
DO.
EXEC SQL.
FETCH NEXT c1INTO :t001-mandt, :t001-bukrs"读取游标
ENDEXEC.
IFsy-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:]
特定数据库表锁函数:ENQUEUE_<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 |