ORACLE的ProC用法讲解
在ORACLE數(shù)據(jù)庫管理和系統(tǒng)中,有三種訪問數(shù)據(jù)庫的方法;
(1)用SQL*Plus,它有SQL命令以交互的應(yīng)用程序訪問數(shù)據(jù)庫;?
(2)用第四代語言應(yīng)用開發(fā)工具開發(fā)的應(yīng)用程序訪問數(shù)據(jù)庫,這些工具有SQL*Froms, QL*Reportwriter,SQL*Menu等;?
(3)利用在第三代語言內(nèi)嵌入的SQL語言或ORACLE庫函數(shù)調(diào)用來訪問。? Pro*C就屬于第三種開發(fā)工具之一, 它把過程化語言C和非過程化語言SQL最完善地結(jié)合起來,? 具有完備的過程處理能力,又能完成任何數(shù)據(jù)庫的處理品任務(wù),使用戶可以通過編程完成各種類型的報(bào)表。在Pro*C程序中可以嵌入SQL語言,利用這些SQL語言可以完成動(dòng)態(tài)地建立、修改和刪除數(shù)據(jù)庫中的表,也可以查詢、插入、修改和刪除數(shù)據(jù)庫表中的行,還可以實(shí)現(xiàn)事務(wù)的提交和回滾。
在Pro*C程序中還可以嵌入PL/SQL塊,以改進(jìn)應(yīng)用程序的性能,特別是在網(wǎng)絡(luò)環(huán)境下,可以減少網(wǎng)絡(luò)傳輸和處理的總開銷。
如何編譯.pc文件:?proc code=cpp??parse=none iname=filename.pconame=filename.cpp
一, 首先要包涵頭文件#include?這個(gè)頭文件
二,??在聲明宿主變量之前一定要先定義struct sqlca sqlca;這個(gè)變量。
三, 所有與oracle數(shù)據(jù)庫SQL語句有關(guān)的變量必須在前面聲明為宿主變量分配空間才可以使用,
宿主變量只能是oracle支持的數(shù)據(jù)類型,一般是基本類型的,結(jié)構(gòu)體類型。只有宿主變量才可以和SQL還有函數(shù)中的其他變量之間相互通信。
例子:
?EXEC SQL BEGIN DECLARE SECTION; //開始申明
?charstrsql[512]={0};
?EXEC SQL END DECLARE SECTION;???//結(jié)束申明
?
四,靜態(tài)SQL語句之查一條記錄的模式,通過宿主變量接收申sql語句所查到的結(jié)果
?舉例:INTO?:TotalRecord, :TotalMoney?,接收結(jié)果,proc中用:綁定變量
EXEC SQL??select count(B.msisdn),sum(B.payamount)
?????INTO :TotalRecord, :TotalMoney
?????from OM_MPAY_USER_INFO A ,OM_MPAY B
??????WHERE??A.msisdn = B.msisdn andA.region=trim(:areacode)??andB.pay_date = :sqltime;
?
五,查詢多條記錄一般我們使用動(dòng)態(tài)SQL語句,結(jié)合游標(biāo)來收集多條記錄的結(jié)果,其次要注意的是循環(huán)得到結(jié)構(gòu)。
舉例:sprintf(strsql,"select*from?mytable?")
????EXEC SQL PREPARE?SqlCountRegion?FROM?:strsql;?//或者活動(dòng)區(qū)
????EXEC SQL DECLARE?CurRegion?CURSORFOR?SqlCountRegion;?//對(duì)活動(dòng)區(qū)申請(qǐng)游標(biāo)
????EXECSQL OPEN?CurRegion;??//打開游標(biāo),打開游標(biāo)的同時(shí)可以用using對(duì)其賦值
???do{
????????EXECSQL FETCH?CurRegion?INTO?:regionnum;?//循環(huán)捕捉游標(biāo)中變量的值
????????if (sqlca.sqlcode ==1403)?
??????????break;
????????cout<<regionnum<<endl;
?}while(1);
?EXEC SQL CLOSE?CurRegion;?//關(guān)閉游標(biāo)
?EXEC SQL rollback work release;?//回滾數(shù)據(jù)關(guān)閉釋放所有資源和鏈接
?
六,捕捉異常錯(cuò)誤和停止程序
//下面的意思是發(fā)生錯(cuò)誤異常的時(shí)候跳轉(zhuǎn)到標(biāo)記處執(zhí)行標(biāo)記后面的語句
EXEC SQL whenever sqlerror??goto?errinfo;
errinfo:
?printf("???sqlca.sqlcode=%d,sqlca.errm=%s\n",sqlca.sqlcode, sqlca.sqlerrd);
?EXEC SQL??wheneversqlerror stop;?//發(fā)生異常的時(shí)候推出整個(gè)程序,關(guān)閉所有連接釋放所有資源
??return sqlca.sqlcode;
?
七, proc中的SQL語句不要加分號(hào)(;) ,注釋如果是C++工程使用如果是C++使用//或者,在oracle中的注釋是--,???oracle數(shù)據(jù)庫中的數(shù)據(jù)如果數(shù)據(jù)字節(jié)不足位數(shù),默認(rèn)用空格補(bǔ)全,宿主變量的空間要大于數(shù)據(jù)庫的字段空間。
對(duì)于結(jié)構(gòu)的特殊含義處理:sqlca.sqlcode ==1403 表示結(jié)束了查找循環(huán),這個(gè)在動(dòng)態(tài)sql語句中比較重要,
sqlca.sqlcode == -1405 表示查詢值為空的時(shí)候報(bào)的錯(cuò)誤,這個(gè)最好留給返回值待程序處理,
sqlca.sqlcode == -1480 表示在sql語句中傳入的變量時(shí)空值一般就是傳值失敗,可能是空間的大小問題。
?
八, 關(guān)于Proc中特殊的SQL語句,如,delete ,update,alter,insert into 等數(shù)據(jù)變動(dòng)性操作的時(shí)候,
要注意2點(diǎn),可以再宿主變量區(qū)申請(qǐng)復(fù)雜的結(jié)構(gòu)類型的指針,用指針將參數(shù)外部的數(shù)據(jù)綁定到sql語句中,接下來就是提交事物,操作完變動(dòng)性數(shù)據(jù)之后就是commint提交事物,進(jìn)行回滾。
例子:
int GetDBRecode( struct buf *tempbuf)
{
EXEC SQL BEGIN DECLARE SECTION; //開始申明
?charstrsql[512]={0};
?struct buf * temp=??tempbuf;
?EXEC SQL END DECLARE SECTION;???//結(jié)束申明
?exec sql insert intomytable( name, sex, num)values( :temp->name, :temp->sex, :temp->num)
if(?sqlca.sqlcode??)
{
???????printf("判斷是否執(zhí)行成功");
}
}
?
?????????????????????????????例子講解
//#include
//#include
//#include"CssCheckBill.h"
//#include
int main()
{
struct sqlca sqlca; //必須要有
?EXEC SQL BEGIN DECLARESECTION;
?charstrsql[512]={0};
?char user[20]={0};
?char pwd[20] ={0};
?char dbname[20]={0};
?char regionnum[7];
?charTotalMoney[15]={0};
?char??TotalRecord[15]={0};
?EXEC SQL END DECLARE SECTION;
?
strcpy(user,"user");
?strcpy(pwd,"pwd");
?strcpy(dbname,"dbname");
?//這句是連接數(shù)據(jù)庫的操作
?EXEC SQL CONNECT :user?IDENTIFIED BY :pwd?USING:dbname;
?
EXEC SQL??selectcount(B.msisdn) ,sum(B.payamount)
?????INTO?:TotalRecord,:TotalMoney???//INTO綁定變量
?????from OM_MPAY_USER_INFO A ,OM_MPAY B
??????WHERE??A.msisdn = B.msisdn andA.region=trim(:areacode)??andB.pay_date = :sqltime;
//設(shè)置捕獲異常信息標(biāo)志
?EXEC SQL??wheneversqlerror goto ORA_ERR;
?if(0>=??::snprintf(strsql,sizeof(strsql),"select distinct(region) from OM_MPAY_USER_INFO where region is notnull" ))
?{
??printf("%s snprintf??create sql??fail !\n", __FUNCTION__);
?????????return -1;
?}
//動(dòng)態(tài)游標(biāo)方式獲取查詢結(jié)果
?EXEC SQL PREPARE?SqlCountRegion?FROM?:strsql;
??EXEC SQL DECLARE?CurRegion?CURSORFOR?SqlCountRegion; //CURSOR FOR?可以直接跟SQL語句
?EXEC SQL OPEN?CurRegion;
?do{
??EXEC SQL FETCH?CurRegion?INTO?:regionnum;
??if (sqlca.sqlcode ==1403)?
????????break;
??printf("regionnum=%s,???len=%d\n",regionnum,strlen(regionnum));
????DelStrRightBlack(regionnum );
?}while(1);
//關(guān)閉異常捕獲信息
?EXEC SQL??whenever sqlerror stop;
?EXECSQL CLOSE?CurRegion;
//設(shè)置回滾事物
?EXEC SQL rollback workrelease;
?returnsqlca.sqlcode;
ORA_ERR:
?printf("sqlca.sqlcode=%d,sqlca.sqlerrp=%s\n",sqlca.sqlcode, sqlca.sqlerrp);
?return sqlca.sqlcode;
return 0 ;
}
總結(jié)了一下PRO*C中存儲(chǔ)過程調(diào)用,普通SQL語句游標(biāo)執(zhí)行,動(dòng)態(tài)SQL語句游標(biāo)執(zhí)行的方法;
PRO*C中常用SQL及游標(biāo)、存儲(chǔ)過程使用匯總:
1) exec sql select c1,c2 into:v1,v2 from table_a;
2) exec sql insert intotable_a(v1,v2) select b.v1,b.v2 from table_b b where 1=2;
3) exec sql insert intotable_a(v1,v2) select b.v1,b.v2 from table_b b where 1=2;
存儲(chǔ)過程調(diào)用
4) exec sql call procedure_a(:v1,:v2);
5) sprintf(sta,"select v1,v2 into :v1,v2 from table_a wherev3=%s",v3);
exec sql execute immediate :sta;
--普通SQL語句游標(biāo)執(zhí)行
6)exec sql declare cur1 cursor for
select v1,v2,v3 from table_a where 1=2;
exec sql open cur1;
do{
exec sql fetch cur1 into :v1,:v2,:v3;
if(sqlca.sqlcode==-1403) break;
....
}while(1) ;
exec sql close cur1;
--動(dòng)態(tài)SQL語句游標(biāo)執(zhí)行
7)> sprintf(sta,"select c1,c2,c3 from table_a where c1=%s and c2=:v1and c3=:v2",v1);
exec sql prepare select_msg from :sta;
exec sql declare cur1 cursor for select_msg;
exec sql open cur1 using :v1,:v2;?//打開游標(biāo)的時(shí)候使用using來傳迪綁定的變量
do{
exec sql fetch cur1 into :c1,:c2,:c3;
if(sqlca.sqlcode==1403)break;
....
}while(1);
exec sql close cur1;
?
其他情況的proc講解
Pro*C/C++編程講解:
1、宿主變量的聲明
在PROC中,在SQL語句中用到的變量稱為宿主變量。他們應(yīng)在EXEC SQL BEGIN DECLARE SECTION;與EXEC SQL EDNDECLARE SECTION; 之間聲明,如上面所示,在聲明宿主變量時(shí)應(yīng)注意以下幾點(diǎn):
(1) 在數(shù)據(jù)庫表中定義為VARCHAR2,VARCHAR,CHAR的字段,在PROC中可聲明為CHAR,但長(zhǎng)度應(yīng)為它們?cè)诒碇卸x的長(zhǎng)度加1,因?yàn)镻ROC中CHAR型變量用做結(jié)尾。
如:ENAME在表中的定義為ename varchar2(10),在PROC中可定義為:
EXEC SQL BEGIN DECLARESECTION;
char ename[11];
EXEC SQL END DECLARESECTION;
常見錯(cuò)誤說明:
如果插入的字符串長(zhǎng)度大于10,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES(‘12345678901’);會(huì)出現(xiàn)以下錯(cuò)誤:
error:ORA-01480: STR 賦值變量缺少空后綴。
如果定義為:
EXEC SQL BEGIN DECLARESECTION;
char ename[15];
EXEC SQL END DECLARESECTION;
當(dāng)插入的字符串長(zhǎng)度大于10,小于15時(shí),如:EXEC SQLINSERT INTO EMP(ENAME) VALUES(‘12345678901’);會(huì)出現(xiàn)以下錯(cuò)誤:
error:ORA-01401: 插入的值對(duì)于列過大。
當(dāng)插入的字符串長(zhǎng)度大于15,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES('12345678901234');會(huì)出現(xiàn)以下錯(cuò)誤:
error:ORA-01401:STR 賦值變量缺少空后綴。
(2) 從SQL語句中取字段的值到宿主變量中時(shí),PROC不會(huì)自動(dòng)給宿主變量去掉右空格。而是以在DECLARE SECTION 中定義的長(zhǎng)度為準(zhǔn)(與 表中定義的無關(guān))不足補(bǔ)右空格.如果不注意這一點(diǎn),在PROC中進(jìn)行字符串操作時(shí)(如比較相等)會(huì)出錯(cuò)。如:
EXEC SQL BEGIN DECLARESECTION;
char ename[10];
EXEC SQL END DECLARESECTION;
如果ENAME在表中的值為''abc'',則取出的值為''abc '';
可用語句EXEC SQL VAR重定義CHAR型變量。這樣宿主變量會(huì)自動(dòng)去掉右空格。如下:
EXEC SQL BEGIN DECLARESECTION;
char ename[11];
EXEC SQL VAR ac_enameIS STRING(11);
EXEC SQL END DECLARESECTION;
如果ENAME在表中的值為''abc'',則取出的值為''abc'';
(3) 對(duì)浮點(diǎn)型的變量,為保證精度,最好是聲明成DOUBLE型的.因?yàn)镈OUBLE型的精度比FLOAT型高很多.
(4) 整型可聲明為L(zhǎng)ONG型(對(duì)較長(zhǎng)的整型,而且所用的平臺(tái)支持的話,如在SUN平臺(tái)上,可聲明為L(zhǎng)ONG LONG型).
(5) DATE型的處理:DATE型一般聲明為CHAR(20)。
往表中插入DATE型數(shù)據(jù)時(shí),一般用TO_DATE()函數(shù)進(jìn)行類型轉(zhuǎn)換,取出值時(shí)一般用TO_CHAR()函數(shù)進(jìn)行類型轉(zhuǎn)換.
EXEC SQL selectto_char(hiredate,''yyyy/mm/dd hh24:mi:ss'') into :ac_hire_date from EMP whereempno=1234;
EXEC SQL insert intoEMP(EMPNO,HIREDATE) values(123,to_date(:ac_hiredate,''yyyy/mm/dd hh24:mi:ss'');
2、宿主變量的作用范圍
如果宿主變量在所有的函數(shù)之外聲明,則他們是全局變量。在使用之前要注意把變量的值初始化,宿主變量也可以在某個(gè)函數(shù)的內(nèi)部定義。這時(shí)他們是局部變量。一般都習(xí)慣把宿主變量聲明為全局變量。
3、數(shù)據(jù)庫的連接與斷開
數(shù)據(jù)庫的連接有以下兩種方法:
(1)
strcpy(vc_user.arr,"scott/tiger");
vc_user.len=11;
exec sql connect:vc_user;
(2)
strcpy(user,"scott");
strcpy(pass,"tiger");
exec sql connect :useridentified by :pass;
注意:在有些平臺(tái)上兩種都可以,在有些平臺(tái)上只能用第一種方法.
在PROC程序中,要記住用EXEC SQL ROLLBACK WORK RELEASE;斷開與數(shù)據(jù)庫的連接,并釋放相關(guān)的數(shù)據(jù)庫資源。
4、PROC中的NULL值的處理
如果某一字段取出的值是NULL,會(huì)報(bào):sqlcode=-1405, sqlerr=ORA-01405: 讀取的列值為NULL并且相應(yīng)的宿主變量的值不會(huì)被改變,為執(zhí)行該SQL語句之前的值. 常用的處理NULL值的方法有:
(1)采用指示器變量,此時(shí)不會(huì)有-1405錯(cuò)誤,當(dāng)必須是所以為NULL的字段都有相應(yīng)的指示器變量,如果某一字段沒有指示器變量,但取出的值為NULL值,則仍然會(huì)有-1405錯(cuò)誤.當(dāng)取出的值是NULL時(shí),相應(yīng)的指示器變量變量為-1,可根據(jù)指示器變量的值做響應(yīng)的處理。
(2)如果字段較多,可取字段到一個(gè)結(jié)構(gòu)體中及與該結(jié)構(gòu)體對(duì)應(yīng)的指示器結(jié)構(gòu)體中.如上面的例子中可定義結(jié)構(gòu)體:
struct str_emp{
long al_empno;
char ac_ename;
char ac_hiredate;
double af_sal;
};
struct str_emp_ind{
long al_empno;
char ac_ename;
char ac_hiredate;
double af_sal;
};
structstr_emp str_emp;
strcut str_emp_indstr_emp_ind;
在取之前可用memset(&str_emp,0,sizeof(str_emp)).清空該結(jié)構(gòu)體,這樣如果是字符型的NULL,會(huì)為"",整型的NULL會(huì)為0,
浮點(diǎn)型的會(huì)為0.00。此時(shí)不會(huì)有-1405錯(cuò)誤。
(3)也可采用NVL()函數(shù):舉例如下:
EXEC SQL DECLAREauthors CURSOR FOR
SELECT EMPNO,NVL(ENAME,chr(0)),nvl(to_char(HIREDATE,''yyyy/mm/ddhh24:mi:ss''),chr(0)),NVL(SAL,0) FROM EMP;
這樣也不會(huì)有-1405錯(cuò)誤不,當(dāng)取出的值是NULL時(shí),自動(dòng)用NVL()中指定的值代替.
CHR(0)也可直接用''''代替,如下:
SELECT EMPNO,NVL(ENAME,''''),nvl(to_char(HIREDATE,''yyyy/mm/ddhh24:mi:ss''),''''),NVL(SAL,0) FROM EMP;
5、PROC中的錯(cuò)誤的處理
所有的SQL語句都有可能出錯(cuò).所以都要加以判斷,但每個(gè)SQL語句后都加錯(cuò)誤判斷,太麻煩,可用一個(gè)函數(shù)如sql_error()來進(jìn)行錯(cuò)誤處理,
方法:
(1)定義ql_error()函數(shù)。
??(2)在開頭加上EXECSQL WHENEVER SQLERROR DO sql_error();這樣當(dāng)發(fā)生sqlca.sqlcode<0 的錯(cuò)誤時(shí),程序自動(dòng)轉(zhuǎn)到sql_error()中執(zhí)行. 注意:對(duì)sqlca.sqlcode>0的錯(cuò)誤如 sqlca.sqlcode =1403 是不會(huì)轉(zhuǎn)到sql_error()中執(zhí)行的.
另外:在UNIX下,可以用OERR 來查找錯(cuò)誤的描述。如: ora ORA -1405 查找錯(cuò)誤號(hào)為-1405的描述.
6、PROC中調(diào)用存儲(chǔ)過程的方法
要把存儲(chǔ)過程放在EXEC SQLEXECUTE 和 END-EXEC;之間,如下所示:
其中:al_empno,ac_ename 為輸入?yún)?shù),l_return,l_errno,c_errtext 為輸出參數(shù)。
al_empno=8888;
strcpy(ac_ename,"ABCD");
EXEC SQL EXECUTE
BEGIN
up_db_emp(:al_empno,:ac_ename,:l_return,:l_errno,:c_errtext);
END;
END-EXEC;
if (l_return != 0)
{
printf("調(diào)用UP_PB_EMP存儲(chǔ)過程出錯(cuò),errno=%ld,errtext=%sn",l_errno,c_errtext);
}
7、PROC的命令行選項(xiàng):PROC編譯器有很多的命令行選項(xiàng),在命令行下直接不帶參數(shù)運(yùn)行PROC,會(huì)列出所有的命令行選項(xiàng)來,并有說明。
(1)儲(chǔ)存過程:編譯儲(chǔ)存過程是要帶上用戶名及密碼
?procUSERID=scott/tiger sqlcheck=SEMANTICS ireclen=512 iname=test.cpp
(2)PARSE=NONE 對(duì)非SQL代碼不進(jìn)行語法分析,默認(rèn)對(duì)非SQL代碼也進(jìn)行語法分析.
在RED HAD6.3上的ORACLE8.1.5中用PROC時(shí),會(huì)提示:/USR/INCLUDE/STDIO.H 及其他的.H文件中有錯(cuò). 可把PARSE=NONE加上,就好了.
8、注意加上:EXECORACLE OPTION (RELEASE_CURSOR = YES);
RELEASE_CURSOR=YES 使PROC 在執(zhí)行完后釋放與嵌入SQL有關(guān)資源,保證在該P(yáng)ROC程序執(zhí)行完后,ORACLE不會(huì)鎖住數(shù)據(jù)庫資源,如鎖表等。
如果在PROC中用到ORACA,還要在程序頭加上:
EXEC ORACLE OPTION(ORACA=YES);
?
轉(zhuǎn)載出處:http://blog.sina.com.cn/s/blog_9b0604b40101kueq.html
轉(zhuǎn)載于:https://blog.51cto.com/aaroncao/1793297
總結(jié)
以上是生活随笔為你收集整理的ORACLE的ProC用法讲解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fir.im Weekly - 2016
- 下一篇: android图片加载库Glide