一 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;
Long sqlcode;
STRUCT{
Unsigned sqlerrm1;
Char sqlerrmc[10];
}sqlerrm;
Char sqlerrp[8];
Long sqlerrd[6];
Char sqlwarn[8];
Char sqlext[8];
}
其中:
1) SQLCA.sqlerrm.sqlerrmc:帶有SQLCA。SQLCODE的錯誤正文。
2) SQLCA.sqlerrd:當前ORACLE的狀態,只有SQLCA.SQLERRD[2]有意義,表示DML語句處理的行數。
3) SQLCA.sqlwarn:提供可能碰到的條件信息。在每執行一個SQL語句后,ORACLE就把返回結果放入SQLCA中,但說明語句除外。
用SQLCA可以查看SQL語句的執行結果。往往有三種結果:
=0:執行成功;
SQLCA.SQLCODE= >0:執行成功的狀態值;
<0:失敗,不答應繼續執行。2 指示器變量
指示器變量有時也稱指示變量.指示變量與一個主變量相關聯,指出主變量的返回情況.
=0:返回值不為空, 未被截斷,值放在主變量中;
返回值= >0:返回值為空, 忽略主變量的值;
<0:主變量長度不夠就被截斷。
使用指示變量要注重:
l 在WHERE子句中不能用指示變量。用NULL屬性來測試空值。
例如下列子句:
SELECT…
FROM…
WHERE ENAME IS NULL;
是正確的,而
WHERE ENAME=:PEME:PEME1
是錯誤的。
l 指示變量在插入空值之前為—1
l 可輸出空值。
3 WHENEVER語句
WHENEVER是說明語句,不返回SQLCODE, 只是根據SQLCA中的返回碼指定相關的措施。格式為
EXEC SQL WHENEVER [SQLERRORSQLWARNINGNOTFORUND]
[STOPCONTINUEGOTO<標號>];
其中
(1)[STOPCONTINUEGOT<標號>]的缺省值為CONTINUE。
(2)SQLERROR:SQLCA.SQLCODE<0;
(3)SQLWARNIGN:SQLCA.SQLWARN[0]=“W”;
(4)NOTFOUND:SQLCA.SQLCODE=1403;
下面給出一段程序來說明WHENEVER的用法:
EXEC SQL BEGIN DEELARE SECTION;
VARCHAR UID[20];
VARCHAR PASW[20];
……
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
Main()
{
……
EXEC SQL WHENEVER SQLERROR GOTO ERR;
EXEC SQL CONNECT:UID/:PWD;
……
EXEC SQL DECLARE CSOR1 CURSOR FOR
SELECT 〈字段〉
FORM〈表〉
EXEC SQL OPEN CSOR1;
SQL
……
EXEC SQL WHENEVER NOT FOUND GOTO good;
For(;;)
EXEC SQL FETCH CSOR, INTO……
Good:
……
printf(“/n查詢結束/n”);
EXEC SQL CLOSE C1;
EXEC SQL WHENEVER SQLERROR CONTINUE.
EXEC SQL COMMIT WORK RELEASE:
Exit();
Printf(“/n%70sn”, sqlca.sqlerrm.sqlerrmc);
EXEC SQL ROLLBACK WORK RELEASE:
Exit(1);
}
(7) 動態定義語句
SQL語句分動態定義語句和靜態定義語句兩種:
(1) 靜態定義語句:SQL語句事先編入PRO*C中,在經過預編譯器編譯之后形成目標程序*。BOJ,然后執行目標程序預即可。
(2) 動態定義語句:有些語句不能事先嵌入到PRO*C程序中,要根據程序運行情況,用戶自己從輸入設備上(如終端上)實時輸入即將執行的SQL語句。
動態定義語句有:
l EXECUTE IMMEDIATE;
l PREPARE 與EXECUTE;
l PREPARE與FETCH 和 OPEN ;
l BIND與DEFINE DESCRipTOR。1. EXECUTE IMMEDIATE語句
此語句表示立即執行, 并且只向SQLCA返回執行結果,無其它信息。例如:
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR abcd[89];
VARCHAR deay[20];
EXEC SQL END DECLARE SECTION;
/** 輸出字符串到abcd **/
EXEC SQL EXECUTE IMMEDIATE :abcd;
注重:
1) EXECUTE IMMEDIATE只能運行帶一個參數的動態語句。其中,abcd是參數,不是要害字。
2) EXECUTE IMMEDIATE使用的先決條件是:SQL語句不能包含主變量;SQL語句不能是查詢語句。
3) 可用任何主變量作為EXECUTE IMMEDIATE的參數;也可用字符串作為主變量。
2. PREPARE與EXECUTE語句
此語句表示“預編譯/執行”。此語句能夠預編譯一次而執行多次。語法為:
EXEC SQL PREPARE 〈語句名〉FROM:主變量;
EXEC SQL EXECUTE〈語句名〉[USING:替換主變量];
PREPARE語句做兩件事:
(1) 預編譯SQL語句;
(2) 給出SQL語句的語句名。
注重:
l SQL語句不能是查詢語句;
l PREPARE和EXECUTE可包含主變量;
l PREPARE不能多次執行。
例如:<example.pc>
#define USERNAME “SCOTT”
#define PASSWORD “TIGER”
#include <stdio.h>
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
Char * username=USERNAME;
Char * password=PASSWORD;
VARCHAR sqlstmt[80];
Int emp_number;
VARCHAR emp_name[15];
VARCHAR job[50];
EXEC SQL END DECLARE SECTION;
Main()
{
EXEC SQL WHENEVER SQLERROR GOTO :sqlerror;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
Sqlstmt.len=sprintf(sqlstmt.arr,”INSERT INTO EMP (EMPNO,ENAME,JOB,SAL)
VALUES(:V1,:V2,:V3,:V4)”);
Puts(sqlstmt.arr);
EXEC SQL PREPARE S FROM :sqlstmt;
For(;;)
{
printf(“/nenter employee number:”);
scanf(“%d”,&emp_number);
if (emp_number==0) break;
printf(“/nenter employee name:”);
scanf(“%s”,&emp_name.arr);
emp_name.len=strlen(emp_name.arr);
printf(“/nenter employee job:”);
scanf(“%s”,job.arr);
job.len=strlen(job.arr);
printf(“/nenter employee salary:”);
scanf(“%f”,&salary);
}
EXEC SQL EXECUTE S USING :emp_number,:emp_name,:job,:salary;
} 3. FETCH語句和OPEN語句
FETCH語句和OPEN語句這組動態語句是對游標進行操作的,其執行過程如下:
PREPARE〈語句名〉FROM 〈主變量字符串〉;
DECLARE〈游標名〉FOR〈語句名〉;
OPEN 〈游標名〉[USING:替換變量1[,:替換變量變…]]
FETCH〈游標名〉INTO: 主變量1[,:主變量2…]
CLOSE〈游標名〉注重:
l SQL語句答應使用查詢語句;
l SELECT子句中的列名不能動態改變,只能預置;
l WHERE和ORDER BY 子句可以動態改變條件。一、 Pro*C的編譯和運行1. 先用ORACLE預編譯器PROC對PRO*C程序進行預處理,該編譯器將源程序中嵌入的SQL語言翻譯成C語言,產生一個C語言編譯器能直接編譯的文件。生成文件的擴展名為 .C
2. 用C語言編譯器CC 對擴展名為 .c的文件編譯,產生目標碼文件,其擴展名為 .o
3. 使用MAKE命令,連接目標碼文件,生成可運行文件
例如: 對上面的example.pc進行編譯運行
PROC iname=example.pc
CC example.c
MAKE EXE=example OBJS=”example.o”
example