原文出自 江正軍 技術博客,博客鏈接:www.cnblogs.com/jiangzhengjun
OPEN SQL也是ABAP開發人員必備的知識,雖然可以使用原生的SQL來寫,但不建議,就像JDBC與Hibernate的關系,性能與跨數據庫的選擇。但為了開發的簡便與可移值性,還是使用Open SQL吧!這里貼出一些常用的操作,做項目時我也經常翻出來看一眼再寫。
4. OPEN SQL
4.1. SELECT 、 INSERT 、 UPDATE 、 DELETE 、 MODIFY
4.2. 條件操作符
4.3. RANG 條件內表
4.4. FOR ALL ENTRIES
4.5. INNER JOIN 、 LEFT OUTER JOIN 使用限制
4.6. 動態 SQL
4.7. 子查詢
4.7.1. = 、 <> 、 < 、 <= 、 > 、 >= 子查詢
4.7.1.1. ALL 、 ANY 、 SOME
4.7.2. [NOT] IN 子查詢
4.7.3. [NOT] EXISTS 子查詢
4.7.4. 相關子查詢
4.8. 統計函數
4.9. 分組過濾
4.10. 游標
4.11. 三種緩存
4.12. Native SQL
4.12.1. 查詢
4.12.2. 存儲過程
4.12.3. 游標
4.13. SAP 鎖
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 連接,像這樣:
另外,在使用 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 的第一個字段
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