oracle中pro*c的學習

oracle中pro*c的學習
一 Pro*C 程序概述:
1.什麼是Pro*C程序
ORACLE數據庫管理和系統中, 有三種訪問數據庫的方法;
(1) 用SQL*Plus, 它有SQL命令以交互的應用程序訪問數據庫;
(2) 用第四代語言應用開發工具開發的應用程序訪問數據庫,這些工具有SQL*Froms,QL*Reportwriter,SQL*Menu等;
(3) 利用在第三代語言內嵌入的SQL語言或ORACLE庫函數調用來訪問。
Pro*C就屬於第三種開發工具之一, 它把過程化語言C和非過程化語言SQL最完善地結合起來, 具有完備的過程
處理能力,又能完成任何數據庫的處理品任務,使用戶可以通過編程完成各種類型的報表。在Pro*C程序中可以嵌入SQL語言, 利用這些SQL語言可以完成動態地建立、修改和刪除數據庫中的表,也可以查詢、插入、修改和刪除數據庫表中的行, 還可以實現事務的提交和回滾。
在Pro*C程序中還可以嵌入PL/SQL塊, 以改進應用程序的性能, 特別是在網絡環境下,可以減少
網絡傳輸和處理的總開銷。

 

2.Pro*C的程序結構圖
通俗來說,Pro*C程序實際是內嵌有SQL語句或PL/SQL塊的C程序, 因此它的組成很類似C程序。 但因爲它內嵌有SQL語句或PL/SQL塊, 所以它還含有與之不同的成份。爲了讓大家對Pro*C有個感性的認識, 特將二者差別比較如下:
C的全程變量說明
C源程序 函數1:同函數K。
函數2:同函數K。 
C的局部變量說明
函數K 
可執行語句

應用程序首部 C的外部變量說明
外部說明段(ORACLE變量說明)
通訊區說明

Pro*C源程序 函數1:同函數K。
函數2:同函數K。
C局部變量說明
程序體 內部說明部分 內部說明段
通訊區說明
函數K C的可執行語句 
可執行語句 SQL的可執行語句 
或PL/SQL塊

二.Pro*C程序的組成結構

每一個Pro*C程序都包括兩部分:(1)應用程序首部;(2)應用程序體
應用程序首部定義了ORACLE數據庫的有關變量, 爲在
C語言中操縱ORACLE數據庫做好了準備。應用程序體基本上由Pro*C的SQL語句調用組成。主要指查詢SELECT、INSERT、UPDATE、DELETE等語句。
應用程序的組成結構如圖所示: 
EXEC SQL BEGIN DECLARE SECTION (SQL變量的定義)EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLLA;
EXEC SQL CONNECT:< 用戶名> IDENTIFIED BY: < 口令 >
SQL 語句及遊標的使用

1. 應用程序首部
應用程序的首部就是Pro*C的開始部分。它包括以下三部分:
l C變量描述部分;
l SQL變量描述部分(DECLARE部分);
l SQL通信區。

(1) .DECLARE部分(描述部分)
描述部分說明程序的SQL變量, 定義部分以EXEC SQL BEGIN DECLARE SECTION ;開始和以 EXEC SQL END DECLARE SECTION ;結束的。它可以出現在程序的主部,也可出現在局部
l SQL變量的說明和使用
在說明段能爲SQL變量指定的數據類型如表所示:
數據類型 描述
CHARCHAR(n)INT SHORT LONG FLOAT DOUBLE VARCHAR 單字符n個字符數組整數短整數單精度浮點數雙精度浮點數變長字符串
這些數據類型實際上就是C語言的數據類型, 其中VARCHAR中視爲C數據類型的擴充。這在以後會談到。
SQL變量的使用應注意以下幾點:
l 必須在描述部分明確定義
l 必須使用與其定義相同的大小寫格式
l 在SQL語句中使用時,必須在其之前加一個“:”(冒號),但在C語句中引用時不需加冒號。
l 不能是SQL命令中的保留字。
l 可以帶指示變量。
例如:EXEC SQL BEGIN DECLARE SECTIONS;
VARCHAR programe[30];
Int porgsal, pempno;
EXEC SQL END DECLARE SECTION;


EXEC SQL SELECT ENAME , SAL 
INTO: programe, : progsal 
FROM EMP 
WHERE EMPNO = : pempno;

(2). 指示器變量的說明和引用
指示變量實際上也是一類SQL變量,它被用來管理與其相關聯的宿主變量(即在SQL語句中充 當輸入或輸出的變量)。每一個宿主變量都可定義一個指示器變量,主要用於處理空值(NULL)
指示器變量的說明基本同一般SQL變量一樣, 但必須定義成2字節的整型,如SHORT、INT。在SQL語句中引用時, 其前也應加“:”(冒號),而且必須附在其相關聯的宿主變量之後,在C語句中,可獨立使用。當指示器變量爲-1時,表示空值。例如:
EXEC SQL BEGIN DECLARE SECTION ; 
INT dept- number;
SHORT ind – num;
CHAR emp –name;
EXEC SQL END DECLARE SECTION ;

Scanf(“90d %s”, & dept- number , dept – name );
If (dept – number ==0)
Ind – num = -1;
Else 
Ind – num = 0;
EXEC SQL INSERT INTO DEPT (DEPTNO, DNAME)
VALUES(:dept – number : ind- num , :dept – name);
其中ind – num是dept – number 的指示器變量。當輸入的dept – number 值是0時, 則向DEPT 表的DEPTNO列插入空值。
(3).指針SQL變量的說明和使用


指針SQL變量在引用前也必須在DECLARE 部分先說明。其說明格式同C語言。在SQL語句中引用時,指針名字前要加前綴“:”(冒號)而不加“*”(星號)。在C語句中用法如同C語言的指針變量。
(4).數組SQL變更的說明和引用
在SQL語句中引用數組時,只需寫數組名(名字前加冒號), 不需寫下標,在C語句中用法如同C語言的數組變量。
使用數組可大大降低網絡傳輸開銷。如要向一表插入100行數據,如果沒有數組,就要重複100次, 而引用後,只須執行一次insert語句、便可一次性插入。例如:
EXEC SQL BEGIN DECLARE SECTION;
Int emp_number[100];
Char emp_name[100][15];
Float salary[100],commission[100];
Int dept_number;
EXEC SQL END DECLARE SECTION;
….
EXEC SQL SELECT EMPNO,ENAME,SAL,COMM
INTO :emp_number,:emp_name,:salary,:commission
FROM EMP
WHERE DEPTNO=:dept_number;
在使用數組時,應注意以下幾點;
l 不支持指針數組
l 只支持一維數組, 而 emp-name [100][15]視爲一維字符串
l 數組最大維數爲32767
l 在一條SQL語句中引用多個數組時,這些數組維數應相同
l 在VALUES , SET, INTO 或WHERE子名中, 不允許把簡單SQL變量與數組SQL變量混用
l 不能在DELARE部分初始化數組
例如:下面的引用是非法的
EXEC SQL BEGIN DECLARE SECTION;
Int dept – num [3] = ;
EXEC SQL END DECLARE SECTION ;

EXEC SQL SELECT EMPNO, ENAME , SAL
INTO : emp – num [ i ], : emp – name [ i ], : salarg [ i ]
FROM EMP 
(5) 僞類型VARCHAR的說明和引用
VARCHAR變量在引用之前也必須在說明段說明, 說明時必須指出串的最大 
長度,如:
EXEC SQL BEGIN DECLARE SECTION;
Int book – number; 
VARCHAR book – name [ 50 ];
EXEC SQL END DECLARE SECTION ; 
在預編繹時, book – name 被翻譯成C語言中的一個結構變量;
Struct { unsigned short len ;
Unsigned chart arr [ 20 ] ; 
} boo – name 
由此看出, VARCHAR變量實際上是含長度成員和數組成員的結構變量。在SQL語句中引用時,應引用以冒號爲前綴的結構名, 而不加下標,在C語句 中引用結構成員。
VARCHAR變量在作輸出變量時,由ORACLE自動設置, 在作爲輸入變量時,程序應先把字符串存入數組成員中, 其長度存入長度成員中,然後再在SQL語句中引用。例如:
Main( )
{ .......
scanf(“90s, 90d’, book – name .arr, & book – number );
book – name .len = strlen (book – name .arr);
EXEC SQL UPDATE BOOK 
SET BNAME = : book – name ;
BDESC = : book – number ;

(6) SQL通信區
SQL 通信區是用下列語句描述的:
EXEC SQL INCLUDE SQLCA;
此部分提供了用戶運行程序的成敗記錄和錯誤處理。

SQLCA的組成
SQLCA是一個結構類型的變量,它是ORACLE 和應用程序的一個接口。在執行 Pro*C程序時, ORACLE 把每一個嵌入SQL語句執行的狀態信息存入SQLCA中, 根據這些信息,可判斷SQL語句的執行是否成功,處理的行數,錯誤信息等,其組成如表所示:
Struct sqlca
{ char sqlcaid [ 8 ] ; ----à標識通訊區
long sqlabc; ---à 通訊區的長度
long sqlcode; ---à保留最近執行的SQL語句的狀態碼
struct { unsigned short sqlerrml; -----à信息文本長度
}sqlerrm;
char sqlerrp [ 8 ];
long sqlerrd [ 6 ];
char sqlwarn [ 8 ];
char sqlext [ 8 ];
}
struct sqlca sqlca;
其中, sqlcode在程序中最常用到,它保留了最近執行的SQL語句的狀態碼。程序員根據這些狀態碼做出相應的處理。這些狀態碼值如下:
0: 表示該SQL語句被正確執行,沒有發生錯誤和例外。
>0:ORACLE執行了該語句,但遇到一個例外(如沒找到任何數據)。


<0:表示由於數據庫、系統、網絡或應用程序的錯誤,ORACLE未執行該SQL語句。 
當出現此類錯誤時,當前事務一般應回滾。 
2.應用程序體
在Pro*C程序中, 能把SQL語句和C語句自由地混合書寫,並能在SQL語句中使用SQL變量,嵌入式SQL語句的書寫文法是:
l 以關鍵字EXEC SQL開始
l 以C語言的語句終結符(分號)終結
SQL語句的作用主要用於同數據庫打交道。C語言程序用於控制,輸入,輸出和數據處理等。
(1) 連接到ORACLE數據庫
在對數據庫存取之前,必須先把程序與ORACLE數據庫連接起來。即登錄到ORACLE上。所連接命令應該是應用程序的第一個可執行命令。連接命令格式如下:
EXEC SQL CONNECT:< 用戶名 > IDENTIFIED BY : < 口令 >
或EXEC SQL CONNECT: < 用戶名 > / < 口令 >
在使用上述兩種格式進行登入時, 應當首先在說明段定義包含用戶名和口令的 
SQL 變量,並在執行CONNECT之前設置它們,否則會造成登錄失敗。例如:
EXEC SQL BEGIN DECLARE SECTION ;
VARCHAR usename [20];
VARCHAR password[20];
EXEC SQL END DECLARE 
..........
strcpy ( usename.arr, “CSOTT’);
usename.len = strlen (username.arr);
strcpy (password.arr , “TIGER’);
password .len = strlen( password .arr);
EXEC SQL WHENEVER SQLERROR GOTO SQLERR;
EXEC SQL CONNECT :username INDNTIFIED BY : password;
注意: 不能把用戶名和口令直接編寫到CONNECT語句中,或者把用引號(’)括起來的字母串在CONNECT 語句中, 如下面的語句是無效的。
EXEC SQL CONNECT SCOTT INENTIFIED BY TIGER; 
EXEC SQL CONNECT ‘SCOTT’ IDENTIFIED BY ‘TIGER’;
(2). 插入、更新和刪除
在講述SQL語言時已詳細講過, 這裏就不舉例說明了。
(3). 數據庫查詢及遊標的使用
在PRO*C中, 查詢可分爲兩種類型:
l 返回單行或定行數的查詢;
l 返回多行的查詢.此種查詢要求使用遊標來控制每一行或每一組(主變量用數組).
1) 返回單行或定行數的查詢
在PRO*C中的查詢SQL SELECT語句由以下幾個子句組成:
SELECT
INTO
FROM
WHERE
CONNECT BY 
UNION
INTERSECT
MINUS
GROUP BY 
HAVING 
ORDER BY 
其中WHERE子句中的查詢條件可以是一個屬性或多個屬性的集合,在執行是賦值的主變量也可放在WHERE子句中.WHERE子句中所用的主變量稱爲輸入主變量。如:


SELECT EMPNO, JOB, SAL 
INTO:PNAME, :PJOB, :PSAL
FROM EMP
WHERE EMPNO=:PEMPNO;
若沒有找到限定的行, 則SQLCA.SQLCODE返回”+1403”, 表明”沒有找到”。
INTO從句中的主變量叫輸出主變量,它提供了查詢時所需要的信息。
在任何項送給主變量之前,都要求ORACLE把這些項轉換成主變量的數據類型。對於數字是通過截斷來完成的(如:9.23轉換爲9)。
如果已確定查詢只返回一行,那麼就不必使用遊標,只給SELECT語句增加一個INTO子句即可。在語義上INTO語句在FROM之前的查詢中有多少個選擇項就有多少個輸出主變量。若在SELECT項中表達式的數目不等於INTO子句中主變量的數目,就把SQLCA.SQLWARN[3]置爲”W”。 
2)多行查詢及遊標的使用
如果查詢返回多行或不知道返回多少行,使用帶有ORACLE遊標(CURSOR)的SELECT語句。
遊標是ORACLE和PRO*C存放查詢結果的工作區域。一個遊標(已命名的)與一條SELECT語句相關聯。操作遊標有由4條命令:(1)DECLARE CURSOR;(2)OPEN CURSOR;(3)FETCH;(4)CLOSE CURSOR。

A. 定義遊標
一個遊標必須首先定義, 才能使用它。語法爲:
EXEC SQL DECLARE 〈遊標名〉CORSOR FOR 
SELECT 〈列〉
FROM 〈表〉
例如:
EXEC SQL DECLARE CSOR, CURSOR FOR


轉載網上的一篇文章支持一下。
PROC是ORACLE數據庫提供的編程接口之一,其應用十分的廣泛,本文通過一個具體的例子,介紹PROC編程的一些經驗及應注意的地方。 
例子程序: 
#include 
#include 
#include 
#include 
#include


EXEC SQL INCLUDE sqlca; 
/*RELEASE_CURSOR=YES 使PROC 在執行完後釋放與嵌入SQL有關資源*/ 
EXEC ORACLE OPTION (RELEASE_CURSOR = YES);

EXEC SQL BEGIN DECLARE SECTION; 
varchar vc_user[20]; 
long al_empno=0; 
char ac_ename[11]=""; 
char ac_hiredate[20]=""; 
double af_sal=0;

EXEC SQL VAR ac_ename IS STRING(11); 
EXEC SQL VAR ac_hiredate IS STRING(20);

EXEC SQL END DECLARE SECTION;


/*錯誤處理函數*/ 
void sql_error(char *msg) 

printf("/n%s,%ld,%s/n", msg,sqlca.sqlcode,(char *)sqlca.sqlerrm.sqlerrmc); 
EXEC SQL ROLLBACK RELEASE; 
exit(-1); 
}


main() 

EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE ERROR: ");

/*連接數據庫*/ 
strcpy(vc_user.arr,"scott/tiger@DEMO"); 
vc_user.len=16; 
exec sql connect :vc_user;

EXEC SQL DECLARE cur_emp CURSOR FOR 
SELECT EMPNO, ENAME,to_char(HIREDATE,'yyyy/mm/dd hh24:mi:ss'),SAL FROM EMP;

EXEC SQL OPEN cur_emp; 
while(1) 

al_empno=0; 
strcpy(ac_ename,""); 
strcpy(ac_hiredate,""); 
af_sal=0; 
EXEC SQL FETCH cur_emp INTO :al_empno, :ac_ename:ename_ind, :ac_hiredate:hiredate_ind, :af_sal:sal_ind; 
if( sqlca.sqlcode == 1403) 

break; 

printf("empno=%ld,ename=%s,hiredate=%s,sal=%lf/n",al_empno,ac_ename,ac_hiredate,af_sal);

EXEC SQL CLOSE cur_emp; 
EXEC SQL ROLLBACK WORK RELEASE; 
}

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=%s/n",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);

9、PROC中的類型轉換 
一、在C語言中: 
(1)字符型到整型可用ATOI() ATOL(),SSCANF() 
(2)整型,浮點型到字符型,可用SPRINTF() 
(3)字符型到浮點型用ATOF()不行,最好用SSCANF(),舉例如下:

EXEC SQL BEGIN DECLARE SECTION; 
double d_demo; 
float f_demo; 
char ac_text[20]="222"; 
EXEC SQL END DECLARE SECTION;

(1)sscanf(ac_text, "%f", &d_demo); 
printf("ac_text=%s,d_demo=%f/n",ac_text,d_demo);

(2)sscanf(ac_text, "%lf", &d_demo); 
printf("ac_text=%s,d_demo=%f/n",ac_text,d_demo);

(3)sscanf(ac_text, "%f", &d_demo); 
printf("ac_text=%s,d_demo=%lf/n",ac_text,d_demo);

(4)sscanf(ac_text, "%lf", &d_demo); 
printf("ac_text=%s,d_demo=%lf/n",ac_text,d_demo);

printf("*******************/n"); 
(5)sscanf(ac_text, "%f", &f_demo); 
printf("ac_text=%s,f_demo=%f/n",ac_text,f_demo);

(6)sscanf(ac_text, "%lf", &f_demo); 
printf("ac_text=%s,f_demo=%f/n",ac_text,f_demo);

(7)sscanf(ac_text, "%f", &f_demo); 
printf("ac_text=%s,f_demo=%lf/n",ac_text,f_demo);

(8)sscanf(ac_text, "%lf", &f_demo); 
printf("ac_text=%s,f_demo=%lf/n",ac_text,f_demo);

輸出的結果: 
ac_text=222.00,d_demo=0.000000 
ac_text=222.00,d_demo=222.000000 
ac_text=222.00,d_demo=222.000032 
ac_text=222.00,d_demo=222.000000 
******************* 
ac_text=222.00,f_demo=222.000000 
ac_text=222.00,f_demo=0.000000 
ac_text=222.00,f_demo=222.000000 
ac_text=222.00,f_demo=0.000000 
d_demo=atof(ac_text); 
printf("ac_text=%s,atof(ac_text)=%f/n",ac_text,d_demo);

d_demo=atof(ac_text); 
printf("ac_text=%s,atof(ac_text)=%lf/n",ac_text,d_demo);

f_demo=atof(ac_text); 
printf("ac_text=%s,atof(ac_text)=%f/n",ac_text,f_demo);

f_demo=atof(ac_text); 
printf("ac_text=%s,atof(ac_text)=%lf/n",ac_text,f_demo);

輸出的結果: 
ac_text=222.00,atof(ac_text)=1243288.000000 
ac_text=222.00,atof(ac_text)=1243288.000000 
ac_text=222.00,atof(ac_text)=1243288.000000 
ac_text=222.00,atof(ac_text)=1243288.000000

從上面的結果可見: 
DOUBLE型應採用sscanf(ac_app_capcity, "%lf", &d_app); 打印用"%lf","%f" 都可以. (2),(4)正確 
FLOAT型應採用sscanf(ac_app_capcity, "%f", &d_app); 打印用"%lf","%f" 都可以. (5),(7)正確 
採用ATOF()轉換的結果都是錯的,所以不要用它。 
二、寫表或從表中取數據時: 
(1)字符型與整型之間可不用轉換,採用默認方式。 
(2)字符型與浮點型之間可不用轉換,採用默認方式。 
(3)日期型與字符型之間可用TO_CHAR(),TO_DATE()。


10、PROC中的4種動態SQL簡介 
(1)動態SQL1: 不能是查詢(SELECT)語句,並且沒有宿主變量. 
用法:拼一串動態SQL語句,並用EXECUTE IMMEDIATE執行,如: 
EXEC SQL EXECUTE IMMEDIATE "CREATE TABLE dyn1 (col1 VARCHAR2(4))";

(2)動態SQL2: 不能是查詢(SELECT)語句,並且輸入的宿主變量數目是知道的, 
用法:拼一串動態SQL語句,用PREPARE,EXECUTE語句執行. 
strcpy(c_sql, "DELETE FROM EMP WHERE EMPNO = :?"); 
EXEC SQL PREPARE sql_stmt FROM :c_sql; 
EXEC SQL EXECUTE sql_stmt USING :emp_number;

(3)動態SQL3: 用於創建動態查詢, 並且要查詢的字段及輸入的宿主變量數目是知道的 
用法: 拼一串動態SQL語句,用PREPARE分析該語句,並要定義一個CURSOR進行取值 
如:如要查詢的數據按一年12月放到12張表中。表名爲user_fee_1mon, user_fee_2mon,....可採用動態SQL3來進行查詢 
strcpy(c_sql,"select c_user_id,c_user_name,to_char(t_date,'yyyy/mm/dd hh:mi:ss'),n_fee/n"); 
strcat(c_sql,"from USER_FEE_"); 
strcat(c_sql,ac_mon); 
strcat(c_sql," /n where c_user_id = :v1");

EXEC SQL PREPARE s FROM :c_sql;

