Open SQL詳解


---

image185

只有標准SQLDML有對應的Open SQL,只有SELECTINSERT, UPDATE, DELETE有對應的Open SQL

 

Native SQL不會用到緩存,會直接發送給數據庫,而不會經過ABAP數據訪問層。除開DML,它一般用於DDLDCL,主要用來維護數據庫表

 

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-SUBRC0,否則設置為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-mandtmandt存儲到 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.

image186

SQL查詢條件

operator比較操作符

SELECT ... WHERE <s><operator><f>...

<f>可能是FROM從句中的某個表的表字段,也可以是數據變量常量值,或者是具有返回值的子查詢<operator>比較操作符可以是以下這些:

image187

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').

如果CITYIN后面列表中的任何一個時返回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_syntaxinitial則相當於*會查詢所有列

如果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條件、子查詢,以及GROUPBYORDER BY同時使用時,也將自動忽略緩沖設定

 

SELECT ... FROM <tables>BYPASSING BUFFER ...

 

">限定選擇行數UP TO n ROWS ...

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

如果n為正數,系統最多選擇n行到程序中,如果n0,則還是選擇所有滿足條件的數據。如果同時使用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連接,像這樣:

image188

image189

 

另外,在使用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條件中所有表達試中的左表只能出現同一個,不能出現第二個,如下所示:)

image190

ü  如果是LEFT OUTER JOIN同一右表dbtab_right不能出現在不同的LEFT OUTER JOIN(在一個Select語句中LEFT JOIN可以多次出現,關聯不同的表)的條件表達式中:

image191

ü  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時,onwhere條件的區別如下:

1on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄

2where條件是在臨時表生成好后,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉。

假設有兩張表:

1tab1

id

size

1

10

2

20

3

30

2tab2

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的過程:

1、中間表on條件: 
tab1.size = tab2.size

tab1.id

tab1.size

tab2.size

tab2.name

1

10

10

AAA

2

20

20

BBB

2

20

20

CCC

3

30

(null)

(null)

   

2、再對中間表過濾where條件:tab2.name=’AAA’

tab1.id

tab1.size

tab2.size

tab2.name

1

10

10

AAA

   

第二條SQL的過程:

1、中間表on條件: 
tab1.size = tab2.size and tab2.name=’AAA’
(
條件不為真也會返回左表中的記錄
)

tab1.id

tab1.size

tab2.size

tab2.name

1

10

10

AAA

2

20

(null)

(null)

3

30

(null)

(null)

其實以上結果的關鍵原因就是left join,right join,full join的特殊性,不管on上的條件是否為真都會返回leftright表中的記錄full則具有leftright的特性的並集。而inner join沒這個特殊性,則條件放在on中和where中,返回的結果集是相同的(但放在ON后面的效率會高一些

子查詢

使用子查詢時會繞過SAP buffering

 

有時只需從一個表中選擇數據,但這些數據與其他表中的數據字段內容相關聯,但又不需將其它表中相關的數據查出來,類似操作可通過子查詢進行。子查詢是沒有SINGLE, INTO, and ORDER BY的查詢語句,通過col operator [ALL|ANY|SOME] EXISTSIN連接至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兩種表

 

ALLANYSOME子查詢

這種子查詢的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>] ...

 

MAXMINAVGSUMCOUNT

 

聚合函數都可以加上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_syntaxInitial時,則會忽略

 

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-SUBRC0,否則為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.

image192

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各字段,與名稱無關

如果數據庫中有一個waprimary key相同的數據,則SY-SUBRC0,否則SY-SUBRC4

 

或者:

TABLES:mard.
UPDATE
mard.

注:此方式不能動態指定表名

 

"CARRID CONNIDspfli的主鍵

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 CONNIDspfli的主鍵

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 + gf = f - g兩種形式在該字段原有值基礎上增減。如果至少有一條數據被更新,則SY-SUBRC返回0,否則返回4SY-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-SUBRC0,否則SY-SUBRC4

 

或者省略wa

TABLES:mard.
DELETE
mard.

注:此方式不能動態指定表名

 

"CARRID CONNIDspfli的主鍵
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-SUBRC0,否則為4SY-DBCNT存儲了被刪除的條數。如果內表itab為空,則SY-SUBRC  SY-DBCNT都為0

"CARRID CONNIDspfli的主鍵
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相當於INSERTUPDATE的結合。當使用MODIFY語句操作數據庫時,如果程序中指定的數據行已經存在數據庫中(根據表關鍵字判斷)則對其進行更新操作,如果不存在,則進行插入操作。

 

插入或更新單行

MODIFY dbtabFROM wa.

根據工作區wa中的表關鍵字段來定位要修改的數據,如果不存在,則插入。工作區wa的寬度也要大於或等於表結構的所有字段表寬度

 

MODIFY<dbtab>.

SY-SUBRC總是為0

 

 

插入或更新多行

MODIFY dbtab FROM TABLE itab.

根據內表中的每一行表關鍵字段來查找數據是否存在,如果不存,則會插入。

SY-SUBRC總是為0SY-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》中的<示例屏幕元素自動參考數據詞典>章節

image193

 

在指定了表工作區之后,在使用SELECTSINGLE語句時可以省略INTO子句(INTOTABLE時不能省略),系統默認將數據行讀取到同名變量的表工作區中。

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查詢選項代替內嵌SelectFOR 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,因為這樣數據庫不會使用索引,所以要使用肯定操作比較操作符,如EQLIKE。另外,如果可能,避免在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語句所使用的索引一樣。此時可以將數據讀到內表后,對內表進行排序

 

image194

 

image195

 

image196

image197

image198

image199

image200

image201

image202

image203

image204

 

 

 

使用Buffer Tables

你可以通過訪問服務器上的Buffer Tables來最大限度的減少訪問數據的時間。

是否是緩存表,可以在ABAP Dictionary中來配置:

 

表的三種緩沖類型:

l  Partial buffering (單記錄緩存single entry) :從數據庫中僅讀取一條數據並存儲到table buffer 中。此緩存只對SELECT SINGLE…語句起作用,如果不是則繞過單記錄緩存區,直接訪問數據庫表。

image205

l  Generic buffering(普通緩存,區域緩存)在此種情況下,你需要在指定一個generic key (由部分或全部關鍵字段組。如果主鍵是由一個字段構成,則不能選擇此類型緩存。下面的generic key為前面三個主鍵:MANDTCARRIDCOUNTNUM) 。表的內容會被划分到相應的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只能是第一個字段,否則不起作用)

image206

將相關的數據放入Buffer,至於將哪些數據放入,則根據設定的generic key為條件。

 

image207

image208

 

l  Resident(常駐) buffering (全部緩存100%) The first time the table is accessed, its entire(整個) contents are loaded in the table buffer.(在第一次讀取表數據時,會將整個表的數據都會緩存下來,不管WHERE條件,都會將整個表緩存起來)

image209

 

當從一個具有緩沖功能的表讀取數據時,以下過程會發生:

1.      ABAP programbuffered 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 語句不會使用到緩存


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM