---
只有標准SQL的DML有對應的Open SQL,只有SELECT、INSERT, UPDATE, DELETE有對應的Open SQL。
Native SQL不會用到緩存,會直接發送給數據庫,而不會經過ABAP數據訪問層。除開DML,它一般用於DDL、DCL,主要用來維護數據庫表
ABAP中的Database Interface層負責將Open SQL轉換成相應的數據庫所支持的Standard SQL
Open SQL
ABAP Dictionary屬於ABAP Workbench的一部分,可以用它來創建與管理數據庫表
Open SQL只能訪問那些通過ABAP Dictionary創建的表(通過ABAP Dictionary創建的表才會顯示在Dictionary里),而不能操作那些直接通過數據庫工具創建的表。ABAP Dictionary通過標准的DDL SQL創建與維護數據庫表。
Open SQL contains the following keywords:
Keyword |
Function |
SELECT |
讀取 |
INSERT |
插入 |
UPDATE |
修改 |
MODIFY |
插入或修改 |
DELETE |
刪除 |
OPENCURSOR,FETCH,CLOSE CURSOR |
游標 |
COMMIT WORK, ROLLBACK WORK |
|
SY-SUBRC:所有Open SQL在執行成功時返回0,否則返回非0
SY-DBCNT:在執行Open SQL語句后,返回受影響的數據條數
讀取數據SELECT
SELECT {SINGLE [FOR UPDATE]}|{[DISTINCT]{}}
* | { {col1|{ MAX( [DISTINCT] col )
| MIN( [DISTINCT] col )
| AVG( [DISTINCT] col )
| SUM( [DISTINCT] col )
| COUNT( DISTINCT col )
| COUNT( * ) } } [AS a1] ... } | (column_syntax)
FROM { {dbtab [AS tabalias]}
| [(] { {dbtab_left [AS tabalias_left]} | join_expression_即兩個或兩個以上的表前部分JOIN表達式}
{[INNER] JOIN}|{LEFT [OUTER] JOIN}
{dbtab_right [AS tabalias_right] ON join_cond} [)]
|{(dbtab_syntax) [AS tabalias]} }
[CLIENT SPECIFIED]
[UP TO n ROWS]
[BYPASSING BUFFER]
{ INTO {{[CORRESPONDING FIELDS OF] wa}|(dobj1, dobj2, ...)} }
| { INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE itab [PACKAGE SIZE n] }
[[FOR ALL ENTRIES IN itab] WHERE [... col {=|EQ|<>|NE|>|GT|<|LT|>=|GE|<=|LE}itab-comp ... ]
{ { col1 {=|EQ|<>|NE|>|GT|<|LT|>=|GE|<=|LE}
{ {dobj}|{col2}|{[ALL|ANY|SOME] (select … from …)} } }
| {col [NOT] BETWEEN dobj1 AND dobj2}
| {col [NOT] LIKE dobj [ESCAPE esc]}
| {col [NOT] IN (dobj1, dobj2 ...)}
| {col [NOT] IN seltab}
| {col IS [NOT] NULL}
| {(cond_syntax)}
| {[NOT] EXISTS (select … from …)}
| {col [NOT] IN (select … from …)} }]
[GROUP BY { {col1 col2 ...} | (column_syntax) }][HAVING sql_cond]
[ORDER BY { {PRIMARY KEY}
| { col1 [ASCENDING|DESCENDING]
col2 [ASCENDING|DESCENDING] ...}
| (column_syntax) }].
...
[ENDSELECT].
sy-subrc |
Meaning |
0 |
查詢到數據 |
4 |
沒有查詢到數據。聚合函數規則特殊,請參見 |
8 |
如果有WHERE從句后沒有完全指定主鍵字段條件,FOR UPDATE時 |
sy-dbcnt 為查詢到的記錄條數
如果從數據庫讀出來的數據存在重復時,是不能存儲到Unique內表中去的——如Unique的排序表與哈希表
讀取單行
SELECT SINGLE [FOR UPDATE] <cols> ... INTO [CORRESPONDING FIELDS OF] wa WHERE ...
SELECT SINGLE [FOR UPDATE] <cols> ... INTO (dobj1, dobj2, ...) WHERE ...
SINGLE 選項不能用在子查詢中
如果有多條,則返回第一條數據
不能使用APPENDING,並且INTO后面不能接內表
為了確保只讀到一條數據,必須在WHERE語句后面指定所有的primary key,否則語法檢查時會警告
FOR UPDATE只能與SINGLE一起使用,即只能對一條數據進行加exclusive lock鎖。如果產生死鎖,會拋異常
FOR UPDATE會繞過數據庫緩存
DATA wa TYPE spfli.
SELECT SINGLE *
FROM spfli
INTO CORRESPONDING FIELDS OF wa
WHERE carrid = 'LH' AND connid = '0400'.
注:一般使用SINGLE是表示根據表的關鍵字來查詢,這樣才能確保只有一條數據,所以當使用SINGLE時,不能再使用ORDER BY語句(因為沒有必要了),如果查詢時不能根據關鍵字來查詢,但要求在查詢時先排序再取第一條時,我們只能使用另一種語法(其實更好的方式是請參考UP TO n ROWS):
SELECT ... UP TO 1 ROWS ... ORDER BY
...
ENDSELECT.
DISTINCT
If DISTINCT is used, the SELECT statement bypasses SAP buffering
讀取多行
兩種選擇:選擇至內表與循環選擇
選擇至內表:
SELECT [DISTINCT] <cols> ... WHERE ...
循環選擇的語法:
SELECT [DISTINCT]<cols> ...INTO CORRESPONDING FIELDS OF <wa>WHERE ...
...
ENDSELECT.
循環發送SQL語句,每次讀取的結果INTO到一個結構對象里,而不是內表里。.
如果至少讀取到一條數據,在讀取后(以及循環讀取后)SY-SUBRC為0,否則設置為4。讀取到的行會存儲在SY-DBCNT里,如果在SELECT…ENDSELECT循環里,每執行一次 SELECT 語句,SY-DBCNT 都加 1
從技術角度SELECT loops里可以嵌套SELECT loops,但出於性能考慮,一般使用a join in the FROM clause or a subquery in the WHERE clause
DATA wa TYPE spfli.
SELECT *INTO CORRESPONDING FIELDS OF waFROM spfliWHERE carrid EQ 'LH'.
WRITE: / sy-dbcnt,wa-carrid, wa-connid, wa-cityfrom, wa-cityto.
ENDSELECT.
列別名
SELECT col1 [AS <a1>] col2 [AS <a2>] ...
col可以是數據庫表里的字段名,但如果從多個表里聯合查詢時,會有重名的字段,此時只能使用別名[AS <a1>]選項了
col可以是數據庫表里的字段名dbtab~col1 dbtab~col2,這種主要用在多個表查詢同名字段時使用,否則編譯出錯
col還可以是tabalias~col形式,tabalias為數據庫表的別名,需在FROM從句定義
注:使用別名后,別名將會替代INTO 與 ORDERBY 從句中原字段名使用
存儲到指定變量中
SELECT ... INTO (<f1>, <f2>, ...). ...
此情況下要求SELECT從句后面的選擇字段個數與 INTO從句后面的字段列表個數相同(與名稱無關,只與類型相關)
在選擇多個字段時,我們也可以將這些字段一個個插入到簡單變量中,而不存儲到一個結構體中,並且如果要存儲到多個變量中,則需要將這些對象放在括號中:
DATA: wa_carrid TYPE spfli-carrid,
wa_connid TYPE spfli-connid.
SELECT SINGLE carrid connid FROM spfli
INTO (wa_carrid , wa_connid )
WHERE cityfrom = 'NEW YORK' AND cityto = 'SAN FRANCISCO'.
WRITE: wa_carrid,wa_connid.
注意使用種形式中,INTO后面的左括號與變量名之間不能有空格,其他可以有。
DATA: average TYPE p DECIMALS 2,
sum TYPE p DECIMALS 2.
SELECT AVG( luggweight ) SUM( luggweight ) INTO (average, sum) FROM sbook.
也可這樣:
DATA: BEGIN OF luggage,
average TYPE p DECIMALS 2,
sum TYPE p DECIMALS 2,
END OF luggage.
SELECT AVG( luggweight ) AS average SUM( luggweight ) AS sum INTO CORRESPONDING FIELDS OF luggage FROM sbook.
SELECT * INTO…
DATA wa TYPE spfli. "定義成與數據庫表結構相同的結構
SELECT * INTO wa FROM spfli.
WRITE: / wa-carrid ...
ENDSELECT.
注:下面兩種省略INTO時,SELECT從句后面只能是星號*,否則編譯不通過
DATA spfli TYPE spfli.
SELECT * FROM spfli. "如果表名與存儲區結構同名,還可以省略
WRITE: / spfli-carrid ...
ENDSELECT.
TABLES spfli."也可直接使用TABLES語句定義與數據庫表同名的結構
SELECT * FROM spfli.
WRITE: / spfli-carrid ...
ENDSELECT.
追加讀取APPENDING
SELECT ... INTO|APPENDING [CORRESPONDING FIELDS OF] TABLE <itab>…
CORRESPONDING FIELDS OF [WA/TABLE]…
SELECT ... INTO [CORRESPONDING FIELDS OF] <wa> ...
該語句讀取一條數據到結構<wa>中。只能使用SINGLE選項或與ENDSELECT一起使用
如果沒有[CORRESPONDING FIELDS OF]選項,<wa>結構至少要大小或等於SELECT語句選擇所有字段長度,但此時從數據庫中查詢出來的數據存儲到結構<wa>時,與結構中的名稱無關,它會將查詢出來的字段從左到右存儲到到<wa>結構中,WA尾部以前的內容可能不會被修改
如果加上了[CORRESPONDING FIELDS OF]選項選擇,則會將從數據庫查詢出來的字段值存儲到<wa>結構中同名字段中,此種情況是根據SELECT從句選擇字段名與結構<wa>中組件字段名來映射的,SELECT從句所選擇字段個數可以大於或小於、等於<wa>結構中的字段個數。
如果查詢出來的結果只有一列,則WA可以直接是基本類型的無列名的結構
SELECT ... INTO (dobj1, dobj2, ...)
將SELECT后面列按順序依次存入dobj1, dobj2, ...中
DATA wa TYPE spfli.
SELECT carrid connid cityfrom cityto
FROM spfli
INTO (wa-carrid, wa-connid, wa-cityfrom, wa-cityto).
WRITE: / wa-carrid, wa-connid, wa-cityfrom, wa-cityto.
ENDSELECT.
SELECT ... INTO|APPENDING[CORRESPONDING FIELDS OF] TABLE<itab>...
從左到右存儲,或者根據名稱映射存儲:
DATA:BEGIN OF strc OCCURS 10,
mandt LIKE mara-mandt,
matnr1 LIKE mara-matnr,
END OF strc.
"運行時出錯,因為Select了三個字段,但strc只有兩個
"select SINGLE ersda matnr mandt FROM mara INTO strc .
"即使Select了三個字段,strc只有兩個這里不會報錯。結果只將mandt儲存到strc中,因為使用了CORRESPONDING選項
select SINGLE ersda matnr mandt FROM mara INTO CORRESPONDING FIELDS OF strc .
CLEAR strc.
"結果是matnr存儲到 strc-mandt,mandt存儲到 strc-matnr1中,規則是Select的順序與strc中字段聲明順序對應起來(從左到右,與名稱無關)
select SINGLE matnr mandt FROM mara INTO strc .
使用CORRESPONDING FIELDS選項,只是將同名字段進行存儲:
DATA wa_spfli TYPE spfli.
SELECT SINGLE carrid connid
FROM spfli
INTO CORRESPONDING FIELDS OF wa_spfli
WHERE cityfrom = 'NEW YORK' AND cityto = 'SAN FRANCISCO'.
WRITE:wa_spfli-carrid,wa_spfli-connid.
將數據一次性存儲到內表中:
DATA: itab TYPE STANDARD TABLE OF spfli,wa LIKE LINE OF itab.
SELECT carrid connid cityfrom cityto
INTO CORRESPONDING FIELDS OF TABLE itab
FROM spfli
WHERE carrid EQ 'LH'.
]">[PACKAGE SIZE <n>] ...
只能用在SELECT ... ENDSELECT語句間。其作用是防止一次性將大量數據寫入內表時,發生內存溢出問題,所以可以分批來讀取,此種情況下不適使用APPENDING選項
如果使用FOR ALL ENTRIES選項,則可能還是會出現從數據庫中讀取大量數據時出現內存溢出的情況,因為FOR ALL ENTRIES的過程是這樣的:先將所有數據從數據庫中讀取並臨時存儲到了個系統內表中,而PACKAGE SIZE只用於將數據從系統內表中分批讀取出來存儲到目標內表中,所以使用FOR ALL ENTRIES還是可能會出現內存溢出的問題
DATA: wa TYPE spfli,
itab TYPE SORTED TABLE OF spfli WITH UNIQUE KEY carrid connid.
SELECT carrid connid
FROM spfli
INTO CORRESPONDING FIELDS OF TABLE itab
PACKAGE SIZE 3.
LOOP AT itab INTO wa.
WRITE: / wa-carrid, wa-connid.
ENDLOOP.
SKIP 1.
ENDSELECT.
SQL查詢條件
operator比較操作符
SELECT ... WHERE <s><operator><f>...
<f>可能是FROM從句中的某個表的表字段,也可以是數據變量或常量值,或者是具有返回值的子查詢,<operator>比較操作符可以是以下這些:
BETWEEN
... col [NOT] BETWEEN dobj1 AND dobj2 ...
SELECT carrid connid fldate
FROM sflight
INTO CORRESPONDING FIELDS OF TABLE sflight_tab
WHERE fldate BETWEEN sy-datum AND date.
LIKE
SELECT ... WHERE <s>[NOT] LIKE <f> [ESCAPE <h>] ...
“_”用於替代單個字符,“%”用於替代任意字符串,包括空字符串。
可以使用ESCAPE選項指定一個忽略符號h,如果通配符“_”、“%”前面有符號<h>,那么通配符失去了它在模式中的功能,而指字符本身了:
... WHERE FUNCNAME LIKE 'EDIT#_%' ESCAPE '#'.
以“EDIT_”開頭的字符串
IN
SELECT ... WHERE <s>[NOT] IN (<f1>, ......, <fn>) ...
... WHERE CITY IN ('BERLIN', 'NEW YORK', 'LONDON').
如果CITY為IN后面列表中的任何一個時返回true
SELECT ... WHERE <s>[NOT] IN <seltab>...
<seltab>為選擇屏幕中的條件選擇內表
如果選擇內表內容如下(順序不重要):
SIGN OPTION LOW HIGH
----------------------------------------------------------------------
I EQ 01104711
I BT 10000000 19999999
I GE 90000000
E EQ 10000911
E BT 10000810 10000815
E CP 1%2##3#+4++5*
則會生成如下的WHERE 語句:
... ( ID = '01104711' OR ID BETWEEN '10000000' AND '19999999' OR ID >= '90000000' )
AND ID <> '10000911'
AND ID NOT BETWEEN '10000810' AND '10000815'
AND ID NOT LIKE '1#%2##3+4__5%' ESCAPE '#'...
seltab條件內表生成WHERE條件語句的詳細規則可以參考《User Dialogs.docx》中的“SELECT-OPTIONS ---- 選擇內表多條件組合規則”章節。
DATA spfli_wa TYPE spfli.
SELECT-OPTIONS: s_carrid FOR spfli_wa-carrid ,
s_connid FOR spfli_wa-connid .
SELECT SINGLE *
FROM spfli
INTO spfli_wa
WHERE carrid IN s_carrid AND
connid IN s_connid.
SELECT ... WHERE <s>[NOT] IN <subquery>...
子查詢返回的某列的多個值
NOT
SELECT ... WHERE NOT <cond>...
... WHERE ( NUMBER = '0001' OR NUMBER = '0002' ) ANDNOT ( COUNTRY = 'F' OR COUNTRY = 'USA' ).
NULL
SELECT ... WHERE <s> IS [NOT] NULL ...
在數據庫中,有一種字段值為空值(NULL),表示該數據沒有任何數據內容,然而在ABAP中,特定的數據對象都具有初始值,這些初始值可能是一串0或空格等,但不等同與數據庫中的NULL值,因而,在使用ABAP語句向數據庫表中插入數據時,所有的數據字段都不可能是NULL值。但是,在ABAP數據詞典里仍有可能出現空值字段,因為在程序中可以使用Native SQL進行空值設定,用數據詞典工具添加數據條目時也可能出現NULL,但在數據查詢過程中,如果將NULL字段的值讀入到程序變量中,會轉化為ABAP中相應字段的初始值,NULL值會使用以下值替換(更多關於ABAP數據庫表的“空”、“NULL”與“Initial Values”請參考《ABAP Work Note.docx》中的“表字段中的Initial Values”與“關於ABAP中空的概念”章節):
DATENTYP INITIALWERT
_______________________________________________
ACCP ' ' blank
CHAR ' ' blank
CLNT 000
CUKY ' ' blank
CURR 0
DATS 00000000
DEC 0
FLTP 0
INT1 0
INT2 0
INT4 0
LANG ' ' blank
NUMC 0000... for field lenth <= 32
No initial value for field length > 32
QUAN 0
RAW No initial value provided
TIMS 000000
UNIT ' ' blank
VARC No initial value,
since VARC not supported from 3.0 onwards
LRAW No initial value provided
LCHR No initial value provided
使用RANG條件內表進行查詢
條件內表過時定義法:
RANGES seltab FOR dobj [OCCURS n].
其中dobj為已定義的某個變量
新的語法:
DATA: BEGIN OF seltab OCCURS 0,
sign TYPE c LENGTH 1,
option TYPE c LENGTH 2,
low LIKE dobj,
high LIKE dobj,
END OF rtab.
另外,選擇屏幕上SELECT-OPTIONS語句定義的參數就是一個RANG條件內表,可以直接使用在下面WHERE從句中。
通過以上定義RANG條件內表后可以在WHERE語句中如下直接使用:
WHERE … field[NOT] IN seltab …
如果RANG條件內表為空,則INseltab邏輯表達試恆為真
動態指定查詢列
SELECT … (column_syntax) ...
column_syntax可以是character-like data object,或者是標准內表,不區分大小寫
如果column_syntax為initial,則相當於*,會查詢所有列
如果column_syntax是一個帶有表的內表,則語句中的column_syntax還是代表的為表體而不是表頭
DATA: itab TYPE STANDARD TABLE OF spfli WITH HEADER LINE.
DATA: line(72) TYPE c,
list LIKE TABLE OF line.
line = 'CARRID'.
APPEND line TO list.
line = 'CITYFROM CITYTO'.
APPEND line TO list.
"以內表作為動態列
SELECT DISTINCT (list) INTO CORRESPONDING FIELDS OF TABLE itab FROM spfli UP TO 2 ROWS.
LOOP AT itab.
WRITE: / itab-cityfrom, itab-cityto,itab-carrid.
ENDLOOP.
CLEAR: itab[],itab.
"以字符串作為動態列
SELECT DISTINCT (line) INTO CORRESPONDING FIELDS OF TABLE itab FROM spfli UP TO 2 ROWS.
SKIP.
LOOP AT itab.
WRITE: / itab-cityfrom, itab-cityto,itab-carrid.
ENDLOOP.
NEW YORK SAN FRANCISCO DL
FRANKFURT BERLIN LH
BERLIN FRANKFURT
FRANKFURT BERLIN
動態查詢表中指定的某列:
"表中的某列的列名
PARAMETERS comp LENGTH 20.
DATA: dref TYPE REF TO data,
long_name TYPE string,
ftab TYPE TABLE OF string.
FIELD-SYMBOLS <fs>.
long_name = 'spfli-' && comp.
"根據詞典中的類型動態創建數據對象
CREATE DATA dref TYPE (long_name).
"動態創建出來的數據對象需解引用並分配給字段符號才能使用
ASSIGN dref->* TO <fs>.
APPEND comp TO ftab."動態列放在內表中
SELECT DISTINCT (ftab) INTO <fs> FROM spfli WHERE carrid = 'LH'.
WRITE: / <fs>.
ENDSELECT.
動態指定表
SELECT ... FROM (dbtab_syntax)...
column_syntax可以是character-like data object,或者是標准內表,不區分大小寫
如果column_syntax是一個帶有表的內表,則語句中的column_syntax還是代表的為表體而不是表頭
DATA wa TYPE scarr.
DATA name(10) VALUE 'SCARR'.
SELECT * INTO wa FROM (name) CLIENT SPECIFIED WHERE mandt = '000'.
WRITE: / wa-carrid, wa-carrname.
ENDSELECT.
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 (cond_syntax) ...
cond_syntax可以是character-like data object,或者是標准內表。如果為初始值initial,則返回結果為真
如果cond _syntax是一個帶有表的內表,則語句中的cond _syntax還是代表的為表體而不是表頭
動態的條件只能用在WHERE從句中,不能用在ON
下面程序中,內表itab僅包含一個類型C組件且最大長度為72的字段,內表名稱必須在括號中指定。可以將各種邏輯表達式(但除上面的RANG條件內表外)添加到內表行中,且在內表行中的邏輯表達式里只能使用文字不能再使用變量:
DATA: cond(72) TYPE c,
itab LIKE TABLE OF cond,
city1(10) VALUE 'NEW YORK',
city2(13) VALUE 'SAN FRANCISCO',
itab_spfli LIKE TABLE OF spfli WITH HEADER LINE.
CONCATENATE 'cityfrom = ''' city1 '''' INTO cond.
APPEND cond TO itab.
CONCATENATE 'or cityfrom = ''' city2 '''' INTO cond.
APPEND cond TO itab.
SELECT * INTO TABLE itab_spfli FROM spfli WHERE (itab).
LOOP AT itab_spfli.
WRITE: / itab_spfli-carrid, itab_spfli-connid.
ENDLOOP.
另外,WHERE后面也可以使用一個或多個拼接好的查詢條件字符串:
DATA: cond1(72) TYPE c,
cond2(72) TYPE c,
city1(10) VALUE 'NEW YORK',
city2(13) VALUE 'SAN FRANCISCO',
itab_spfli LIKE TABLE OF spfli WITH HEADER LINE.
CONCATENATE 'cityfrom = ''' city1 '''' INTO cond1.
CONCATENATE 'cityfrom = ''' city2 '''' INTO cond2.
SELECT * INTO TABLE itab_spfli FROM spfli WHERE (cond1) OR (cond2).
也可以是一部分是拼接好的查詢條件字符串,一部分是條件table:
DATA: cond(72) TYPE c,
cond1(72) TYPE c,
itab LIKE TABLE OF cond,
city1(10) VALUE 'NEW YORK',
city2(13) VALUE 'SAN FRANCISCO',
itab_spfli LIKE TABLE OF spfli WITH HEADER LINE.
CONCATENATE 'cityfrom = ''' city1 '''' INTO cond1.
CONCATENATE 'cityfrom = ''' city2 '''' INTO cond.
APPEND cond TO itab.
SELECT * INTO TABLE itab_spfli FROM spfli WHERE (itab) or (cond1).
也可以部分是動態的條件:
DATA: cond(72) TYPE c,
itab LIKE TABLE OF cond,
city1(10) VALUE 'NEW YORK',
city2(13) VALUE 'SAN FRANCISCO',
itab_spfli LIKE TABLE OF spfli WITH HEADER LINE.
CONCATENATE 'cityfrom = ''' city2 '''' INTO cond.
APPEND cond TO itab.
SELECT * INTO TABLE itab_spfli FROM spfli WHERE (itab) or cityfrom = city1.
指定集團CLIENT SPECIFIED ...
一般的SAP數據庫表在創建時,屬於特定集團的表都由系統自動生成一個默認的字段MANDT,用於指定數據屬於哪個集團。該字段也是關鍵字段之一。有些系統通用表是與集團無關的。
一般情況下,OPENSQL操作時,系統會自動進行集團處理,系統只從當前集團提取數據,在程序中不能指定MANDT字段,否則出錯。
如果確實需要在程序中指明需要操作的特定集團,則需要使用CLIENT SPECIFIED取消系統的自動處理功能:
SELECT|UPDATE ... <tables>CLIENT SPECIFIED ...
該選項必須跟在數據庫表名稱之后。關閉了系統自動集團處理后,就可以就可以在WHERE條件子句中指定集團字段了。
TABLES spfli.
SELECT SINGLE * FROM spfli CLIENT SPECIFIED WHERE mandt BETWEEN '100' AND'999'.
WRITE spfli-cityto.
禁止使用緩沖BYPASSING BUFFER ...
可以在數據字典Technical settings中進行設定。如果對已經進行了緩沖設定的數據庫表,系統將在首次數據查詢操作的同時進行數據緩沖。不同的緩沖之間或緩沖與數據庫表本身間的同步過程則數據接口完成。
SELECT語句中的FROM子句的BYPASSING BUFFER附加項,可以用於在特殊情況下禁止緩沖。此外,DISTINCT附加項與聯合查詢、總計選擇、IS NULL條件、子查詢,以及GROUPBY和ORDER BY同時使用時,也將自動忽略緩沖設定。
SELECT ... FROM <tables>BYPASSING BUFFER ...
">限定選擇行數UP TO n ROWS ...
SELECT ... FROM <tables>UP TO <n> ROWS ...
如果n為正數,系統最多選擇n行到程序中,如果n為0,則還是選擇所有滿足條件的數據。如果同時使用ORDER BY 選項,則系統首先選出所有滿足條件的數據,並排序,然后將頭n行作為選擇結果。
注:一般使用SINGLE是表示根據表的關鍵字來查詢,這樣才能確保只有一條數據,所以當使用SINGLE時,不能再使用ORDER BY語句(因為也沒有必要了),如果查詢時不是根據關鍵字來查詢,且查詢時先排序再取一條時,我們只能使用另一種語法:
SELECT * FROM tj02t INTO CORRESPONDING FIELDS OF TABLE gt_result UP TO 1 ROWS WHERE SPRAS = 'E'
ORDER BY ISTAT .
SELECT語句嵌套
DATA: wa_carrid TYPE spfli-carrid,
wa_connid TYPE spfli-connid,
wa_carrname TYPE scarr-carrname.
SELECT carrid connid FROM spfli INTO (wa_carrid, wa_connid) WHERE
cityfrom = 'NEW YORK'.
SELECT carrname FROM scarr INTO wa_carrname
WHERE carrid = wa_carrid.
WRITE wa_carrname.
ENDSELECT.
ENDSELECT.
每當在表SPFLI中查詢到一個符合條件值,系統就重新對SCARR進行一次查詢,這與標准SQL相關子查詢類似。
FOR ALL ENTRIES選項
SELECT ... FOR ALL ENTRIES IN <itab> WHERE <cond>...
該選項拿<itab>每一條數據到數據庫表中查詢,並且將查詢出來的結果集使用合並並返回。重復的數據會自動剔除。如果<itab>為空,則會忽略該條件(即使Where后面還有其它條件,所有的條件都會忽略),即查詢出所有數據。<cond>條件語句中不能使用LIKE, BETWEEN, IN這些操作符,只能使用比較操作符
該選項的作用與Selection Options是類似的
為了避免多次重復數據查詢(嵌套查詢效率很低),可以先將SPFLI中符合條件的數據選進一個內表,然后僅根據該內表中包含的carrid字段繼續查詢表scarr,這樣最多只發送兩次查詢,而不是1+N次查詢。
選出符合已存在內表中所有滿足條件的數據值:
FOR ALL ENTRIES對於以下兩種情況會忽略SAP bufferung:
l Tables with single record buffering.
l Tables with generic buffering if the condition after FOR ALL ENTRIES prevents precisely one generic area from being specified exactly.
1、使用該選項后,對於最后得出的結果集系統會自動刪除重復行(具有DISTINCT選項的作用,但與DISTINCT不同的是,這個去除重復的動作是在將所有數據從數據庫中講到到SAP應用服務器后進行刪除的,而不是在數據庫系統里去除的,這是因為FOR ALL ENTRIES在執行查詢時,可能會分成多個SQL語句,所以只能將多次讀取的數據合並后進行去除)。因此如果你要保留重復行記錄時,記得在SELECT語句中添加足夠鍵值項目(有必要時,增加所有所查表的所有主鍵),以保證結果集中所需重復項目不會被刪除。
2、FOR ALL ENTRIES IN后面使用的內部表itab如果為空,系統將視為無條件選取(即忽略WHERE語句),將當前CLIENT下所有記錄選出,因此為避免無意義的全件檢索,在使用該語句前一定要判斷內部表itab是否為空,為空時不執行包含該語句的數據庫檢索處理
3、由於itab-f實際上是作為占位符被替換,所以內部表itab中不要帶HEADER行,以免造成混淆,檢索出錯
4、內表中的條件字段不能使用LIKE,BETWEEN,IN比較操作符。因為這些比較操作符都是不確定比較操作符(將選擇條件設定在一個范圍內),而FOR ALL ENTRIES IN語句的作用相當於將選擇條件塊全部並列開來,用OR連接,如果每個OR分支中又是不確定的范圍,那么系統性能將大大降低,因此R/3系統在使用該語句時禁止使用不確定比較操作符。
5、使用該語句時,ORDER BY語句和HAVING語句將不能使用。
6、使用該語句時,除COUNT( * )(並且如果有了COUNT函數,則不能再選擇其他字段,只能使用在Select ... ENDSelect語句中了)以外的所有合計函數(MAX,MIN,AVG,SUM)都不能使用。
DATA: tab_spfli TYPE TABLE OF spfli,
tab_sflight TYPE SORTED TABLE OF sflight WITH UNIQUE KEY TABLE LINE,
wa LIKE LINE OF tab_sflight.
SELECT carrid connid
INTO CORRESPONDING FIELDS OF TABLE tab_spfli
FROM spfli
WHERE cityfrom = 'NEW YORK'.
SELECT carrid connid fldate
INTO CORRESPONDING FIELDS OF TABLE tab_sflight
FROM sflight
FOR ALL ENTRIES IN tab_spfli
WHERE carrid = tab_spfli-carrid AND connid = tab_spfli-connid.
LOOP AT tab_sflight INTO wa.
AT NEW connid.
WRITE: / wa-carrid, wa-connid.
ENDAT.
WRITE: / wa-fldate.
ENDLOOP.
注意:FOR ALL ENTRIES所使用的內表里一定要有數據,否則查詢時會將表中的所有數據都查詢出來,即使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都會被忽略掉。
TABLES: mara.
DATA: BEGIN OF strc OCCURS 0,
matnr LIKE mara-matnr,
lvorm LIKE mara-lvorm,
END OF strc.
SELECT-OPTIONS: s_matnr FOR mara-matnr.
START-OF-SELECTION.
SELECT matnr FROM mara
INTO CORRESPONDING FIELDS OF TABLE strc
FOR ALL ENTRIES IN strc WHERE matnr = strc-matnr .
當內表strc為空時,上面Select語句生成的標准SQL如下:
SELECT
"MATNR"
FROM
"MARA"
WHERE"MANDT" = '210'
內表strc不為空時,生成的SQL如下:
strc-matnr = '000000000000000101'.
APPEND strc.
strc-matnr = '000000000000000103'.
APPEND strc.
strc-matnr = '000000000000000104'.
APPEND strc.
START-OF-SELECTION.
SELECT matnr FROM mara
INTO CORRESPONDING FIELDS OF TABLE strc
FOR ALL ENTRIES IN strc WHERE matnr = strc-matnr .
SELECT
"MATNR"
FROM
"MARA"
WHERE "MANDT" = '210' AND "MATNR" IN ( '000000000000000101' , '000000000000000103' , '000000000000000104' )
注:這里看上去FOR ALL ENTRIES使用 IN 表達式來代替了,這是只有使用到內表中一個條件是這樣的,如果使用多個條件時,不會使用In表達式,而是使用OR連接,像這樣:
另外,在使用FOR ALL ENTRIES時,不管使用了條件內表中的一個還是多個條件字段,都會以5個值為單位進行SQL發送,但RANGE可以達到3000左右
內表strc不為空時,且在Where后面加上了另外的條件:
strc-matnr = '000000000000000101'.
APPEND strc.
strc-matnr = '000000000000000103'.
APPEND strc.
strc-matnr = '000000000000000104'.
APPEND strc.
START-OF-SELECTION.
SELECT matnr FROM mara
INTO CORRESPONDING FIELDS OF TABLE strc
FOR ALL ENTRIES IN strc WHERE matnr = strc-matnr and ERNAM = 'XUJIJING'.
SELECT
"MATNR"
FROM
"MARA"
WHERE "MANDT" = '210' AND "MATNR" IN ( '000000000000000101' , '000000000000000103' , '000000000000000104' ) AND "ERNAM" = 'XUJIJING'
內表strc為空時,且在Where后面加上了另外的條件:
SELECT
"MATNR"
FROM
"MARA"
WHERE "MANDT" = '210'
聯合查詢
使用JOIN時,會繞過SAP緩存,可以使用FOR ALL ENTRIES來代替
ON后面的條件與Where條件類似,但有以下不同:
ü 必需要有ON,也就是說必須要有一個條件,且多個條件之間只能使用AND連接
ü 所有條件表達式中兩個操作數之間必須有一個是來自於JOIN右邊表dbtab_right的某個字段
ü 不能使用NOT, LIKE, IN(但如果是 INNER JOIN,則>、<、BETWEEN …AND、<>都可用)
ü 如果是INNER JOIN,也可把ON從句中的<cond>條件置於WHERE子句中(Left Outer Join是有所區別的,請參見后面),因為二者效果一樣
ü 如果是LEFT OUTER JOIN,則只能使用等號操作符:(=, EQ)
ü 如果是LEFT OUTER JOIN,則至少有一個條件表達式的兩個操作數一個是來自於左邊表dbtab_left,另一個來自右邊表dbtab_right
ü 如果是LEFT OUTER JOIN,則只能與同一個左表進行連接(關聯),即每個條件表達式兩個操作數中除了一個已固定來自於右邊表dbtab_right外(不管是Inner,還是Left,因為所有ON后面每個條件中必須要有一個是來自於右邊表dbtab_right中的字段),所有條件表達式中另外一個操作數(在另一操作數非dbtab_right字段的情況下,如果另一操作數就是dbtab_right某個字段或某個常量時,就另當別論了)必須來自於同一個左邊表dbtab_left,即LEFT OUTER JOIN只能與一個dbtab_left發生關聯關系(即在ON條件中所有表達試中的左表只能出現同一個,不能出現第二個,如下所示:)
ü 如果是LEFT OUTER JOIN,同一右表dbtab_right不能出現在不同的LEFT OUTER JOIN(在一個Select語句中LEFT JOIN可以多次出現,關聯不同的表)的條件表達式中:
ü LEFT OUTER JOIN右邊表dbtab_right的所有字段不能出現在WHERE中(如果出現在WHERE從句好像沒有什么意義了,此時與INNER JOIN相當),只能出現在ON條件從句中(可以將從表的條件寫在On后面而不是Where后面來解除這個限制,但是,Left join的條件放在on 與 where后面是不一樣的,請看后面的示例)
SELECT ...FROM <tab> [INNER] JOIN <dbtab> [AS <alias>] ON <cond>
DATA: BEGIN OF wa,
carrid TYPE spfli-carrid,
connid TYPE spfli-connid,
fldate TYPE sflight-fldate,
bookid TYPE sbook-bookid,
END OF wa,
itab LIKE SORTED TABLE OF wa WITH UNIQUE KEY carrid connid fldate bookid.
SELECT p~carrid p~connid f~fldate b~bookid
INTO CORRESPONDING FIELDS OF TABLE itab
FROM ( ( spfli AS p
INNER JOIN sflight AS f ON p~carrid = f~carrid AND p~connid = f~connid )
INNER JOIN sbook AS b ON b~carrid = f~carrid AND b~connid = f~connid AND b~fldate = f~fldate )
WHERE p~cityfrom = 'FRANKFURT' AND p~cityto = 'NEW YORK' AND f~seatsmax > f~seatsocc.
SELECT ...FROM <tab> LEFT [OUTER] JOIN <dbtab> [AS <alias>] ON <cond>
DATA: BEGIN OF wa,
carrid TYPE scarr-carrid,
carrname TYPE scarr-carrname,
connid TYPE spfli-connid,
END OF wa,
itab LIKE SORTED TABLE OF wa WITH NON-UNIQUE KEY carrid.
SELECT s~carrid s~carrname p~connid
INTO CORRESPONDING FIELDS OF TABLE itab
FROM scarr AS s
LEFT OUTER JOIN spfli AS p ON s~carrid = p~carrid AND p~cityfrom = 'FRANKFURT'.
數據庫在通過連接兩張或多張表來返回記錄時,都會生成一張中間的臨時表,然后再將這張臨時表返回給用戶。在使用left jion時,on和where條件的區別如下:
1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
2、where條件是在臨時表生成好后,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉。
假設有兩張表:
表1:tab1
id |
size |
1 |
10 |
2 |
20 |
3 |
30 |
表2:tab2
size |
name |
10 |
AAA |
20 |
BBB |
20 |
CCC |
兩條SQL:
1、select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’
2、select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)
第一條SQL的過程:
|
||||||||||||||||||||||||||||||||||||
第二條SQL的過程:
|
其實以上結果的關鍵原因就是left join,right join,full join的特殊性,不管on上的條件是否為真都會返回left或right表中的記錄,full則具有left和right的特性的並集。而inner join沒這個特殊性,則條件放在on中和where中,返回的結果集是相同的(但放在ON后面的效率會高一些)。
子查詢
使用子查詢時會繞過SAP buffering
有時只需從一個表中選擇數據,但這些數據與其他表中的數據字段內容相關聯,但又不需將其它表中相關的數據查出來,類似操作可通過子查詢進行。子查詢是沒有SINGLE, INTO, and ORDER BY的查詢語句,通過col operator [ALL|ANY|SOME] 、EXISTS、IN連接至WHERE從句與HAVING從句中(但不能出現在ON從句中):
l col operator [ALL|ANY|SOME] ( SELECT …FROM … )
l [NOT] EXISTS ( SELECT …FROM … )
l [NOT] IN ( SELECT …FROM … )
子查詢可以嵌套,但不能用於pool tables 、cluster tables兩種表
ALL、ANY、SOME子查詢
這種子查詢的SELECT從句中只有一個表字段或者是一個統計列
... <s><operator><subquery> ...
要求子查詢只能返回一條數據(否則運行時出錯),所以<subquery>一般是一個SELECT SINGLE的子查詢。
如果子查詢的結果只有一條數據時,可以省略[ALL|ANY|SOME]選項:
DATA wa_sflight TYPE sflight.
SELECT *
FROM sflight
INTO wa_sflight
WHERE seatsocc = ( SELECT MAX( seatsocc ) FROM sflight ).
ENDSELECT.
如果子查詢返回的是多條,則可以使用以下子查詢:
... <s><operator>ALL|ANY|SOME <subquery> ...
l 如果使用ALL,則如果子查詢返回的所有行都滿足<operator>比較條件時,才為真
l 如果使用ANY|SOME,則如果子查詢返回的所有行中只要有一條滿足<operator>比較條件時,就會為真
l 比較操作符(= or EQ)與ANY|SOME一起使用時,與IN操作符具有一樣的效果
DATA: id TYPE sbook-customid,
cnt TYPE i.
SELECT customid COUNT( * )
FROM sbook
INTO (id, cnt)
GROUP BY customid
HAVING COUNT( * ) >= ALL ( SELECT COUNT( * )
FROM sbook
GROUP BY customid ).
ENDSELECT.
[NOT] IN子查詢
此類子查詢SELECT從句中也只有單獨的一列選擇列,但查詢出的結果可能有多個。與[NOT] IN一起使用
DATA: carr_id TYPE spfli-carrid VALUE 'LH',
conn_id TYPE spfli-connid VALUE '0400'.
DATA: city TYPE sgeocity-city,
lati TYPE p DECIMALS 2,
longi TYPE p DECIMALS 2.
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 ).
WRITE: city, lati, longi.
[NOT] EXISTS子查詢
這類子查詢沒有返回值,也不要求SELECT從句中只有一個選擇列,選擇列可以任意個數,WHERE or HAVING從句來根據該子查詢的是否查詢到數據來決定外層主查詢語句來選擇相應數據
該類子查詢只能與[NOT] EXISTS一起使用:
DATA: name_tab TYPE TABLE OF scarr-carrname,
name LIKE LINE OF name_tab.
SELECT carrname INTO TABLE name_tab FROM scarr
WHERE EXISTS ( SELECT * FROM spfli
WHERE carrid = scarr~carrid
AND cityfrom = 'NEW YORK' ).
LOOP AT name_tab INTO name.
WRITE: / name.
ENDLOOP.
此子查詢又為相關子查詢
如果某個子查的WHERE條件中引用了外層查詢語句的列,則稱此子查詢為相關子查詢。相關子查詢對外層查詢結果集中的每條記錄都會執行一次,所以盡量少用相關子查詢
統計函數
SELECT <lines><agg>( [DISTINCT] <s1> ) [AS <a1>]<agg>( [DISTINCT] <s2> ) [AS <a2>] ...
MAX、MIN、AVG、SUM、COUNT
聚合函數都可以加上DISTINCT選項
MAX, MIN, or SUM計算的結果類型為相應表字段的類型
AVG計算的結果類型為數據詞典類型FLTP,在ABAP程序里可以使用F類型來接收
COUNT have the Dictionary type INT4.
DATA: BEGIN OF luggage,
average TYPE p DECIMALS 2,
sum TYPE p DECIMALS 2,
END OF luggage.
SELECT AVG( luggweight ) AS average SUM( luggweight ) AS sum
INTO CORRESPONDING FIELDS OF luggage
FROM sbook.
SELECT carrid connid SUM( seatsocc )
FROM sflight
INTO (wa_carrid, wa_connid, sum_seat)
WHERE spfli~cityform = `sing`
分組
SELECT <lines><s1> [AS <a1>] <s2> [AS <a2>] ...
<agg><sm> [AS <am>] <agg><sn> [AS <an>] ...
...
GROUP BY <s1><s2> ....
GROUP BY后面還可以是動態指:... GROUP BY (<itab>) ...這里的<itab>是一個具有列寬為72 C Type的內表,只有一個字段,且存儲了分組的字段名,如上面的<s1><s2>
如果將統計函數與GROUP BY子句一起使用,那么Select語句中未出現在統計函數的數據庫字段都必須在GROUP BY子句中出現(如這里的<s1>、<s2>)。如果使用INTO CORRESPONDING FIELDS項,則需要在Select語句中通過AS后面的別名將統計結果存放到與之相應同名的內表字段中。
DATA : carrid TYPE sflight-carrid,
minimum TYPE p DECIMALS 2,
maximum TYPE p DECIMALS 2.
WRITE: / `Carrier ID`,
AT 15 `Minimum Price`,
AT 30 `Maximum Price`.
SELECT carrid MIN( price ) MAX( price )
INTO (carrid,minimum,maximum)
FROM sflight
GROUP BY carrid.
WRITE: / carrid, minimum, maximum.
ENDSELECT.
Carrier ID Minimum Price Maximum Price
LH 899.00 6,000.00
SQ 849.00 849.00
分組過濾
只有使用GROUP BY子句時,才能出現HAVING。
SELECT <lines><s1> [AS <a1>] <s2> [AS <a2>] ...
<agg><sm> [AS <am>] <agg><sn> [AS <an>] ...
...
GROUP BY <s1><s2> ....
HAVING <cond>.
像WHERE動態條件從句一樣,也可以使用動態的條件
SELECT carrid min( price ) as m max( price )
INTO (carrid, minimum, maximum)
from sflight
group by carrid
HAVING MAX( price ) > 10.
WRITE: / carrid, minimum, maximum.
ENDSELECT.
排序
注:SELECT SIGLE不能與ORDER BY一起使用
根據關鍵字排序:
SELECT *
...
... ORDER BY PRIMARY KEY.
注:... ORDER BY PRIMARY KEY只能用在從單表中查詢時使用
指定排序字段,默認為升序:
SELECT ...
...
ORDER BY <s1> [ASCENDING|DESCENDING]
<s2> [ASCENDING|DESCENDING] ...
動態指定排序列:
SELECT ...
...
ORDER BY (column_syntax).
column_syntax為Initial時,則會忽略
DATA: BEGIN OF wa,
carrid TYPE sflight-carrid,
connid TYPE sflight-connid,
min TYPE i,
END OF wa.
SELECT carrid connid MIN( seatsocc ) AS min
INTO CORRESPONDING FIELDS OF wa
FROM sflight
GROUP BY carrid connid
ORDER BY carrid min DESCENDING.
WRITE: / wa-carrid, wa-connid, wa-min.
ENDSELECT.
通過游標讀取數據
在通常的SELECT語句中,滿足查詢條件的所有數據都是一次性從數據庫中讀取出來放在INTO子句指定的目標區域中,這樣做會帶來一個問題:這些數據從數據庫讀取出來然后一條條APPEND到內表中,這一過程也需要花費時間。如果使用游標,則會解決SELECT語句的一些處理開銷,使用游標時,可以將數據行直接放到一個扁平的結構體對象中。
1. 打開游標
OPEN CURSOR [WITH HOLD] <c>FOR SELECT <result>
FROM <source>
[WHERE <condition>]
[GROUP BY <fields>]
[HAVING <cond>]
[ORDER BY <fields>].
游標不能用於SINGLE選項的SELECT語句。在數據庫提交時,系統將自動關閉光標,一個例外情況是如果在OPEN CURSOR語句中使用了WITH HOLD選項時,則Native SQL數據庫提交將不會關閉光標。
<C>必須是一個使用DATA語句定義的具有CURSOR類型的變量
2. 讀取數據
FETCH NEXT CURSOR<c> INTO <target>.
<target>為扁平的結構對象
如果讀取到數據,則SY-SUBRC to 0, otherwise to 4. After a FETCH statement, the system field SY-DBCNT contains the number of lines already read by the current cursor.
3. 關閉游標
CLOSE CURSOR <c>.
DATA: c TYPE cursor.
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.
更新數據
INSERT
INSERT
{INTO {dbtab|(dbtab_syntax)} [CLIENT SPECIFIED] VALUES wa}
| {{dbtab|(dbtab_syntax)} [CLIENT SPECIFIED] FROM wa|{TABLE itab [ACCEPTING DUPLICATE KEYS]}}
插入單條:
INSERT INTO <tabname> VALUES <wa>.
或
INSERT <tabname> FROM <wa>.
或
INSERT <tabname>.
在插入時是按照數據庫表結構來解析<wa>結構,與<wa>中的字段名無關,所以<wa>的長度只少要等於或大於所對應表結構總長度
工作區wa是與數據表具有相同結構的數據對象,一般直接基於數據表結構聲明。FROM這種格式在以下這種情況下可以省略(此方式下不允許使用動態指定表):
TABLES:mard.
INSERT mard.
如果插入成功,SY-SUBRC為0,否則為4
TABLES spfli.
DATA wa TYPE spfli.
wa-carrid = 'LH'.
wa-cityfrom = 'WASHINGTON'.
INSERT INTO spfli VALUES wa.
wa-carrid = 'UA'.
wa-cityfrom = 'LONDON'.
INSERT spfli FROM wa.
spfli-carrid = 'LH'.
spfli-cityfrom = 'BERLIN'.
INSERT spfli.
插入多行:
INSERT dbtab FROM TABLE itab.
其中內表itab中包含希望插入的數據條目,該內表的行結構也必須和數據庫表的行結構一致。如果所有數據都插入成功,則SY-SUBRC返回0,如果有一條不成功,則所有數據都不會插入,但使用下面的插入語句可以避免部分不成功的問題:
INSERT<tabname>FROM TABLE <itab> [ACCEPTING DUPLICATE KEYS].
其中ACCEPTING DUPLICATE KEYS選項的效果是:如果現出關鍵字相同條目,系統將SY-SUBRC返回4,並跳過該條目,但其他數據會插入進去。
SY-DBCNT存儲了插入成功的條數,而不管SY-SUBRC的值是什么
DATA: itab TYPE HASHED TABLE OF spfli WITH UNIQUE KEY carrid connid,
wa LIKE LINE OF itab..
"假設下面兩條數據在數據庫中都不存在
wa-carrid = 'UD'.
wa-connid = '0011'.
wa-cityfrom = 'ZH'.
INSERT wa INTO TABLE itab.
INSERT spfli FROM TABLE itab.
WRITE:/ sy-subrc, sy-dbcnt.
wa-carrid = 'AD'.
wa-connid = '4574'.
wa-cityfrom = 'EN'.
INSERT wa INTO TABLE itab.
INSERT spfli FROM TABLE itab ACCEPTING DUPLICATE KEYS.
WRITE:/ sy-subrc, sy-dbcnt.
UPDATE
UPDATE {dbtab|(dbtab_syntax)} [CLIENT SPECIFIED]
{ {SET [col1 = f1 col2 = f2 ... ]
[col1 = col1 + f1 col2 = col2 + f2 ...]
[col1 = col1 - f1 col2 = col2 - f2 ...]
[(expr_syntax1) (expr_syntax2) ...] [WHERE sql_cond]}
| {FROM wa|{TABLE itab}} }
expr_syntax1:動態指定修改表達式,可以是character-like data object or a standard table,如果為Initail則忽略
sql_cond:請參考SELECT語句中的WHERE從句用法(但不適用FOR ALL ENTRIES條件)
更新單條:
UPDATE dbtab FROM wa.
系統將根據工作區中表關鍵字段primary key(而不是內表行的關鍵字段)的值定位數據行,並使用所有非關鍵字段的值將該行進行更新。
工作區wa的寬度必須大於或等於數據庫表寬度,會按照數據庫表結構從前往后來解析wa各字段,與名稱無關
如果數據庫中有一個wa中primary key相同的數據,則SY-SUBRC為0,否則SY-SUBRC為4
或者:
TABLES:mard.
UPDATE mard.
注:此方式不能動態指定表名
"CARRID 與 CONNID為spfli的主鍵
DATA wa TYPE spfli.
MOVE 'AA' TO wa-carrid.
MOVE '0064' TO wa-connid.
MOVE 'WASHINGTON' TO wa-cityfrom.
UPDATE spfli FROM wa.
TABLES spfli.
MOVE 'LH' TO spfli-carrid.
MOVE '0017' TO spfli-connid.
MOVE 'BERLIN' TO spfli-cityfrom.
UPDATE spfli.
更新多行:
UPDATE dbtab FROM TABLE itab.
對於每一個內表行,都根據表關鍵字段要更改的數據,並更改其他非關鍵字段的值,如果所有內表行都更新成功,SY-SUBRC返回0,只要有一條未成功,則返回4(但沒有問題的數據行還是會被更新)。SY-DBCNT存儲了被修改的行數。如果內表itab為空,則SY-SUBRC and SY-DBCNT都會為0。
"CARRID 與 CONNID為spfli的主鍵
DATA: itab TYPE HASHED TABLE OF spfli WITH UNIQUE KEY carrid connid,
wa LIKE LINE OF itab.
wa-carrid = 'UA'.
wa-connid = '0011'.
wa-cityfrom = 'ZH'.
INSERT wa INTO TABLE itab.
wa-carrid = 'LH'.
wa-connid = '1245'.
wa-cityfrom = 'EN'.
INSERT wa INTO TABLE itab.
UPDATE spfli FROM TABLE itab.
更新指定列:
UPDATE dbtab SET f1 = g1 … fi = gi WHERE<conditions>.
WHERE子句后面可以是所有表關鍵字段,也可以不是,但如果只是更新一條,則條件需要使用所有表關鍵字段。SET子句中只能為非關鍵字段。對於數據字段,除 f = g 外,還可以使用 f = f + g、f = f - g兩種形式在該字段原有值基礎上增減。如果至少有一條數據被更新,則SY-SUBRC返回0,否則返回4。SY-DBCNT中存儲了修改的行數
注:此種方式不能動態指定表
UPDATE sflight
SET planetype = 'A310' price = price - '100.00'
WHERE carrid = 'LH' AND connid = '0402'.
DELETE
DELETE { {FROM {dbtab|(dbtab_syntax)} [CLIENT SPECIFIED] [WHERE sql_cond]}
|{{dbtab|(dbtab_syntax)} [CLIENT SPECIFIED] FROM wa|{TABLE itab}} }.
sql_cond:請參考SELECT語句中的WHERE從句用法(但不適用FOR ALL ENTRIES條件)
刪除單行
DELETEdbtab FROM wa.
從數據庫表中刪除表關鍵字段與工作區wa中相應字段相同的行。工作區的長度至少要等於數據庫表的產關鍵字段長度。
如果數據庫中存在這樣的數據,則SY-SUBRC為0,否則SY-SUBRC為4
或者省略wa:
TABLES:mard.
DELETE mard.
注:此方式不能動態指定表名
"CARRID 與 CONNID為spfli的主鍵
DATA: BEGIN OF wa,
carrid TYPE spfli-carrid,
connid TYPE spfli-connid,
END OF wa.
MOVE 'AA' TO wa-carrid.
MOVE '0064' TO wa-connid.
DELETE spfli FROM wa.
TABLES spfli.
MOVE 'LH' TO spfli-carrid.
MOVE '0017' TO spfli-connid.
DELETE spfli.
刪除多行
DELETE dbtab FROM TABLE itab.
根據表主鍵來刪除itab中相同的數據行
如果所有行都被刪除,SY-SUBRC為0,否則為4。SY-DBCNT存儲了被刪除的條數。如果內表itab為空,則SY-SUBRC 與 SY-DBCNT都為0。
"CARRID 與 CONNID為spfli的主鍵
DATA: BEGIN OF wa,
carrid TYPE spfli-carrid,
connid TYPE spfli-connid,
END OF wa,
itab LIKE HASHED TABLE OF wa WITH UNIQUE KEY carrid connid.
wa-carrid = 'UA'.
wa-connid = '0011'.
INSERT wa INTO TABLE itab.
wa-carrid = 'LH'.
wa-connid = '1245'.
INSERT wa INTO TABLE itab.
DELETE spfli FROM TABLE itab.
刪除單行或多行
DELETE FROM dbtab WHERE<conditions>.
If at least one line is deleted, the system sets SY-SUBRC to 0, otherwise to 4. SY-DBCNTcontains the number of lines deleted.
DELETE FROM sflight WHERE planetype = 'A310' AND carrid = 'LH'.
MODIFY(插入或修改)
MODIFY {dbtab|(dbtab_syntax)} [CLIENT SPECIFIED] FROM wa|{TABLE itab}.
MODIFY相當於INSERT與UPDATE的結合。當使用MODIFY語句操作數據庫時,如果程序中指定的數據行已經存在數據庫中(根據表關鍵字判斷)則對其進行更新操作,如果不存在,則進行插入操作。
插入或更新單行
MODIFY dbtabFROM wa.
根據工作區wa中的表關鍵字段來定位要修改的數據,如果不存在,則插入。工作區wa的寬度也要大於或等於表結構的所有字段表寬度
MODIFY<dbtab>.
SY-SUBRC總是為0
插入或更新多行
MODIFY dbtab FROM TABLE itab.
根據內表中的每一行表關鍵字段來查找數據是否存在,如果不存,則會插入。
SY-SUBRC總是為0,SY-DBCNT為內表行數
其他技術
使用表工作區Interface work areas
表工作區是接口工作區的一種,使用TABLES語句聲明:
TABLES dbtab.
該語句會根據數據庫中表(或視圖、或ABAP Dictionary中定義的structure)名為dbtab的表來創建一個同名的結構,組成該結構的內表字段類型與參考的表(或視圖、structure)相同。
在4.0版以前,使用Open SQL訪問表時,一定要先使用該語句來聲明Interface work areas,現在不需要了,但是,你仍然需要使用該語句來使屏幕input/output字段參考相應的數據庫表,在PBO事件里,ABAP程序會將字段內容傳遞到相應的屏幕字段中,在PAI事件時,屏幕上的字段會存儲到ABAP程序中對應Interface work areas中的相應字段中(具體可以參照《User Dialogs.docx》中的<示例:屏幕元素自動參考數據詞典>章節)。
在指定了表工作區之后,在使用SELECTSINGLE語句時可以省略INTO子句(INTO到TABLE時不能省略),系統默認將數據行讀取到同名變量的表工作區中。
TABLES spfli.
SELECT SINGLE * FROM spfli WHERE cityfrom = 'NEW YORK'.
WRITE: spfli-cityto.
操作時間分析(類似System.currentTimeMillis()方法)
GET RUN TIME FIELD <f>.
其中f應為I類型的字段,系統返回從程序開始后的毫秒數。
DATA: t1 TYPE i,
t2 TYPE i,
t TYPE i.
GET RUN TIME FIELD t1.
TABLES: spfli.
SELECT SINGLE * FROM spfli CLIENT SPECIFIED WHERE mandt BETWEEN '100' AND '999'.
GET RUN TIME FIELD t2.
t = t2 - t1.
WRITE: / t.
如果需要全面性能分析,可以使用SE30
數據庫優化
1、 優先使用多表聯接,不使用內嵌Select
2、 Joins方式聯合查詢不會使用到緩存,所以盡量少用,可以使用ABAP Dictionary view來替換。創建ABAP Dictionary view來代替從物理表中讀取
3、 使用內表FOR ALL ENTRIES查詢選項代替內嵌Select。FOR ALL ENTRIES是一種與聯結和數據庫視圖相似的多表操作方式,但是其性能不如聯結和數據庫視圖好。
4、 INSERT, UPDATE, and DELETE時,使用內表的方式來減少與數據庫交互次數
5、 使用游標讀取數據,這樣省掉了將從數據庫中的取記錄放入內表的INTO語句這一過程開銷。
6、 避免全表掃描,在WHERE orHAVING從句中使用索引字段進行查詢。
R/3 System會自動為primary index(主鍵索引,也叫第一索引)創建UNIQUE主鍵索引。如果在WHERE orHAVING從句中未使用到primary index fields,則不會使用到主鍵索引。此時可以通過ABAP Dictionary來創建第二索引(可以是unique的,也可以是非唯一索引)
在創建索引時,索引字段不能在其他索引中使用過(即索引字段不要重疊),否則性能會很差。另外,只能那些經常讀取的表進行創建索引,而那些經常需要更新的表,則不適合創建索引,因為在數據更新時同時會更新索引。最后,索引創建時不多於4個字段,一個表上的創建的索引不要超過5個。
在需要經常訪問的字段上創建索引,並且將重復數據最少的字段放在索引最開頭的規則來確定索引中字段順序。要在重復率少的字段上創建索引,而不應該在重復率高的字段上創建索引
7、 除了主鍵字段,如果一個表的某些字段被SELECT語句頻繁訪問,則考慮基於這些字段建立第二索引。注:一個表的不是越多越好,使用創建不當的第二索引進行查詢可能導致比不使用該索引進行查詢更差的性能
8、 組成索引的所有字段都要用到,並且使用的是“=”表達式,而且各個表達式使用“AND”連接時,查找效率會最高。
9、 在條件從句中不要使用否定的邏輯表達式,如NE(<>)、NOT LIKE,因為這樣數據庫不會使用索引,所以要使用肯定操作比較操作符,如EQ、LIKE。另外,如果可能,避免在WHERE從句中使用NOT操作符,因為數據庫不會用到索引。
10、 不要使用OR來連接多個索引字段表達式,OR后面的表達式中的字段將不會用到索引,看是否能使用IN操作符轉換
11、 使用部分索引要注意的問題:如果一個索引是由多個字段組成的,你可以只使用一部分字段來進行查詢時,也可以使用到索引,但使用時要注意要按照索引定義的順序來使用,如定義時為 a,b,c,d,e 五個字段組成的索引,當使用c,d來查詢時,查詢條件前面也一定要帶上a,b查詢條件字段,所以當只按c,d兩個字段查詢,是用不到索引的(好像只要按物理順序寫,是可以用到索引的???)。
12、 在WHERE條件語句中,要將索引字段條件寫在最前面(左邊),非索引字段寫在最后面,這樣查詢時效率會高些
13、 最好不要將允許為NULL值的字段作為索引字段,因為某些數據庫不會將NULL值存儲到索引表中。
14、 一般不要使用ORDER BY,除非ORDER BY所使用的索引與WHERE語句所使用的索引一樣。此時可以將數據讀到內表后,對內表進行排序
使用Buffer Tables
你可以通過訪問服務器上的Buffer Tables來最大限度的減少訪問數據的時間。
是否是緩存表,可以在ABAP Dictionary中來配置:
表的三種緩沖類型:
l Partial buffering (單記錄緩存single entry) :從數據庫中僅讀取一條數據並存儲到table buffer 中。此緩存只對SELECT SINGLE…語句起作用,如果不是則繞過單記錄緩存區,直接訪問數據庫表。
l Generic buffering(普通緩存,區域緩存):在此種情況下,你需要在指定一個generic key (由部分或全部關鍵字段組。如果主鍵是由一個字段構成,則不能選擇此類型緩存。下面的generic key為前面三個主鍵:MANDT、CARRID、COUNTNUM) 。表的內容會被划分到相應的generic areas中(根據WHERE條件中使用的主鍵字段),當你使用generic keys進行數據訪問時,則屬於此generic area的整片數據都會被加載到table buffer中。客戶特定的表一般根據client來緩存。此類型的緩存需注意:
1、 查詢時如果使用BYPASSING BUFFER 選項,除了繞過緩存直接到數據庫查詢外,查詢出來的數據也不會放入緩存。
2、 只要查詢條件中出現了用作緩存區域的所有字段(generic key),則查詢出所有滿足generic key的所有數據,然后進行緩存。
3、 如果查詢條件中generic key只出現某個或者某部分,則不會進行緩存操作。
4、 如果主鍵是只由一個字段組成,則不能設定為此種緩存。
5、 如果有MANDT字段,則為generic key的第一個字段(注:在創建表時,MANDT只能是第一個字段,否則不起作用)
將相關的數據放入Buffer,至於將哪些數據放入,則根據設定的generic key為條件。
l Resident(常駐) buffering (全部緩存100%) The first time the table is accessed, its entire(整個) contents are loaded in the table buffer.(在第一次讀取表數據時,會將整個表的數據都會緩存下來,不管WHERE條件,都會將整個表緩存起來)
當從一個具有緩沖功能的表讀取數據時,以下過程會發生:
1. ABAP program從buffered table中讀取數據
2. ABAP processor 解析Open SQL 語句。如果查詢的表配置了綏中,ABAP processor 則會在服務器上檢查local buffer ,看查詢的數據是否已緩存
3. 如果查詢的數據沒有被緩存,將會去查詢數據庫。如果存在,則將滿足條件的數據返回到程序中。
4. 數據服務器會將數據傳送到SAP應用服務器,並將它緩存下來
5. 將查找到的數據返回到應用程序
當修改一個具有緩沖功能的表時,以下動作會發生:
1. 數據庫表與SAP應用服務器上的緩沖會被更新。數據庫接口(database interface)記錄修改日志到table DDLOG表中(Buffer Synchronization表)。如果系統不只有一個application server,其他的服務器上的緩存並不會立即更新。
2. 所有的應用服務器會定期的讀取table DDLOG,根據該表中的日志來更新緩存。掃描的間隔與buffering type有關,在分布式系統中,同步時間為60 seconds
3. 在未同步的應用服務上,用戶讀取的數據是舊的。該數據直到下次緩存同步時才認為過期。
適合使用緩存的表:
1. 頻繁讀取的表
2. 很少修改的表
3. 相對小的表(few lines, few columns, or short columns)
4. 延遲更新可接受的表
SELECT 語句在下列方式不會使用到緩存:
1. 在FROM從句中使用了BYPASSING BUFFER 選項
2. 在SELECT從句中使用了DISTINCT選項
3. 在SELECT從句使用Aggregateexpressions
4. FROM從句中使用了join
5. WHERE從句中使用了IS NULL條件
6. WHERE從句中使用了Subqueries(子查詢)
7. 使用了ORDER BY從句(如果排序的字段是主鍵,則還是會使用緩存)
8. 使用了GROUP BY從句
9. 使用了FOR UPDATE選項(經測試,好像還是會用到緩存,但FOR UPDATE是要依靠數據庫系統本身來加鎖的,但明確的指定繞過緩存選項又不支持:SELECT SINGLE FOR UPDATE… BYPASSING BUFFER… 這樣的語句又不支持)
10. 另外,所有的Native SQL 語句不會使用到緩存