EXEC SQL DECLARE cur_user_fee CURSOR FOR s;

EXEC SQL OPEN cur_user_fee USING :ac_user_id;

while(1) 
{

EXEC SQL FETCH cur_user_fee into :c_user_id,:c_user_name,:c_date,:n_fee);

if (sqlca.sqlcode < 0) 

/*FETCH CURSOR失敗*/ 
printf("fetch cursor cur_user_fee fail,sqlcode=%ld,sqlserr=%s",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc); 

if( sqlca.sqlcode == SQLNOTFOUND) 

break; 


EXEC SQL CLOSE cur_user_fee;

(4)動態SQL4:要處理的字段及輸入的宿主變量數目和主變量的類型事先是不知道的,如: 
INSERT INTO EMP () VALUES () 
是最複雜的動態SQL,很少用,在此不做介紹。


11、SQLCA:SQL是ORACLE的一個結構體,它的域用於最近的一條SQL語句執行後的一些信息,如錯誤號,錯誤描述,警告,狀態等。常用的 
域介紹如下: 
SQLCA.sqlcode:錯誤號,=0正確,=1403沒取到數據 
SQLCA.sqlserrm.sqlerrmc:錯誤描述 
SQLCA.sqlerrd[3]:最近的一條SQL語句所處理的行數,如果該語句處理失敗,則它的值是不定的,如果錯誤在一個CURSOR操作中發生,則 
它的值指已成功處理的行數.在DELETE,UPDATE中,它不包含因外鍵約束而刪除,更新的那些行,
DELETE FROM EMP WHERE DEPT='SALE'; 
在表EMP中刪除20行,但如果表EMP與表ADDRESS有外鍵約束,導致表ADDRESS也被刪除20行,則SQLCA.sqlerrd[3]=20,而不是40。


SELECT ENAME , JOB, SAL 
FROM EMP
WHERE DEPTNO=:DEPTNO;
當賦給一個與查詢相關聯的遊標CURSOR之後, 當SELECT查詢EMP時可從數據庫中返回多行,這些行就是CURSOR的一個活動區域。
注意:
1) 定義遊標必須在對遊標操作之前完成;
2) PRO*C不能引用沒有定義的遊標;
3) 遊標定義後,其作用範圍是整個程序。所以對一個程序來講, 同時定義兩個相同的遊標是錯誤的。 
B. 打開遊標
打開遊標的OPEN語句主要用來輸入主變量的內容,這些主要是WHERE中使用的主變量。打開遊標的語句是:EXEC SQL OPEN 〈遊標名〉
當打開遊標後,可以從相關的查詢中取出多於一行的結果。所有滿足查詢標準的行組成一集合,叫做"遊標活動集"。通過取操作,活動集中的每一行或每一組是一個一個返回的,查詢完成後, 遊標就可關閉了。如圖所示:
定義遊標:DECLARE

開始查詢:SELECT
打開遊標:OPEN

從活動集取數據:FETCH

查詢完成

關閉遊標:CLOSE

注意:1)遊標處於活動集的第一行前面;
2)若改變了輸入主變量就必須重新打開遊標。

C. 取數據
從活動集中取出一行或一組把結果送到輸出主變量中的過程叫取數據。輸出主變量的定義在取數據語句中。取數據的語句如下:
EXEC SQL FETCH〈遊標名〉INTO:主變量1,主變量2,……
FETCH的工作過程如圖所示:

如圖所示的查詢結果指滿足查詢條件的查詢結果。使用FETCH應注意以下幾點:
l 遊標必須先定義再打開。
l 只有在遊標打開之後才能取數據,即執行FETCH語句。
l FETCH語句每執行一次,從當前行或當前組取數據一次,下一行或下一組向上移一次。遊標每次所指的行或組都爲當前行或當前組,而FETCH每次都是取遊標所指定的行或組的數據。
l 當遊標活動集空之後,ORCLE返回一個SQLCA。SQLCA(=1403)。
l 若希望此遊標再操作, 必須先關閉再打開它。
l 在C程序中可以開闢一個內存空間,來存放操作結果,這樣就能利用開闢的空間來靈活操縱查詢的結果。 
D.關閉遊標
取完活動集中所有行後,必須關閉遊標,以釋放與該遊標有關的資源。
關閉遊標的格式爲:
EXEC SQL CLOSE 遊標名;
例如:
EXEC SQL CLOSE C1;
ORACLE V5.0版支持SQL格式“CURRENT OF CURSOR”。這條語句將指向一個遊標中最新取出的行, 以用於修改和刪除操作。該語句必須有取操作之後使用,它等同存儲一個ROWID,並使用它。

