嵌套SQL語句訪問DB2中SQLCA的調用技巧,db2sqlca
在IBM的關係型資料庫產品DB2中,使用SQL Communication Area(SQLCA)將程式中嵌套的SQL語句運行情況返回給程式。在程式中有針對性地對SQLCA實施調用,可對程式中各類SQL語句的執行結果實施控制,從而避免程式的意外終止。同時,也可以提高運行效率,減小系統開銷和處理時間。本文將對此作一簡要介紹。
SQLCA的結構
SQLCA的結構定義如下:
struc sqlca
{ unsigned char sqlcaid[8];
long sqlabc;
long sqlcode;
short sqlerrml;
unsigned char sqlerrnmc[10];
unsigned char sqlerrp[8];
long sqlerrd[6];
unsigned char sqlwarn[21];
unsigned char sqlstate[5]; }
結構中各個域各有不同的含義和用途,部分域的功能和用途將在以下各小節中做詳細探討,其它一些域的含義如下:
sqlcaid: 標識性域,包含字串“sqlca”.
Sqlabc: 包含sqlca結構的長度。
Sqlerrml: 包含sqlerrmc域中資料的實際長度。
Sqlerrmc: 由0或多個字串組成,它對返回的值給以一個更詳細的解釋。如返回的代碼錶示表沒找到,則此域中包含未找到的表名。
Sqlerrp: 包含一些對使用者無用的論斷資訊。
Sqlstate: 長度為5的字串,它指示SQL語句的查詢結果。與sqlca不同的是,它遵循ANSI/ISOSQL92的標準,所以,儘管不同資料庫產品的sqlca結構中sqlcode域的含義不同,但sqlstate域的含義是相同的。
調用方法
DB2通過一個函數:sqlaintp,可以方便地讀取sqlca中SQL語句執行後的結果和錯誤。此函數定義在sql.h中,可通過下述語句實現對其定義:
EXEC SQL INCLUDE sqlca.h
Sqlaintp函數格式如下:
int sqlaintp
( char *buffer
short buffer_size
short line_width
struct sqlca *sqlca )
其中, buffer為存放了sqlca資訊的緩衝區;buffer_size中存放了buffer的長度;line_width存放了兩個執行符之間的字元長度。函數返回值為正時代表sqlca資訊的長度,為負時代表沒有sqlca資訊返回。一般來講,sqlca資訊都可存放在長度為512個位元組的緩衝區中。
為了處理各種錯誤情況,DB2提供了WHENEVER語句。其具體使用方法如下:
(1) EXEC SQL WHENEVER SQLERROR action SQLCODE<0時,執行action.
(2) EXEC SQL WHENEVER SQLWARNING action SQLCODE>;0但不為100且SQLWARN[0]=W時時,執行action.
(3) EXEC SQL WHENEVER NOT FOUND action SQLCODE=100時,執行action.
其中action有兩種可能:
CONTINUE:繼續執行程式中的另一條命令。
GO TO label:轉到label指定的語句開始。
值得注意的是,WHENEVER語句的作用範圍到下一個WHENEVER時終止。
對SQLCODE的調用
在對SQLCA的調用中,最常見的就是通過訪問SQLCODE來實現的。很多程式員甚至在每條SQL語句執行完畢後都設定檢查SQLCODE返回值的代碼,以對程式的運行進行監控。當返回值為+0的時,表明SQL語句執行成功;返回值為+100時,表明滿足檢索條件的記錄沒找到。一般來說,負的SQLCODE返回負值意味著SQL語句執行失敗,程式員可在程式中實現根據不同的SQLCODE返回值,採取不同的程式流程以實現錯誤控制。例如,當SQLCODE的返回值為-911時, 表明系統檢測到了死結(Dead Lock),程式員可針對這種情況採取以下兩種處置方法:
(1)設定迴圈,反覆執行查詢請求並檢測SQLCODE,直至返回值為+0(執行成功)。
(2)設定一個計數器,執行查詢請求到一定次數後終止程式或向使用者發出警報。
值得注意的是,為了保證資料的完整性,有時需要針對返回的錯誤類型對資料庫進行復原(ROLLBACK)操作,且復原的起點不一定是未執行成功的SQL語句導致系統所處於的狀態。復原的起點與SQL語句的巢狀型別(動態,靜態,複合式)以及錯誤類型都有關係。尤其是後者,因為有些錯誤類型會導致系統作一個隱式的復原(例如SQLCODE -911),從而使復原的起點判斷更為複雜。
儘管多數情況下我們希望SQL語句執行成功,但有些時候,通過一個故意“製造”的負的SQLCODE返回值,可以使程式中的邏輯判斷更為簡潔,還可在較大程度上降低系統開銷。我們可以設想這樣一種情況:郵電局有兩種話費收據,一種是針對只安有一部電話的使用者的,另一種是針對安有多部電話的使用者的,兩種話費收據上的項目個不相同,需要不同的子程式進行處理。在話費收據處理常式中,首先根據每一個使用者唯一的ID號檢索對應的電話號碼,並設定計數器對檢索到的記錄數(安裝電話數)進行統計,當某使用者ID僅對應一條電話號碼記錄時,調用單機使用者話費收據處理常式對相應使用者的話費資料進行處理;當某使用者ID僅對應多條電話號碼記錄時,調用多機使用者話費收據處理常式對相應使用者的話費資料進行處理。無論何種情況,都需對使用者的資料重新進行讀取方可進行下一步處理。也就是說,需要對一個使用者的電話資料進行兩次讀取才能完成相應的資料處理。這無疑會極大的增加系統處理時間。通過對SQLCODE的調用,可以使這種情況得以顯著改善。首先,針對每一個使用者的ID作一個SELECT操作,然後檢查SQLCODE返回值,當返回值為+0時,表明該使用者只安裝了一部電話;當返回值為-811時,表明該使用者安裝了不止一部電話。可由此判斷應由那種程式來處理使用者話費資訊。採用這種解決方案,只對使用者的資料讀取一次就可完成使用者的話費處理,幾乎減少了一半的系統處理時間。與其它諸如改變表的結構等方法,此種方法對系統的改動最小,並且簡便易行,效果明顯。
在對資料庫訪問的程式中,程式通常要求實現如下功能:更新資料庫中的某一條記錄,當這條記錄不存在時建立相應的記錄。比較常見的做法是,先進行一次SELECT查詢,當SQLCODE返回+0時,表明此條記錄已存在,然後再重讀此記錄對其進行UPDATE操作;當SQLCODE返回+100時,表明相應記錄不存在,接下來再進行INSTER操作。另一種實現方岸根據資料訪問的特點,當對資料的更新多於新值插入時,直接進行UPDATE操作,當SQLCODE返回+0時更新成功,反之,返回+100時,需對其進行INSERT操作;當新值插入要多餘於更新操作時,首先進行INSERT操作,SQLCODE值為+0時插入成功,否則返回-803,表明原記錄已存在,需要進行UPDATE操作。顯而易見,多數情況下,第二種方法只需對資料進行一次操作即可,從而提高系統的處理效率。
對SQLWARN的調用
儘管程式員通常總是忽略SQL的警告錯誤,但適當的使用可以協助程式檢測到各種潛在的錯誤,並且可以使編程更加簡潔。因此,此類警告資訊亦應受到程式員的重視。
警告資訊在SQLCA中有兩種表示方法。每一個除了+100以外的SQLCODE正返回值都代表一定的警告資訊;同時,SQLCA中的SQLWARN[n](n=1,2,3,4,5,6或A)返回值也代表著相應的警告資訊。當系統發現警告錯誤時,系統會以這兩種方式通知程式。此時,查詢可能會返回一些結果,但此時的結果極有可能是錯誤或不完整的。當SQLWARN[O]=W時,DB2提供了協助使用者判斷具體警告類型的資訊,其相應值及含義如下表:
SQLCA值 返回值 警告內容
SQLWARN[1] W 序主變數長度不夠而發生截取
SQLWARN[2] W 欄位功能處理的資料中有空(NULL)值
SQLWARN[3] W 返回欄位個數大於程式定義的序主變數個數
SQLWARN[4] W 在UPDATE或DELETE操作中未指定WHERE條件
SQLWARN[6] W 對時間資料進行數學運算後進行修正
SQLWARN[A] W 轉換出錯
假設某學校要計算某一學期各班,各科,個人的平均成績。其中,個人平均成績=(個人總分)/(本學期所學科目數)。由於工作人員疏忽,誤將某一同學的學期學習科目輸為0。在使用嵌套SQL語句的程式對相關資料進行處理時,SQLCODE返回值為-802(除數為零)導致程式終止運行。儘管使用者知道可能是某一項資料錯誤,但無法知道具體是哪一項資料錯誤。對於一個擁有較多資料的學校來說,尋找起來是非常費事的。通過下述辦法可以很好的解決這一問題:在定義代表計算結果的序主變數的同時,為其指定一個可以為空白的指示變數,如 :AVGRD :IND代表序主變數為AVGRD,指示變數為IND。此時發生被零除錯誤時,指示變數值被設為-2,同時SQLCODE返回值為+802警告資訊。程式捕捉到此資訊時,可向使用者提供相應的資訊,協助使用者確定出錯資料位元置。
當SQLWARN[O]的值為W時,表明系統檢測到警告錯誤。此時系統提供的警告資訊也可被程式員所利用。比如:當程式把一個表中的某一字元型欄位值傳入一個比其長度要短的序主變數中時,發生字元截取。儘管此時SQLCODE會返回+0,但程式擷取的資料是不完整的。通過為序主變數指定一個指示變數,發生同樣錯誤時,SQLWARN[O]和SQLWARN[1]的返回值都為W,同時,指示變數被賦給了欄位中資料的實際長度。此種方法甚至可以用來判斷表中欄位中字串資料的實際長度。
對SQLERRD數組的調用
SQLERRD是SQLCA中代表SQL查詢運行結果的一個數組。數組中的不同元素有不同的含義。其中較常用的是SQLERRD[3]。它將返回程式中上一次INSERT,UPDATE或DELETE操作所影響到的記錄數。否則,程式需要藉助一定的迴圈來統計被以上操作影響到的記錄數。但值得注意的是,在執行DELETE操作時,如果相關欄位的刪除類型被設為CASCADE而導致被刪除其它記錄數不會被包含在內;同時,如果在DELETE語句中未指定WHERE條件,則SQLERRD[3]的返回值為-1。以上兩點在使用此數組時應予以注意。SQLERRD中各元素的含義以及其對於複合式SQL語句,串連方法的不同含義如下:
SQLERRD元素 表示意義 複合式SQL語句 串連方式
SQLERRD[2] 儲存當前SQL語句處理的行數。但若當前SQL失敗, 則無定義; 若在數組操作中出錯, 則停於出錯行, 這時給出成功處理的行數; OPEN執行後, 清為0, FECTH 後增值(原有值+上本次fetch的行數); EXECUTE、INSERT、UPDATE、SELETE和SELECT後, 為成功處理的行數。
SQLERRD[3] 返回的記錄數(估計)及INSERT/UPDATE或DELETE操作所影響到的記錄數(不包含因限制條件而影響到的記錄) 總語句數 0:由底層客戶機的一段式提交委託確認1:一段式提交2:一段式唯讀提交3:兩段式提交
SQLERRD[4] 指出語句中出錯的位移, 首字元位移為0。
SQLERRD[5] INSERT/UPDATE或DELETE操作所影響到的記錄數(包含因限制條件而影響到的記錄) 因限制條件而影響到的記錄數 無
常用:SQLERRD[2] ,如:#defineSQLROWS sqlca.sqlerrd[2]
DB2支援多種進階語言(包括當前極為流行的C和C++等)通過嵌套SQL語句對其上的資料進行訪問。同時,由於對多種嵌套(動態,靜態,複合式)方式的支援,更加增強了訪問的靈活性。通過在程式中調用SQLCA,可對程式中嵌套的SQL語句的執行結果進行控制,增強了程式的可靠性,防止程式意外終止;也可使程式的編寫更加簡潔,提高程式的運行效率,縮短系統的處理時間。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。