標籤:
pro*c是進階的用法,OCI是oracle的基礎用法
如何編譯.pc檔案: proc code=cpp parse=none iname=filename.pc oname=filename.cpp
一, 首先要包涵標頭檔#include 這個標頭檔
二, 在聲明宿主變數之前一定要先定義struct sqlca sqlca;這個變數。
三, 所有與oracle資料庫SQL語句有關的變數必須在前面聲明為宿主變數分配空間才可以使用,
宿主變數只能是oracle支援的資料類型,一般是基本類型的,結構體類型。只有宿主變數才可以和SQL還有函數中的其他變數之間相互連信。
例子:
EXEC SQL BEGIN DECLARE SECTION; //開始申明
char strsql[512]={0};
EXEC SQL END DECLARE SECTION; //結束申明
四,靜態SQL語句之查一條記錄的模式,通過宿主變數接收申sql語句所查到的結果
舉例:INTO :TotalRecord, :TotalMoney ,接收結果,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 and A.region=trim(:areacode) and B.pay_date = :sqltime;
五,查詢多條記錄一般我們使用動態SQL語句,結合遊標來收集多條記錄的結果,其次要注意的是迴圈得到結構。
舉例:sprintf(strsql,"select *from mytable ")
EXEC SQL PREPARE SqlCountRegion FROM :strsql; //或者活動區
EXEC SQL DECLARE CurRegion CURSOR FOR SqlCountRegion; //對活動區申請遊標
EXEC SQL OPEN CurRegion; //開啟遊標,開啟遊標的同時可以用using對其賦值
do{
EXEC SQL FETCH CurRegion INTO :regionnum ; //迴圈捕捉遊標中變數的值
if (sqlca.sqlcode ==1403)
break;
cout<<regionnum<<endl;
}while(1);
EXEC SQL CLOSE CurRegion; //關閉遊標
EXEC SQL rollback work release; //復原資料關閉釋放所有資源和連結
六,捕捉異常錯誤和停止程式
//下面的意思是發生錯誤異常的時候跳轉到標記處執行標記後面的語句
EXEC SQL whenever sqlerror goto errinfo;
errinfo:
printf(" sqlca.sqlcode=%d, sqlca.errm=%s\n",sqlca.sqlcode, sqlca.sqlerrd);
EXEC SQL whenever sqlerror stop; //發生異常的時候推出整個程式,關閉所有串連釋放所有資源
return sqlca.sqlcode;
七, proc中的SQL語句不要加分號(;) ,注釋如果是C++工程使用如果是C++使用//或者,在oracle中的注釋是--, oracle資料庫中的資料如果資料位元組不足位元,預設用空格補全,宿主變數的空間要大於資料庫的欄位空間。
對於結構的特殊含義處理:sqlca.sqlcode ==1403 表示結束了尋找迴圈,這個在動態sql語句中比較重要,
sqlca.sqlcode == -1405 表示查詢值為空白的時候報的錯誤,這個最好留給傳回值待程式處理,
sqlca.sqlcode == -1480 表示在sql語句中傳入的變數時空值一般就是傳值失敗,可能是空間的大小問題。
八, 關於Proc中特殊的SQL語句,如,delete ,update,alter,insert into 等資料變動性操作的時候,
要注意2點,可以再宿主變數區申請複雜的結構類型的指標,用指標將參數外部的資料繫結到sql語句中,接下來就是提交事物,操作完變動性資料之後就是commint提交事物,進行復原。
例子:
int GetDBRecode( struct buf * tempbuf)
{
EXEC SQL BEGIN DECLARE SECTION; //開始申明
char strsql[512]={0};
struct buf * temp= tempbuf;
EXEC SQL END DECLARE SECTION; //結束申明
exec sql insert into mytable( name, sex, num)values( :temp->name, :temp->sex, :temp->num)
if( sqlca.sqlcode )
{
printf("判斷是否執行成功");
}
}
例子講解
//#include //#include
//#include"CssCheckBill.h"
//#include
int main()
{
struct sqlca sqlca; //必須要有
EXEC SQL BEGIN DECLARE SECTION;
char strsql[512]={0};
char user[20]={0};
char pwd[20] ={0};
char dbname[20]={0};
char regionnum[7];
char TotalMoney[15]={0};
char TotalRecord[15]={0};
EXEC SQL END DECLARE SECTION;
strcpy(user,"user");
strcpy(pwd,"pwd");
strcpy(dbname,"dbname");
//這句是串連資料庫的操作
EXEC SQL CONNECT :user IDENTIFIED BY :pwd USING :dbname;
EXEC SQL select count(B.msisdn) ,sum(B.payamount)
INTO :TotalRecord, :TotalMoney //INTO綁定變數
from OM_MPAY_USER_INFO A , OM_MPAY B
WHERE A.msisdn = B.msisdn and A.region=trim(:areacode) and B.pay_date = :sqltime;
//設定捕獲異常資訊標誌
EXEC SQL whenever sqlerror goto ORA_ERR;
if(0 >= ::snprintf(strsql,sizeof(strsql), "select distinct(region) from OM_MPAY_USER_INFO where region is not null" ))
{
printf("%s snprintf create sql fail !\n", __FUNCTION__);
return -1;
}
//動態資料指標方式擷取查詢結果
EXEC SQL PREPARE SqlCountRegion FROM :strsql;
EXEC SQL DECLARE CurRegion CURSOR FOR 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);
//關閉異常捕獲資訊
EXEC SQL whenever sqlerror stop;
EXEC SQL CLOSE CurRegion;
//設定復原事物
EXEC SQL rollback work release;
return sqlca.sqlcode;
ORA_ERR:
printf("sqlca.sqlcode=%d, sqlca.sqlerrp=%s\n",sqlca.sqlcode, sqlca.sqlerrp);
return sqlca.sqlcode;
return 0 ;
}
總結了一下PRO*C中預存程序調用,普通SQL語句遊標執行,動態SQL語句遊標執行的方法;
PRO*C中常用SQL及遊標、預存程序使用匯總:
1) exec sql select c1,c2 into :v1,v2 from table_a;
2) exec sql insert into table_a(v1,v2) select b.v1,b.v2 from table_b b where 1=2;
3) exec sql insert into table_a(v1,v2) select b.v1,b.v2 from table_b b where 1=2;
預存程序調用
4) exec sql call procedure_a(:v1,:v2);
5) sprintf(sta,"select v1,v2 into :v1,v2 from table_a where v3=%s",v3);
exec sql execute immediate :sta;
--普通SQL語句遊標執行
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;
--動態SQL語句遊標執行
7)> sprintf(sta,"select c1,c2,c3 from table_a where c1=%s and c2=:v1 and 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; //開啟遊標的時候使用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語句中用到的變數稱為宿主變數。他們應在EXEC SQL BEGIN DECLARE SECTION;與EXEC SQL EDN DECLARE SECTION; 之間聲明,如上面所示,在聲明宿主變數時應注意以下幾點:
(1) 在資料庫表中定義為VARCHAR2,VARCHAR,CHAR的欄位,在PROC中可聲明為CHAR,但長度應為它們在表中定義的長度加1,因為PROC中CHAR型變數用做結尾。
如:ENAME在表中的定義為ename varchar2(10),在PROC中可定義為:
EXEC SQL BEGIN DECLARE SECTION;
char ename[11];
EXEC SQL END DECLARE SECTION;
常見錯誤說明:
如果插入的字串長度大於10,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES(‘12345678901’);會出現以下錯誤:
error:ORA-01480: STR 賦值變數缺少空尾碼。
如果定義為:
EXEC SQL BEGIN DECLARE SECTION;
char ename[15];
EXEC SQL END DECLARE SECTION;
當插入的字串長度大於10,小於15時,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES(‘12345678901’);會出現以下錯誤:
error:ORA-01401: 插入的值對於列過大。
當插入的字串長度大於15,如:EXEC SQL INSERT INTO EMP(ENAME) VALUES(‘12345678901234‘);會出現以下錯誤:
error:ORA-01401:STR 賦值變數缺少空尾碼。
(2) 從SQL語句中取欄位的值到宿主變數中時,PROC不會自動給宿主變數去掉右空格。而是以在DECLARE SECTION 中定義的長度為準(與 表中定義的無關)不足補右空格.如果不注意這一點,在PROC中進行字串操作時(如比較相等)會出錯。如:
EXEC SQL BEGIN DECLARE SECTION;
char ename[10];
EXEC SQL END DECLARE SECTION;
如果ENAME在表中的值為‘‘abc‘‘,則取出的值為‘‘abc ‘‘;
可用語句EXEC SQL VAR重定義CHAR型變數。這樣宿主變數會自動去掉右空格。如下:
EXEC SQL BEGIN DECLARE SECTION;
char ename[11];
EXEC SQL VAR ac_ename IS STRING(11);
EXEC SQL END DECLARE SECTION;
如果ENAME在表中的值為‘‘abc‘‘,則取出的值為‘‘abc‘‘;
(3) 對浮點型的變數,為保證精度,最好是聲明成DOUBLE型的.因為DOUBLE型的精度比FLOAT型高很多.
(4) 整型可聲明為LONG型(對較長的整型,而且所用的平台支援的話,如在SUN平台上,可聲明為LONG LONG型).
(5) DATE型的處理:DATE型一般聲明為CHAR(20)。
往表中插入DATE型資料時,一般用TO_DATE()函數進行類型轉換,取出值時一般用TO_CHAR()函數進行類型轉換.
EXEC SQL select to_char(hiredate,‘‘yyyy/mm/dd hh24:mi:ss‘‘) into :ac_hire_date from EMP where empno=1234;
EXEC SQL insert into EMP(EMPNO,HIREDATE) values(123,to_date(:ac_hiredate,‘‘yyyy/mm/dd hh24:mi:ss‘‘);
2、宿主變數的作用範圍
如果宿主變數在所有的函數之外聲明,則他們是全域變數。在使用之前要注意把變數的值初始化,宿主變數也可以在某個函數的內部定義。這時他們是局部變數。一般都習慣把宿主變數聲明為全域變數。
3、資料庫的串連與斷開
資料庫的串連有以下兩種方法:
(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 :user identified by :pass;
注意:在有些平台上兩種都可以,在有些平台上只能用第一種方法.
在PROC程式中,要記住用EXEC SQL ROLLBACK WORK RELEASE;斷開與資料庫的串連,並釋放相關的資料庫資源。
4、PROC中的NULL值的處理
如果某一欄位取出的值是NULL,會報:sqlcode=-1405, sqlerr=ORA-01405: 讀取的列值為 NULL並且相應的宿主變數的值不會被改變,為執行該SQL語句之前的值. 常用的處理NULL值的方法有:
(1)採用指標變數,此時不會有-1405錯誤,當必須是所以為NULL的欄位都有相應的指標變數,如果某一欄位沒有指標變數,但取出的值為NULL值,則仍然會有-1405錯誤.當取出的值是NULL時,相應的指標變數變數為-1,可根據指標變數的值做響應的處理。
(2)如果欄位較多,可取欄位到一個結構體中及與該結構體對應的指標結構體中.如上面的例子中可定義結構體:
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;
};
struct str_emp str_emp;
strcut str_emp_ind str_emp_ind;
在取之前可用memset(&str_emp,0,sizeof(str_emp)).清空該結構體,這樣如果是字元型的NULL,會為"",整型的NULL會為0,
浮點型的會為0.00。此時不會有-1405錯誤。
(3)也可採用NVL()函數:舉例如下:
EXEC SQL DECLARE authors CURSOR FOR
SELECT EMPNO, NVL(ENAME,chr(0)),nvl(to_char(HIREDATE,‘‘yyyy/mm/dd hh24:mi:ss‘‘),chr(0)),NVL(SAL,0) FROM EMP;
這樣也不會有-1405錯誤不,當取出的值是NULL時,自動用NVL()中指定的值代替.
CHR(0)也可直接用‘‘‘‘代替,如下:
SELECT EMPNO, NVL(ENAME,‘‘‘‘),nvl(to_char(HIREDATE,‘‘yyyy/mm/dd hh24:mi:ss‘‘),‘‘‘‘),NVL(SAL,0) FROM EMP;
5、PROC中的錯誤的處理
所有的SQL語句都有可能出錯.所以都要加以判斷,但每個SQL語句後都加錯誤判斷,太麻煩,可用一個函數如sql_error()來進行錯誤處理,
方法:
(1)定義ql_error()函數。
(2)在開頭加上EXEC SQL WHENEVER SQLERROR DO sql_error();這樣當發生sqlca.sqlcode <0 的錯誤時,程式自動轉到sql_error()中執行. 注意:對sqlca.sqlcode >0的錯誤如 sqlca.sqlcode =1403 是不會轉到sql_error()中執行的.
另外:在UNIX下,可以用OERR 來尋找錯誤的描述。如: ora ORA -1405 尋找錯誤號碼為-1405的描述.
6、PROC中調用預存程序的方法
要把預存程序放在EXEC SQL EXECUTE 和 END-EXEC;之間,如下所示:
其中:al_empno,ac_ename 為輸入參數,l_return,l_errno,c_errtext 為輸出參數。
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("調用UP_PB_EMP預存程序出錯,errno=%ld,errtext=%sn",l_errno,c_errtext);
}
7、PROC的命令列選項:PROC編譯器有很多的命令列選項,在命令列下直接不帶參數運行PROC,會列出所有的命令列選項來,並有說明。
(1)儲存過程:編譯儲存過程是要帶上使用者名稱及密碼
proc USERID=scott/tiger sqlcheck=SEMANTICS ireclen=512 iname=test.cpp
(2)PARSE=NONE 對非SQL代碼不進行文法分析,預設對非SQL代碼也進行文法分析.
在RED HAD6.3上的ORACLE8.1.5中用PROC時,會提示:/USR/INCLUDE/STDIO.H 及其他的.H檔案中有錯. 可把PARSE=NONE加上,就好了.
8、注意加上:EXEC ORACLE OPTION (RELEASE_CURSOR = YES);
RELEASE_CURSOR=YES 使PROC 在執行完後釋放與嵌入SQL有關資源,保證在該PROC程式執行完後,ORACLE不會鎖住資料庫資源,如鎖表等。
如果在PROC中用到ORACA,還要在程式頭加上:
EXEC ORACLE OPTION (ORACA=YES);
原文地址:http://blog.sina.com.cn/s/blog_9b0604b40101kueq.html
[轉]ORACLE的ProC用法講解