(4).舉例
EXEC SQL DECLARE SALESPEOPLE CURSOR FOR 
SELECT SSNO, NAME, SALARY
FROM EMPLOYEE
WHERE DNAME=‘Sales’;
EXEC SQL OPEN SALESPEOPLE;
EXEC SQL FETCH SALESPEOPLE
INTO :SS,:NAME,:SAL;
EXEC SQL CLOSE SALESPEOPLE;

(5)SQL嵌套的方法及應用
嵌入SQL與交互式SQL在形式上有如下差別:
1) 在SQL語句前增加前綴“EXEC SQL”, 這一小小的差別其目的是在於預編譯時容易識別出來, 以便把每一條SQL作爲一條高級語言來處理。
2) 每一SQL語句分爲說明性語句和可執行語句兩大類。可執行語句又分爲數據定義、數據控制、數據操縱、數據檢索四大類。
可執行性SQL語句寫在高級語言的可執行處;說明性SQL語句寫在高級語言的說明性的地方。
例如:在PRO*C程序中建立一個名爲BOOK的表結構,過程如下:
#include〈stdio.h〉
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR uid[20], pwd[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
Main()

/*login database*/
strcpy(uid.arr,’wu’);
uid.len=strlen(uid,arr);
strcpy(pwd.arr,’wu’);
pwd.len=strlen(pwd.arr);
EXEC SQL CONNECT:uid IDENTIFEED BY:pwd;
EXEC SQL CREATE TABLE book 
( acqnum number, copies number , price number);
EXEC SQL COMMIT WORK RELEASE;
EXIT;
PRO*C可非常簡便靈活地訪問ORCLE數據庫中的數據,同時又具有C語言高速的特點,因而可完成一些ORACLE產品不能完成的任務,例如以下一個固定的特殊格式輸出結果。
SQL嵌套源程序示例
#unclude<stdio.h>
typedef char asciz[20];
EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL TYPE asciz IS STRING (20) REFERENCE;
asciz username;
asciz password;
asciz emp_name(5);
int emp_number(5a);
float salary[5];
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE sqlca;
Void print_rows();
Void sqlerror();
Main()
{
int num_ret;
strcpy(username,”SCOTT’);
strcpy(password, “TYGER”);
EXEC SQL WHENEVER SQLERROR DO sqlerror();
EXEC SQL CONNECT:username IDENTIFIED BY:password;
Print (“/nConnected to ORACLE as user:%s/n”, username);
EXEC SQL DECLARE c1 CURSOR FOR
SELECT EMPNO , ENAME , SAL FROM EMP;
EXEC SQL OPEN c1;
Num_ret = 0;
For(;;)
{
EXEC SQL WHENEVER NOT FOUND DO break;
EXEC SQL FETCH c1 INTO : emp_number , :emp_name , :salary;
Print_rows (sqlca.sqlerrd[2] – num_ret);
Num_ret=sqlca.sqlerrd[2];
}
if ((sqlca.sqlerrd[2] – num_ret)>0);
print _rows(sqlca.sqlerrd[2] –num_ret);
EXEC SQL CLOSE c1;
Printf(“/Have a good day./n”);
EXEC SQL COMMIT WORK RELEASE;
}

void print_rows(n);
int n;
{
int i;
printf(“/nNumber Employee Salary/n”);
printf(“------------------------------/n”);
for (i=0;i<n; i++ )
printf(“% - 9d%- 8s%9.2f/n”,emp-number[i], emp---name[i],salary[i];
}
void sqlerror()
{
EXEC SQL WHENEVER SQLERROR CONTINUE;
Printf(“/noracle error detected:/n”);
Printf(‘/n%.70s/n”, sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE;
Exit(1);
}


(6) 錯誤檢測和恢復
在使用SQL語句和PRO*C對數據庫進行操作時,常常有字段空值,無條件刪除,無行返回,數據溢出和截斷等現象發生,這種現象可以用SQLCA和指示器變量來檢測。

1 SQLCA的結構
在PRO*C程序中SQLCA結構如下:
STRUCT SQLCA{
Char sqlcaid[8];
Long sqlabc;

發佈了15 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章