本节目录
1、使用程序设计语言访问数据库
SQL提供一种强大的声明性查询语言,实现相同的查询,用SQL写查询语句比通用程序设计语言简单,然而数据库程序员必须能够使用通用程序设计语言,原因至少有以下两点:
*因为SQL没有提供通用设计语言那样的表达能力,所以SQL并不能表达所有查询要求。
*非声明性的动作都不能用SQL实现,一个应用程序通常包括很多部分,查询或更新数据只是其中之一。
可以通过一下两种方法从通用编程语言中访问SQL:
*动态SQL:通用程序设计语言可以通过函数或方法来连接数据库服务器并与之交互。利用动态SQL可以在运行时以字符串形式构建SQL查询,提交查询,然后把结果存入程序变量中,每次一个元组,动态SQL的SQL组件允许程序在运行时构建和提交SQL查询。
这一章中会介绍两种用于连接到SQL数据库并执行查询和更新的标准,一种是java语言的应用程序接口JDBC,另一种是ODBC,最初是为C语言开发的,后来扩展到C++等。
*嵌入式SQL:与动态SQL类似,嵌入式SQL提供了另外一种使程序与数据库服务器交互的手段,然而嵌入式SQL语句必须在编译时全部确定,并交给预处理器,预处理程序提交SQL语句到数据库系统进行预编译和优化,然后把它应用程序中的SQL语句替换成相应的代码和函数,最后调用程序语言的编译器进行编译。
1.1 JDBC(略)
1.2 ODBC
开放数据库互连标准定义了一个API,应用程序用它来打开一个数据库连接、发送查询和更新以及获取返回结果等。应用程序可以使用相同的ODBC API来访问任何一个支持ODBC标准的数据库。
每一个支持ODBC的数据库系统都提供一个和客户端程序相连接的库,当客户端发出一个ODBC API请求,库中的代码就可以和服务器通信来执行被请求的动作并取回结果。
下图是一个使用ODBC API的c语言代码示例,使用ODBC和服务器通信的第一步就是建立一个和服务器的连接,为了实现这一步,程序先分配一个SQL环境变量,然后是一个数据库连接句柄,OBDC定义了HENV、HDBC、和RETCODE几种类型,程序随后利用SQLConnect打开和数据库的连接,这个调用有几个参数,包括数据库的连接句柄、要连接的服务器、用户的身份和密码等,常数SQL_NTS表示前面的参数是一个以null结尾的字符串。
一旦连接建立,C语言就可以通过SQLExecDiret语句把命令发送到数据库,因为C语言的变量和查询结果的属性绑定,所以当一个元组被SQLFetch语句取回时,结果中的相应的属性的值就可以放到对应的C变量里了,SQLBindCol做这项工作,在SQLBindCol函数中第二个参数代表选择属性中哪一个位置的值,第三个参数代表SQL应该把属性转化为什么类型的C变量,再下一个参数给出存放变量的地址,对于诸如字符数组这样的变长类型,最后两个参数还要给出变量的最大长度和一个位置来存放元组取回时的实际长度,如果一个长度域返回一个负值,那么代表着这个值为null。对于定长类型的变量如整型或浮点型,最大长度的域被忽略,而当长度域返回一个负值时表示该值为空值。
SQLFetch在while循环中一直被执行,知道SQLFecth返回一个非SQL_SUCCESS的值,在每一次fecth过程中,程序把值存放在调用SQLBindCol所说明的C变量中并把它们打印出来。在会话结束的时候程序释放语句的句柄,断开与数据库的连接,同时释放连接和SQL环境句柄,好的编程风格要求检查每一个函数的结果,确保它们没有错误。
可以创建带有参数的SQL语句,例如问号是为将来提供值的占位符,上面的语句可以先被准备,也就是在数据库中先编译,然后可以通过占位符提供具体的值来反复执行。
ODBC为各种不同的任务定义了函数。在默认情况下,每一个SQL语句都被认为是一个自动提交的独立事务,调用SQLConnectOption(conn,SQL_AUTOCOMMIT,0)可以关闭连接conn的自动提交,事务必须通过显式的调用SQLTransact(conn,SQL_COMMIT)来提交或显式的调用SQLTransact(conn,SQL_ROLLBACK)来回滚。
SQL标准定义了调用级接口,它与ODBC接口类似。
1.3 嵌入式SQL
SQL标准定义了嵌入SQL到许多不同的语言中,SQL查询所嵌入的语言被称为宿主语言,宿主语言中使用的SQL结构被称为嵌入式SQL。
使用宿主语言写出的程序可以通过嵌入SQL语法访问和修改数据库中的数据,一个使用嵌入式SQL的程序在编译前必须先由一个特殊的预处理器进行处理,嵌入的SQL请求被宿主语言的声明以及允许运行时刻执行数据库访问的过程中所调用所代替,然后产生的程序由宿主语言编译器编译,这是嵌入式SQL和JDBC或ODBC的主要区别。
在JDBC中SQL语句是在运行时被解释的,当使用嵌入式SQL时,一些SQL相关的错误可以再编译过程中被发现。
为了使预处理器识别嵌入式SQL请求,使用EXEC SQL语句,格式如下:
嵌入式SQL的确切语法依赖于宿主语言,在应用程序中合适的地方插入SQL INCLUDE SQLCA语句,表示预处理器应该在此处插入特殊变量用以程序和数据库系统之间的通信。
在嵌入的SQL语句中可以使用宿主语言的变量不过前面要加:以区别SQL变量。
在执行任何SQL语句之前,程序必须首先连接到数据库,使用下面的语句实现:
这里的server标识将要建立的服务器。嵌入式SQL语句的格式和本章描述的SQL语句类似。但是这里要指出几点重要的不同之处。
为了标识关系查询,使用声明游标语句,然而这时并不计算查询的结果,而程序必须用open和fetch语句,得到结果元组。以之前的大学模式,假设我们有一个宿主变量credit_amount,声明方法和宿主语言惯例一样。假设想找出学分高于credit_amount的所有学生的名字,查询如下:
上述表达式中的变量c被称为查询的游标,我们使用这个变量来标识该查询,然后用open语句来执行查询。open语句如下:
这条居于使得数据库系统执行这条查询并把执行结果存于一个临时关系中,当open语句被执行的时候,宿主变量的值就会被应用到查询中。如果SQL查询出错,数据库系统将会在SQL通信区域的变量中存储一个错误诊断信息。然后利用一系列fecth语句把结果元组的值赋给宿主语言的变量。
接下来的应用程序就可以利用宿主语言的特性对si和sn进行操作了。我们必须使用close语句来告诉数据库系统删除用于保存查询结果的临时关系,对于上面的例子:
用于数据库修改的嵌入式SQL表达式不返回结果,因此这种语句表达起来在某种程度上相对简单,数据库修改请求格式如下:
前面带冒号的宿主语言的变量可以出现在数据库修改语句的表达式中,如果在语句执行过程中出错,SQLCA中将设置错误诊断信息。
也可以通过设置游标来更新数据库关系。然后利用在游标上的fecth操作对元组进行迭代。
2、函数和过程
前面学到了SQL的一些内建函数,这一节可以编写自己的函数和过程,把它们存储在数据库中并在SQL语句中调用,函数对于特定的数据