【网学网提醒】:网学会员,鉴于大家对oracle中pro_c的学习十分关注,会员在此为大家搜集整理了“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局部变量说明
程序体内部说明部分内部说明段
通讯区说明
函数KC的可执行语句
可执行语句SQL的可执行语句
或PL/SQL块
二.Pro*C程序的组成结构
每一个Pro*C程序都包括两部分:(1)应用程序首部;(2)应用程序体
应用程序首部定义了ORACLE数据库的有关变量,为在C语言中操纵ORACLE数据库做好了准备。应用程序体基本上由Pro*C的SQL语句调用组成。主要指查询SELECT、INSERT、UPDATE、DELETE等语句。
应用程序的组成结构如图所示:
EXECSQLBEGINDECLARESECTION(SQL变量的定义)EXECSQLENDDECLARESECTION;
EXECSQLINCLUDESQLLA;
EXECSQLCONNECT:<用户名>IDENTIFIEDBY:<口令>
SQL语句及游标的使用
1.应用程序首部
应用程序的首部就是Pro*C的开始部分。它包括以下三部分:
lC变量描述部分;
lSQL变量描述部分(DECLARE部分);
lSQL通信区。
(1).DECLARE部分(描述部分)
描述部分说明程序的SQL变量,定义部分以EXECSQLBEGINDECLARESECTION;开始和以EXECSQLENDDECLARESECTION;结束的。它可以出现在程序的主部,也可出现在局部
lSQL变量
的说明和使用
在说明段能为SQL变量指定的数据类型如表所示:
数据类型描述
CHARCHAR(n)INTSHORTLONGFLOATDOUBLEVARCHAR单字符n个字符数组整数短整数单精度浮点数双精度浮点数变长字符串
这些数据类型实际上就是C语言的数据类型,其中VARCHAR中视为C数据类型的扩充。这在以后会谈到。
SQL变量的使用应注意以下几点:
l必须在描述部分明确定义
l必须使用与其定义相同的大小写格式
l在SQL语句中使用时,必须在其之前加一个“:”(冒号),但在C语句中引用时不需加冒号。
l不能是SQL命令中的保留字。
l可以带指示变量。
例如:EXECSQLBEGINDECLARESECTIONS;
VARCHARprograme[30];
Intporgsal,pempno;
EXECSQLENDDECLARESECTION;
EXECSQLSELECTENAME,SAL
INTO:programe,:progsal
FROMEMP
WHEREEMPNO=:pempno;
(2).指示器变量的说明和引用
指示变量实际上也是一类SQL变量,它被用来管理与其相关联的宿主变量(即在SQL语句中充当输入或输出的变量)。每一个宿主变量都可定义一个指示器变量,主要用于处理空值(NULL)
指示器变量的说明基本同一般SQL变量一样,但必须定义成2字节的整型,如SHORT、INT。在SQL语句中引用时,其前也应加“:”(冒号),而且必须附在其相关联的宿主变量之后,在C语句中,可独立使用。当指示器变量为-1时,表示空值。例如:
EXECSQLBEGINDECLARESECTION;
INTdept-number;
SHORTind–num;
CHARemp–name;
EXECSQLENDDECLARESECTION;
Scanf(“90d%s”,&;dept-number,dept–name);
If(dept–number==0)
Ind–num=-1;
Else
Ind–num=0;
EXECSQLINSERTINTODEPT(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语句、便可一次性插入。例如:
EXECSQLBEGINDECLARESECTION;
Intemp_number[100];
Charemp_name[100][15];
Floatsalary[100],commission[100];
Intdept_number;
EXECSQLENDDECLARESECTION;
….
EXECSQLSELECTEMPNO,ENAME,SAL,COMM
INTO:emp_number,:emp_name,:salary,:commission
FROMEMP
WHEREDEPTNO=:dept_
number;
在使用数组时,应注意以下几点;
l不支持指针数组
l只支持一维数组,而emp-name[100][15]视为一维字符串
l数组最大维数为32767
l在一条SQL语句中引用多个数组时,这些数组维数应相同
l在VALUES,SET,INTO或WHERE子名中,不允许把简单SQL变量与数组SQL变量混用
l不能在DELARE部分初始化数组
例如:下面的引用是非法的
EXECSQLBEGINDECLARESECTION;
Intdept–num[3]={10,20,30};
EXECSQLENDDECLARESECTION;
EXECSQLSELECTEMPNO,ENAME,SAL
INTO:emp–num[i],:emp–name[i],:salarg[i]
FROMEMP
(5)伪类型VARCHAR的说明和引用
VARCHAR变量在引用之前也必须在说明段说明,说明时必须指出串的最大
长度,如:
EXECSQLBEGINDECLARESECTION;
Intbook–number;
VARCHARbook–name[50];
EXECSQLENDDECLARESECTION;
在预编绎时,book–name被翻译成C语言中的一个结构变量;
Struct{unsignedshortlen;
Unsignedchartarr[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);
EXECSQLUPDATEBOOK
SETBNAME=:book–name;
BDESC=:book–number;
}
(6)SQL通信区
SQL通信区是用下列语句描述的:
EXECSQLINCLUDESQLCA;
此部分提供了用户运行程序的成败记录和错误处理。
SQLCA的组成
SQLCA是一个结构类型的变量,它是ORACLE和应用程序的一个接口。在执行Pro*C程序时,ORACLE把每一个嵌入SQL语句执行的状态信息存入SQLCA中,根据这些信息,可判断SQL语句的执行是否成功,处理的行数,错误信息等,其组成如表所示:
Structsqlca
{charsqlcaid[8];----à标识通讯区
longsqlabc;---à通讯区的长度
longsqlcode;---à保留最近执行的SQL语句的状态码
struct{unsignedshortsqlerrml;-----à信息文本长度
}sqlerrm;
charsqlerrp[8];
longsqlerrd[6];
charsqlwarn[8];
charsqlext[8];
}
structsqlcasqlca;
其中,sqlcode在程序中最常用到,它保留了最近执行的SQL语句的状态码。程序员根据这些状态码做出相应的处理。这些状态码值如下:
0:表示该SQL语句被正确执行,没有发生错误和例外。
>0:ORACLE执行了该语句,但遇到一个例外(如没找到任何数据)。
<0:表示由于数据库、系统、网络或应用程序的错误,ORACLE未执行该SQL语句
。
当出现此类错误时,当前事务一般应回滚。
2.应用程序体
在Pro*C程序中,能把SQL语句和C语句自由地混合书写,并能在SQL语句中使用SQL变量,嵌入式SQL语句的书写文法是:
l以关键字EXECSQL开始
l以C语言的语句终结符(分号)终结
SQL语句的作用主要用于同数据库打交道。C语言程序用于控制,输入,输出和数据处理等。
(1)连接到ORACLE数据库
在对数据库存取之前,必须先把程序与ORACLE数据库连接起来。即登录到ORACLE上。所连接命令应该是应用程序的第一个可执行命令。连接命令格式如下:
EXECSQLCONNECT:<用户名>IDENTIFIEDBY:<口令>
或EXECSQLCONNECT:<用户名>/<口令>
在使用上述两种格式进行登入时,应当首先在说明段定义包含用户名和口令的
SQL变量,并在执行CONNECT之前设置它们,否则会造成登录失败。例如:
EXECSQLBEGINDECLARESECTION;
VARCHARusename[20];
VARCHARpassword[20];
EXECSQLENDDECLARE
..........
strcpy(usename.arr,“CSOTT’);
usename.len=strlen(username.arr);
strcpy(password.arr,“TIGER’);
password.len=strlen(password.arr);
EXECSQLWHENEVERSQLERRORGOTOSQLERR;
EXECSQLCONNECT:usernameINDNTIFIEDBY:password;
注意:不能把用户名和口令直接编写到CONNECT语句中,或者把用引号(’)括起来的字母串在CONNECT语句中,如下面的语句是无效的。
EXECSQLCONNECTSCOTTINENTIFIEDBYTIGER;
EXECSQLCONNECT‘SCOTT’IDENTIFIEDBY‘TIGER’;
(2).插入、更新和删除
在讲述SQL语言时已详细讲过,这里就不举例说明了。
(3).数据库查询及游标的使用
在PRO*C中,查询可分为两种类型:
l返回单行或定行数的查询;
l返回多行的查询.此种查询要求使用游标来控制每一行或每一组(主变量用数组).
1)返回单行或定行数的查询
在PRO*C中的查询SQLSELECT语句由以下几个子句组成:
SELECT
INTO
FROM
WHERE
CONNECTBY
UNION
INTERSECT
MINUS
GROUPBY
HAVING
ORDERBY
其中WHERE子句中的查询条件可以是一个属性或多个属性的集合,在执行是赋值的主变量也可放在WHERE子句中.WHERE子句中所用的主变量称为输入主变量。如:
SELECTEMPNO,JOB,SAL
INTO:PNAME,:PJOB,:PSAL
FROMEMP
WHEREEMPNO=: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)DECLARECURSOR;(2)OPENCURSOR;(3)FETCH;(4)CLOSECURSOR。
A.定义游标
一个游标必须首先定义,才能使用它。语法为:
EXECSQLDECLARE〈游标名〉CORSORFOR
SELECT〈列〉
FROM〈表〉
例如:
EXECSQLDECLARECSOR,CURSORFOR
转载网上的一篇文章支持一下。
PROC是ORACLE数据库提供的编程接口之一,其应用十分的广泛,本文通过一个具体的例子,介绍PROC编程的一些经验及应注意的地方。
例子程序:
#include
#include
#include
#include
#include
EXECSQLINCLUDEsqlca;
/*RELEASE_CURSOR=YES使PROC在执行完后释放与嵌入SQL有关资源*/
EXECORACLEOPTION(RELEASE_CURSOR=YES);
EXECSQLBEGINDECLARESECTION;
varcharvc_user[20];
longal_empno=0;
charac_ename[11]="";
charac_hiredate[20]="";
doubleaf_sal=0;
EXECSQLVARac_enameISSTRING(11);
EXECSQLVARac_hiredateISSTRING(20);
EXECSQLENDDECLARESECTION;
/*错误处理函数*/
voidsql_error(char*msg)
{
printf("%s,%ld,%s",msg,sqlca.sqlcode,(char*)sqlca.sqlerrm.sqlerrmc);
EXECSQLROLLBACKRELEASE;
exit(-1);
}
main()
{
EXECSQLWHENEVERSQLERRORDOsql_error("ORACLEERROR:");
/*连接数据库*/
strcpy(vc_user.arr,"scott/tiger@DEMO");
vc_user.len=16;
execsqlconnect:vc_user;
EXECSQLDECLAREcur_empCURSORFOR
SELECTEMPNO,ENAME,to_char(HIREDATE,'yyyy/mm/ddhh24:mi:ss'),SALFROMEMP;
EXECSQLOPENcur_emp;
while(1)
{
al_empno=0;
strcpy(ac_ename,"");
strcpy(ac_hiredate,"");
af_sal=0;
EXECSQLFETCHcur_empINTO: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",al_empno,ac_ename,ac_hiredate,af_sal);
}
EXECSQLCLOSEcur_emp;
EXECSQLROLLBACKWORKRELEASE;
}
1、宿主变量的声明
在PROC中,在SQL语句中用到的变量称为宿主变量。他们应在EXECSQLBEGINDECLARESECTION;与EXECSQLEDNDECLARESECTION;
之间声明,如上面所示.在声明宿主变量时应注意以下几点:
(1)在数据库表中定义为VARCHAR2,VARCHAR,CHAR的字段,在PROC中可声明为CHAR,但长度应为它们在表中定义的长度加1,因为PROC中
CHAR型变量用做结尾。
如:ENAME在表中的定义为enamevarchar2(10),在PROC中可定义为:
EXECSQLBEGINDECLARESECTION;
charename[11];
EXECSQLENDDECLARESECTION;
常见错误说明:
如果插入的字符串长度大于10,如:EXECSQLINSERTINTOEMP(ENAME)VALUES('12345678901');会出现以下错误:
error:ORA-01480:STR赋值变量缺少空后缀。
如果定义为:
EXECSQLBEGINDECLARESECTION;
charename[15];
EXECSQLENDDECLARESECTION;
当插入的字符串长度大于10,小于15时,如:EXECSQLINSERTINTOEMP(ENAME)VALUES('12345678901');会出现以下错误:
error:ORA-01401:插入的值对于列过大。
当插入的字符串长度大于15,如:EXECSQLINSERTINTOEMP(ENAME)VALUES('12345678901234');会出现以下错误:
error:ORA-01401:STR赋值变量缺少空后缀。
(2)从SQL语句中取字段的值到宿主变量中时,PROC不会自动给宿主变量去掉右空格。而是以在DECLARESECTION中定义的长度为准(与表中定义的无关)不足补右空格.如果不注意这一点,在PROC中进行字符串操作时(如比较相等)会出错。如:
EXECSQLBEGINDECLARESECTION;
charename[10];
EXECSQLENDDECLARESECTION;
如果ENAME在表中的值为'abc',则取出的值为'abc';
可用语句EXECSQLVAR重定义CHAR型变量。这样宿主变量会自动去掉右空格。如下:
EXECSQLBEGINDECLARESECTION;
charename[11];
EXECSQLVARac_enameISSTRING(11);
EXECSQLENDDECLARESECTION;
如果ENAME在表中的值为'abc',则取出的值为'abc';
(3)对浮点型的变量,为保证精度,最好是声明成DOUBLE型的.因为DOUBLE型的精度比FLOAT型高很多.
(4)整型可声明为LONG型(对较长的整型,而且所用的平台支持的话,如在SUN平台上,可声明为LONGLONG型).
(5)DATE型的处理:DATE型一般声明为CHAR(20)。
往表中插入DATE型数据时,一般用TO_DATE()函数进行类型转换,取出值时一般用TO_CHAR()函数进行类型转换.
EXECSQLselectto_char(hiredate,'yyyy/mm/ddhh24:mi:ss')into:ac_hire_datefromEMPwhereempno=1234;
EXECSQLinsertintoEMP(EMPNO,HIREDATE)values(123,to_date(:ac_hiredate,'yyyy/mm/ddhh24:mi:ss');
2、宿主变量的作用范围
如果宿主变量在所有的函数之外声明,则他们是全局变量。在使用之前要注意把变量的值初始化,宿主变量也可以在某个函数的内部定义。这时他们是局部变量。一般都习惯把宿主变量声明为全局变量。
3、数据库的连接与断开
数据库的连接有以下两种方法:
(1)
strcpy(vc_user.arr,"scott/tiger");
vc_user.len=11;
execsqlconnect:vc_user;
(2)
strcpy(user,"scott");
strcpy(pass,"tiger");
execsqlconnect:useridentifiedby:pass;
注意:在有些平台上两种都可以,在有些平台上只能用第一种方法.
在PROC程序中,要记住用EXECSQLROLLBACKWORKRELEASE;断开与数据库的连接,并释放相关的数据库资源。
4、PROC中的NULL值的处理
如果某一字段取出的值是NULL,会报:sqlcode=-1405,sqlerr=ORA-01405:读取的列值为NULL
并
且相应的宿主变量的值不会被改变,为执行该SQL语句之前的值.常用的处理NULL值的方法有:
(1)采用指示器变量,此时不会有-1405错误,当必须是所以为NULL的字段都有相应的指示器变量,如果某一字段没有指示器变量,但取出的值
为NULL值,则仍然会有-1405错误.当取出的值是NULL时,相应的指示器变量变量为-1,可根据指示器变量的值做响应的处理。
(2)如果字段较多,可取字段到一个结构体中及与该结构体对应的指示器结构体中.如上面的例子中可定义结构体:
structstr_emp{
longal_empno;
charac_ename;
charac_hiredate;
doubleaf_sal;
};
structstr_emp_ind{
longal_empno;
charac_ename;
charac_hiredate;
doubleaf_sal;
};
structstr_empstr_emp;
strcutstr_emp_indstr_emp_ind;
在取之前可用memset(&;str_emp,0,sizeof(str_emp)).清空该结构体,这样如果是字符型的NULL,会为"",整型的NULL会为0,
浮点型的会为0.00。此时不会有-1405错误。
(3)也可采用NVL()函数:举例如下:
EXECSQLDECLAREauthorsCURSORFOR
SELECTEMPNO,NVL(ENAME,chr(0)),nvl(to_char(HIREDATE,'yyyy/mm/ddhh24:mi:ss'),chr(0)),NVL(SAL,0)FROMEMP;
这样也不会有-1405错误不,当取出的值是NULL时,自动用NVL()中指定的值代替.
CHR(0)也可直接用''代替,如下:
SELECTEMPNO,NVL(ENAME,''),nvl(to_char(HIREDATE,'yyyy/mm/ddhh24:mi:ss'),''),NVL(SAL,0)FROMEMP;5、PROC中的错误的处理
所有的SQL语句都有可能出错.所以都要加以判断,但每个SQL语句后都加错误判断,太麻烦,可用一个函数如sql_error()来进行错误处理,
方法:
(1)定义ql_error()函数。
(2)在开头加上EXECSQLWHENEVERSQLERRORDOsql_error();这样当发生sqlca.sqlcode<0的错误时,程序自动转到sql_error()中执行.注意:对sqlca.sqlcode>0的错误如sqlca.sqlcode=1403是不会转到sql_error()中执行的.
另外:在UNIX下,可以用OERR来查找错误的描述。如:oraORA-1405查找错误号为-1405的描述.
6、PROC中调用存储过程的方法
要把存储过程放在EXECSQLEXECUTE和END-EXEC;之间,如下所示:
其中:al_empno,ac_ename为输入参数,l_return,l_errno,c_errtext为输出参数。
al_empno=8888;
strcpy(ac_ename,"ABCD");
EXECSQLEXECUTE
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",l_errno,c_errtext);
}
7、PROC的命令行选项:PROC编译器有很多的命令行选项,在命令行下直接不带参数运行PROC,会列出所有的命令行选项来,并有说明。
(1)储存过程:编译储存过程是要带上用户名及密码
procUSERID=scott/tigersqlcheck=SEMANTICSireclen=512iname=test.cpp
(2)PARSE=NONE对非SQL代码不进行语法分析,默认对非SQL代码也进行语法分析.
在REDHAD6.3
上的ORACLE8.1.5中用PROC时,会提示:/USR/INCLUDE/STDIO.H及其他的.H文件中有错.可把PARSE=NONE加上,就好了.
8、注意加上:EXECORACLEOPTION(RELEASE_CURSOR=YES);
RELEASE_CURSOR=YES使PROC在执行完后释放与嵌入SQL有关资源,保证在该PROC程序执行完后,ORACLE不会锁住数据库资源,如锁表等。
如果在PROC中用到ORACA,还要在程序头加上:
EXECORACLEOPTION(ORACA=YES);
9、PROC中的类型转换
一、在C语言中:
(1)字符型到整型可用ATOI()ATOL(),SSCANF()
(2)整型,浮点型到字符型,可用SPRINTF()
(3)字符型到浮点型用ATOF()不行,最好用SSCANF(),举例如下:
EXECSQLBEGINDECLARESECTION;
doubled_demo;
floatf_demo;
charac_text[20]="222";
EXECSQLENDDECLARESECTION;
(1)sscanf(ac_text,"%f",&;d_demo);
printf("ac_text=%s,d_demo=%f",ac_text,d_demo);
(2)sscanf(ac_text,"%lf",&;d_demo);
printf("ac_text=%s,d_demo=%f",ac_text,d_demo);
(3)sscanf(ac_text,"%f",&;d_demo);
printf("ac_text=%s,d_demo=%lf",ac_text,d_demo);
(4)sscanf(ac_text,"%lf",&;d_demo);
printf("ac_text=%s,d_demo=%lf",ac_text,d_demo);
printf("*******************");
(5)sscanf(ac_text,"%f",&;f_demo);
printf("ac_text=%s,f_demo=%f",ac_text,f_demo);
(6)sscanf(ac_text,"%lf",&;f_demo);
printf("ac_text=%s,f_demo=%f",ac_text,f_demo);
(7)sscanf(ac_text,"%f",&;f_demo);
printf("ac_text=%s,f_demo=%lf",ac_text,f_demo);
(8)sscanf(ac_text,"%lf",&;f_demo);
printf("ac_text=%s,f_demo=%lf",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",ac_text,d_demo);
d_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf",ac_text,d_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%f",ac_text,f_demo);
f_demo=atof(ac_text);
printf("ac_text=%s,atof(ac_text)=%lf",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语句,并用EXECUTEIMMEDIATE执行,如:
EXECSQLEXECUTEIMMEDIATE"CREATETABLEdyn1(col1VARCHAR2(4))";
(2)动态SQL2:不能是查询(SELECT)语句,并且输入的宿主变量数目是知道的,
用法:拼一串动态SQL语句,用PREPARE,EXECUTE语句执行.
strcpy(c_sql,"DELETEFROMEMPWHEREEMPNO=:?");
EXECSQLPREPAREsql_stmtFROM:c_sql;
EXECSQLEXECUTEsql_stmtUSING:emp_number;
(3)动态SQL3:用于创建动态查询,并且要查询的字段及输入的宿主变量数目是知道的
用法:拼一串动态SQL语句,用PREPARE分析该语句,并要定义一个CURSOR进行取值
如:如要查询的数据按一年12月放到12张表中。表名为user_fee_1mon,user_fee_2mon,....可采用动态SQL3来进行查询
strcpy(c_sql,"selectc_user_id,c_user_name,to_char(t_date,'yyyy/mm/ddhh:mi:ss'),n_fee");
strcat(c_sql,"fromUSER_FEE_");
strcat(c_sql,ac_mon);
strcat(c_sql,"wherec_user_id=:v1");
EXECSQLPREPAREsFROM:c_sql;
EXECSQLDECLAREcur_user_feeCURSORFORs;
EXECSQLOPENcur_user_feeUSING:ac_user_id;
while(1)
{
EXECSQLFETCHcur_user_feeinto:c_user_id,:c_user_name,:c_date,:n_fee);
if(sqlca.sqlcode<0)
{
/*FETCHCURSOR失败*/
printf("fetchcursorcur_user_feefail,sqlcode=%ld,sqlserr=%s",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc);
}
if(sqlca.sqlcode==SQLNOTFOUND)
{
break;
}
}
EXECSQLCLOSEcur_user_fee;
(4)动态SQL4:要处理的字段及输入的宿主变量数目和主变量的类型事先是不知道的,如:
INSERTINTOEMP()VALUES()
是最复杂的动态SQL,很少用,在此不做介绍。
11、SQLCA:SQL是ORACLE的一个结构体,它的域用于最近的一条SQL语句执行后的一些信息,如错误号,错误描述,警告,状态等。常用的
域介绍如下:
SQLCA.sqlcode:错误号,=0正确,=1403没取到数据
SQLCA.sqlserrm.sqlerrmc:错误描述
SQLCA.sqlerrd[3]:最近的一条SQL语句所处理的行数,如果该语句处理失败,则它的值是不定的,如果错误在一个CURSOR操作中发生,则
它的值指已成功处理的行数.在DELETE,UPDATE中,它不包含因外键约束而删除,更新的那些行,
DELETEFROMEMPWHEREDEPT='SALE';
在表EMP中删除20行,但如果表EMP与表ADDRESS有外键约束,导致表ADDRESS也被删除20行,则SQLCA.sqlerrd[3]=20,而不是40。
SELECTENAME,JOB,SAL
FROMEMP
WHEREDEPTNO=:DEPTNO;
当赋给一个与查询相关联的游标CURSOR之后,当SELECT查询EMP时可从数据库中返回多行,这些行就是CURSOR的一个活动区域。
注意:
1)定义游标必须在对游标操作之前完成;
2)PRO*C不能引用没有定义的游标;
3)游标定义后,其作用范围是整个程序。所以对一个程序来讲,同时定义两个相同的游标是错误的。
B.打开游标
打开游标
的OPEN语句主要用来输入主变量的内容,这些主要是WHERE中使用的主变量。打开游标的语句是:EXECSQLOPEN〈游标名〉
当打开游标后,可以从相关的查询中取出多于一行的结果。所有满足查询标准的行组成一集合,叫做"游标活动集"。通过取操作,活动集中的每一行或每一组是一个一个返回的,查询完成后,游标就可关闭了。如图所示:
定义游标:DECLARE
开始查询:SELECT
打开游标:OPEN
从活动集取数据:FETCH
查询完成
关闭游标:CLOSE
注意:1)游标处于活动集的第一行前面;
2)若改变了输入主变量就必须重新打开游标。
C.取数据
从活动集中取出一行或一组把结果送到输出主变量中的过程叫取数据。输出主变量的定义在取数据语句中。取数据的语句如下:
EXECSQLFETCH〈游标名〉INTO:主变量1,主变量2,……
FETCH的工作过程如图所示:
如图所示的查询结果指满足查询条件的查询结果。使用FETCH应注意以下几点:
l游标必须先定义再打开。
l只有在游标打开之后才能取数据,即执行FETCH语句。
lFETCH语句每执行一次,从当前行或当前组取数据一次,下一行或下一组向上移一次。游标每次所指的行或组都为当前行或当前组,而FETCH每次都是取游标所指定的行或组的数据。
l当游标活动集空之后,ORCLE返回一个SQLCA。SQLCA(=1403)。
l若希望此游标再操作,必须先关闭再打开它。
l在C程序中可以开辟一个内存空间,来存放操作结果,这样就能利用开辟的空间来灵活操纵查询的结果。
D.关闭游标
取完活动集中所有行后,必须关闭游标,以释放与该游标有关的资源。
关闭游标的格式为:
EXECSQLCLOSE游标名;
例如:
EXECSQLCLOSEC1;
ORACLEV5.0版支持SQL格式“CURRENTOFCURSOR”。这条语句将指向一个游标中最新取出的行,以用于修改和删除操作。该语句必须有取操作之后使用,它等同存储一个ROWID,并使用它。
(4).举例
EXECSQLDECLARESALESPEOPLECURSORFOR
SELECTSSNO,NAME,SALARY
FROMEMPLOYEE
WHEREDNAME=‘Sales’;
EXECSQLOPENSALESPEOPLE;
EXECSQLFETCHSALESPEOPLE
INTO:SS,:NAME,:SAL;
EXECSQLCLOSESALESPEOPLE;
(5)SQL嵌套的方法及应用
嵌入SQL与交互式SQL在形式上有如下差别:
1)在SQL语句前增加前缀“EXECSQL”,这一小小的差别其目的是在于预编译时容易识别出来,以便把每一条SQL作为一条高级语言来处理。
2)每一SQL语句分为说明性语句和可执行语句两大类。可执行语句又分为数据定义、数据控制、数据操纵、数据检索四大类。
可执行性SQL语句写在高级语言的可执行处;说明性SQL语句写在高级语言的说明性的地方。
例如:
在PRO*C程序中建立一个名为BOOK的表结构,过程如下:
#include〈stdio.h〉
EXECSQLBEGINDECLARESECTION;
VARCHARuid[20],pwd[20];
EXECSQLENDDECLARESECTION;
EXECSQLINCLUDESQLCA;
Main()
{
/*logindatabase*/
strcpy(uid.arr,’wu’);
uid.len=strlen(uid,arr);
strcpy(pwd.arr,’wu’);
pwd.len=strlen(pwd.arr);
EXECSQLCONNECT:uidIDENTIFEEDBY:pwd;
EXECSQLCREATETABLEbook
(acqnumnumber,copiesnumber,pricenumber);
EXECSQLCOMMITWORKRELEASE;
EXIT;
PRO*C可非常简便灵活地访问ORCLE数据库中的数据,同时又具有C语言高速的特点,因而可完成一些ORACLE产品不能完成的任务,例如以下一个固定的特殊格式输出结果。
SQL嵌套源程序示例
#unclude
typedefcharasciz[20];
EXECSQLBEGINDECLARESECTION;
EXECSQLTYPEascizISSTRING(20)REFERENCE;
ascizusername;
ascizpassword;
ascizemp_name(5);
intemp_number(5a);
floatsalary[5];
EXECSQLENDDECLARESECTION;
EXECSQLINCLUDEsqlca;
Voidprint_rows();
Voidsqlerror();
Main()
{
intnum_ret;
strcpy(username,”SCOTT’);
strcpy(password,“TYGER”);
EXECSQLWHENEVERSQLERRORDOsqlerror();
EXECSQLCONNECT:usernameIDENTIFIEDBY:password;
Print(“ConnectedtoORACLEasuser:%s”,username);
EXECSQLDECLAREc1CURSORFOR
SELECTEMPNO,ENAME,SALFROMEMP;
EXECSQLOPENc1;
Num_ret=0;
For(;;)
{
EXECSQLWHENEVERNOTFOUNDDObreak;
EXECSQLFETCHc1INTO: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);
EXECSQLCLOSEc1;
Printf(“Haveagoodday.”);
EXECSQLCOMMITWORKRELEASE;
}
voidprint_rows(n);
intn;
{
inti;
printf(“NumberEmployeeSalary”);
printf(“------------------------------”);
for(i=0;i printf(“%-9d%-8s%9.2f”,emp-number[i],emp---name[i],salary[i];
}
voidsqlerror()
{
EXECSQLWHENEVERSQLERRORCONTINUE;
Printf(“oracleerrordetected:”);
Printf(‘%.70s”,sqlca.sqlerrm.sqlerrmc);
EXECSQLROLLBACKWORKRELEASE;
Exit(1);
}
(6)错误检测和恢复
在使用SQL语句和PRO*C对数据库进行操作时,常常有字段空值,无条件删除,无行返回,数据溢出和截断等现象发生,这种现象可以用SQLCA和指示器变量来检测。
1SQLCA的结构
在PRO*C程序中SQLCA结构如下:
STRUCTSQLCA{
Charsqlcaid[8];
Longsqlabc;
Longsqlcode;
STRUCT{
Unsignedsqlerrm1;
Charsqlerrmc[10];
}sqlerrm;
Charsqlerrp[8];
Longsqlerrd[6];
Charsqlwarn[8];
Charsqlext[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…
WHEREENAMEISNULL;
是正确的,而
WHEREENAME=:PEME:PEME1
是错误的。
l指示变量在插入空值之前为—1
l可输出空值。
3WHENEVER语句
WHENEVER是说明语句,不返回SQLCODE,只是根据SQLCA中的返回码指定相关的措施。格式为
EXECSQLWHENEVER[SQLERROR|SQLWARNING|NOTFORUND]
[STOP|CONTINUE|GOTO<标号>];
其中
(1)[STOP|CONTINUE|GOT<标号>]的缺省值为CONTINUE。
(2)SQLERROR:SQLCA.SQLCODE<0;
(3)SQLWARNIGN:SQLCA.SQLWARN[0]=“W”;
(4)NOTFOUND:SQLCA.SQLCODE=1403;
下面给出一段程序来说明WHENEVER的用法:
EXECSQLBEGINDEELARESECTION;
VARCHARUID[20];
VARCHARPASW[20];
……
EXECSQLENDDECLARESECTION;
EXECSQLINCLUDESQLCA;
Main()
{
……
EXECSQLWHENEVERSQLERRORGOTOERR;
EXECSQLCONNECT:UID/:PWD;
……
EXECSQLDECLARECSOR1CURSORFOR
SELECT〈字段〉
FORM〈表〉
EXECSQLOPENCSOR1;
SQL
……
EXECSQLWHENEVERNOTFOUNDGOTOgood;
For(;;)
EXECSQLFETCHCSOR,INTO……
Good:
……
printf(“查询结束”);
EXECSQLCLOSEC1;
EXECSQLWHENEVERSQLERRORCONTINUE.
EXECSQLCOMMITWORKRELEASE:
Exit();
Printf(“%70s|n”,sqlca.sqlerrm.sqlerrmc);
EXECSQLROLLBACKWORKRELEASE:
Exit(1);
}
(7)动态定义语句
SQL语句分动态定义语句和静态定义语句两种:
(1)静态定义语句:SQL语句事先编入PRO*C中,在经过预编译器编译之后形成目标程序*。BOJ,然后执行目标程序预即可。
(2)动态定义语句:有些语句不能事先嵌入到PRO*C程序中,要根据程序运行情况,用户自己从输入设备上(如终端上)实时输入即将执行的SQL语句。
动态定义语句有:
lEXECUTEIMMEDIATE;
lPREPARE与EXECUTE;
lPREPARE与FETCH和OPEN;
lBIND与DEFINEDESCRIPTOR。
1.EXECUTEIMMEDIATE语句
此语句表示立即执行,并且只向SQLCA返回执行结果,无其它信息。例如:
EXECSQLBEGINDECLARESECTION;
VARCHARabcd[89];
VARCHARdeay[20];
EXECSQLENDDECLARESECTION;
/**输出字符串到abcd**/
EXECSQLEXECUTEIMMEDIATE:abcd;
注意:
1)EXECUTEIMMEDIATE只能运行带一个参数的动态语句。其中,abcd是参数,不是关键字。
2)EXECUTEIMMEDIATE使用的先决条件是:SQL语句不能包含主变量;SQL语句不能是查询语句。
3)可用任何主变量作为EXECUTEIMMEDIATE的参数;也可用字符串作为主变量。
2.PREPARE与EXECUTE语句
此语句表示“预编译/执行”。此语句能够预编译一次而执行多次。语法为:
EXECSQLPREPARE〈语句名〉FROM:主变量;
EXECSQLEXECUTE〈语句名〉[USING:替换主变量];
PREPARE语句做两件事:
(1)预编译SQL语句;
(2)给出SQL语句的语句名。
注意:
lSQL语句不能是查询语句;
lPREPARE和EXECUTE可包含主变量;
lPREPARE不能多次执行。
例如:
#defineUSERNAME“SCOTT”
#definePASSWORD“TIGER”
#include
EXECSQLINCLUDEsqlca;
EXECSQLBEGINDECLARESECTION;
Char*username=USERNAME;
Char*password=PASSWORD;
VARCHARsqlstmt[80];
Intemp_number;
VARCHARemp_name[15];
VARCHARjob[50];
EXECSQLENDDECLARESECTION;
Main()
{
EXECSQLWHENEVERSQLERRORGOTO:sqlerror;
EXECSQLCONNECT:usernameIDENTIFIEDBY:password;
Sqlstmt.len=sprintf(sqlstmt.arr,”INSERTINTOEMP(EMPNO,ENAME,JOB,SAL)
VALUES(:V1,:V2,:V3,:V4)”);
Puts(sqlstmt.arr);
EXECSQLPREPARESFROM:sqlstmt;
For(;;)
{
printf(“enteremployeenumber:”);
scanf(“%d”,&;emp_number);
if(emp_number==0)break;
printf(“enteremployeename:”);
scanf(“%s”,&;emp_name.arr);
emp_name.len=strlen(emp_name.arr);
printf(“enteremployeejob:”);
scanf(“%s”,job.arr);
job.len=strlen(job.arr);
printf(“enteremployeesalary:”);
scanf(“%f”,&;salary);
}
EXECSQLEXECUTESUSING:emp_number,:emp_name,:job,:salary;
}
3.FETCH语句和OPEN语句
FETCH语句和OPEN语句这组动态语句是对游标进行操作的,其执行过程如下:
PREPARE〈语句名〉FROM〈主变量字符串〉;
DECLARE〈游标名〉FOR〈语句名〉;
OPEN〈游标名〉[USING:替换变量1[,:替换变量变…]]
FETCH〈游标名〉INTO:主变量1[,:主变量2…]
CLOSE〈游标名〉
注意:
lSQL语句允许使用查询语句;
lSELECT子句中的列名不能动态改变,只能预置;
lWHERE和ORDERBY子句可以动态改变条件。
一、Pro*C的编译和运行
1.先用ORACLE预编译器PROC对PRO*C程序进行预处理,该编译器将源程序中嵌入的SQL语言翻译成C语言,产生一个C语言编译器能直接编译的文件。生成文件的扩展名为.C
2.用C语言编译器CC对扩展名为.c的文件编译,产生目标码文件,其扩展名为.o
3.使用MAKE命令,连接目标码文件,生成可运行文件
例如:对上面的example.pc进行编译运行
PROCiname=example.pc
CCexample.c
MAKEEXE=exampleOBJS=”example.o”
example