笔记目录
- 一、基本技巧
- 1. 嵌入式SQL语言概述
- 2. 变量声明
- 3. 数据库连接
- 4. 事务
- 5. 数据集与游标
- 5.1 标准游标
- 5.2 可滚动游标
- 6. 数据库的增删改
- 7. 状态捕获及错误处理机制
- 二、动态SQL
- 1. 动态SQL的概念和作用
- 2. 动态SQL的执行方式
- 3. 数据字典与SQLDA
- 4. ODBC和JDBC简介
一、基本技巧
1. 嵌入式SQL语言概述
- 交互式SQL语言的局限
- 使用者角度:普通用户不容易上手
- SQL本身角度:特别复杂的检索结果难以用一条交互式SQL语句完成,此时需要结合高级语言中经常出现的顺序、分支和循环结构来帮助处理
- 嵌入式SQL语言
- 概念:将SQL语言嵌入到某一种高级语言(C/C++,java等)中使用,被嵌入的语言称为宿主语言
- 优点
- 既继承了高级语言的过程控制性,又结合SQL语言的复杂结果集操作的非过程性
- 为数据库操作者提供安全可靠的操作方式:通过应用程序进行操作
- 示例
- 交互式SQL语言
select Sname, Sage from Student where Sname=‘张三’
- 嵌入式SQL语言(C语言为宿主语言)
exec sql select Sname, Sage into :vSname, :vSage from Student where Sname=‘张三’ ;
- 对比:
- exec sql引导SQL语句:提供给C编译器,以便对SQL语句预编译成C编译器可识别的语句
- into语句:指出接收SQL语句检索结果的程序变量
- 由冒号引导的程序变量:在SQL语句中加冒号,在C语言中不用加
2. 变量声明
- 变量的声明
- 嵌入式SQL语句中可以出现宿主语言语句所使用的变量,但是这些变量需要特殊声明,并且在SQL语句中使用需要加:引导。
- 声明示例:即C语言的声明夹上特定的声明语句
exec sql begin declare section;
char vSname[10], specName[10]=“张三”;
int vSage;
exec sql end declare section;
- 注意
- 宿主程序的字符串变量长度应比字符型字段的长度多1个。因宿主程序的字符串尾部多一个终止符为‘\0‘,而程序中用双引号来描述。
- 宿主程序变量类型与数据库字段类型之间有些是有差异的,有些DBMS可支持自动转换,有些不能。
3. 数据库连接
- 连接
- 嵌入式SQL程序执行之前,首先要与数据库进行连接
- SQL标准的连接语法
execsql connecttotarget_server asconnect_name useruser_name
- Oracle连接语法
execsql connect:user_name identified by :user_pwd
- DB2 连接语法
execsql connecttomydb user:user_name using:user_pwd
- 断开
- 嵌入式SQL程序执行之后,需要与数据库断开连接
- SQL标准断开语法
exec sql disconnect connect-name
- 或
exec sql disconnect current
- Oracle断开语法
exec sql commit release
- 或
exec sql rollback release
- DB2断开语法
exec sql connect reset
- 或
exec sql disconnect current
4. 事务
- SQL执行的提交与撤消
- SQL语句在执行过程中,必须有提交和撤消语句才能确认其操作结果
- SQL执行的提交
execsql commitwork
- SQL执行的撤消
execsql rollbackwork
- 事务
- 概念
- 从应用程序员角度:事务是一个存取或改变数据库内容的程序的一次执行,或者说一条或多条SQL语句的一次执行
- 从DBMS角度:事务是数据库管理系统提供的控制数据操作的一种手段,通过这一手段,应用程序员将一系列的数据库操作组合在一起作为一个整体进行操作和控制,以便数据库管理系统能够提供一致性状态转换的保证
- 事务一般是由应用程序员提出,因此有开始和结束,结束前需要提交或撤消
- 语法
BeginTransaction
execsql …
…
execsql …
execsql commit work |execsql rollback work
EndTransaction
- 在嵌入式SQL程序中,只要该程序当前没有正在处理的事务,任何一条数据库操纵语句(如execsqlselect等)都会引发一个新事务的开始
- 事务的结束需要应用程序员通过commit或rollback确认
- BeginTransaction和End Transaction两行语句可以不需要
- 特性(ACID)
- 原子性(Atomicity):DBMS能够保证事务的一组更新操作是原子不可分的
- 一致性(Consistency):DBMS保证事务的操作状态是正确的,符合一致性的操作规则,它是进一步由隔离性来保证的
- 隔离性(Isolation):DBMS保证并发执行的多个事务之间互相不受影响
- 持久性(Durability):DBMS保证已提交事务的影响是持久的,被撤销事务的影响是可恢复的
5. 数据集与游标
5.1 标准游标
- 游标(Cursor)是为了读取多行数据,当SQL语句的返回集有多个元组时使用
- 游标是指向某检索记录集的指针,通过这个指针的移动,每次读一行,处理一行,再读一行… , 直至处理完毕
- 标准的游标始终是自开始向结束方向移动的,每fetch一次,向结束方向移动一次;一条记录只能被访问一次;再次访问该记录只能关闭游标后重新打开
- 游标的使用
- 游标的使用需要先定义、再打开(执行)、接着一条接一条处理,最后再关闭
- 游标可以定义一次,多次打开(多次执行),多次关闭
- 语法
- 定义游标
EXEC SQL DECLARE cursor_name CURSOR FOR
Subquery
[ORDER BY result_column [ASC | DESC][, result_column …]
[FOR [ READ ONLY | UPDATE [OF columnname [, columnname…]]]]
- 示例:
exec sql declare cur_student cursor for
select Sno, Sname, Sclass from Student where Sclass= :vClass
order by Sno
for read only
- 打开游标
EXEC SQL OPEN cursor_name
- 关闭游标
EXEC SQL CLOSE cursor_name
- 用游标读取数据
EXEC SQL FETCH cursor_name
INTO host_variable , [host_variable, …]
- 示例:
exec sql fetch cur_student into :vSno, :vSname, :vSage
5.2 可滚动游标
- 可滚动游标是可使游标指针在记录集之间灵活移动、使每条记录可以反复被访问的一种游标
- 语法
- 定义
EXEC SQL DECLARE cursor_name [INSENSITIVE] [SCROLL] CURSOR
[WITH HOLD] FOR Subquery
[ORDER BY result_column [ASC | DESC][, result_column …]
[FOR READ ONLY | FOR UPDATE OF columnname [, columnname ]…];
- 使用
EXEC SQL FETCH
[NEXT | PRIOR | FIRST | LAST | [ABSOLUTE | RELATIVE] value_spec ]
FROM cursor_name INTO host-variable [, host-variable …]
- NEXT:向结束方向移动一条
- PRIOR:向开始方向移动一条
- FIRST:移动到第一条
- LAST:移动到最后一条
- ABSOLUTvalue_spec:定向检索指定位置的行
- RELATIVEvalue_spec:相对当前记录向前或向后移动,若为负数则向开始方向移动
- 判断游标检索到达终点
- 可通过判断是否到EOF位置(最后一条记录的后面),或BOF位置(起始记录的前面)
- 如果不需区分,可通过whenevernotfound语句设置来检测
6. 数据库的增删改
- 插入
EXEC SQL INSERT INTO tablename [ (columnname [, columnname, …] )]
[VALUES (expr [ , expr , …] ) | subqurey]
- 删除
- 查找删除
EXEC SQL DELETE FROM tablename [corr_name]
WHERE search_condition
- 定位删除(通过游标定位删除)
EXEC SQL DELETE FROM tablename [corr_name]
WHERE CURRENT OF cursor_name
- 更新
- 查找更新
EXEC SQL UPDATE tablename [corr_name]
SET columnname = expr [, columnname = expr …]
[WHERE search_condition]
- 定位更新
EXEC SQL UPDATE tablename [corr_name]
SET columnname = expr [, columnname = expr …]
WHERE CURRENT OF cursor_name
7. 状态捕获及错误处理机制
- 对嵌入式SQL语句执行过程的异常状态进行捕获和处理
- 状态捕获及处理
- 设置SQL通信区:一般在嵌入式SQL程序的开始处便设置
exec sql include sqlca
- SQL通信区: SQLCA
- SQLCA是一个已被声明过的具C语言的结构形式的内存信息区,其中的成员变量用来记录SQL语句执行的状态,便于宿主程序读取与处理
- SQLCA是DBMS(执行SQL语句)与宿主程序之间交流的桥梁之一
- 设置状态捕获语句
exec sql whenever condition action
- 作用域:其后的所有Exec SQL语句,一直到程序中出现另一条相同条件的Whenever语句为止,后面的将覆盖前面的
- 作用域内发生符和condition的状态时,就采取action
- condition包括:
- SQLERROR:检测是否有SQL语句出错
- NOT FOUND:执行某一SQL语句后,没有相应的结果记录出现
- SQLWARNING:不是错误,但应引起注意的条件
- action包括:
- CONTINUE: 忽略条件或错误,继续执行
- GOTO 标号: 转移到标号所指示的语句,去进行相应的处理
- STOP: 终止程序运行、撤消当前的工作、断开数据库的连接
- DO 函数或CALL 函数: 调用宿主程序的函数进行处理,函数返回后从引发该condition的Exec SQL语句之后的语句继续进行
- 设置状态处理语句
- 当我们要在程序中处理不同的状态信息时,需要知道状态的类型,典型DBMS系统记录状态信息的三种方法
- sqlcode
- sqlca.sqlcode
- sqlstate
二、动态SQL
1. 动态SQL的概念和作用
- 动态SQL语言是相对静态SQL语言而言的
- 静态SQL:SQL语句在程序中已经按要求写好,只需传参,而不需要再进行语句的构造,如
exec sql declare cur_student cursor for
select Sno, Sname, Sclass from Student where Sclass=:vClass
order by Sno for read only
- 动态SQL:SQL语句需要再程序中动态构造,形成一个字符串,然后再交给DBMS执行,交给DBMS执行时仍旧可以传递变量,如
#include <stdio.h>
exec sql include sqlca;//通信区
exec sql begin declare section;//声明变量
char user_name[ ] = “Scott”; char user_pwd[ ] =“tiger”;
char sqltext[ ] = “ delete from customers where cid = \‘c006\’ ” ;
exec sql end declare section;
int main()
{
exec sql whenever sqlerror goto report_error;
exec sql connect :user_name identified by :user_pwd;
exec sql execute immediate :sqltext;//动态SQL语句
exec sql commit release;
return 0;
report_error: print_dberror(); exec sql rollback release; return 1;
}
- 动态SQL通过字符串构造SQL语句,通过变量传递给数据库执行
2. 动态SQL的执行方式
- 立即执行语句: 运行时编译并执行
EXEC SQL EXECUTE IMMEDIATE :host-variable
- Prepare-Execute-Using语句:PREPARE语句先编译,编译
后的SQL语句允许动态参数,EXECUTE语句执行,用USING语句传参
EXEC SQL PREPARE sql_temp FROM :host-variable;/*先编译*/
. . .
EXEC SQL PREPARE sql_temp FROM :host-variable;/*后传参*/
- 例:
#include <stdio.h>
#include "prompt.h"
exec sql include sqlca;
exec sql begin declare section;
char cust_id[5], sqltext[256], user_name[20], user_pwd[10];
exec sql end declare section;
char cid_prompt[ ] = "Name customer cid to be deleted: ";
int main()
{
strcpy(sqltext, "delete from customers where cid = :dcid");
… …
while (prompt(cid_prompt, 1, cust_id, 4) >= 0) {
exec sql whenever not found goto no_such_cid;
exec sql prepare delcust from :sqltext; /* prepare statement */
exec sql execute delcust using :cust_id; /* using clause ... replaces ":n" above */
exec sql commit work; continue;
no_such_cid: printf("No cust %s in table\n",cust_id);
continue;
}
…
}
3. 数据字典与SQLDA
- 数据字典(系统目录)
数据字典是系统维护的一些表或视图的集合,这些表或视图存储了数据库中各类对象的定义信息,这些对象包括用Create语句定义的表、列、索引、视图、权限、约束等,这些信息又称数据库的元数据–关于数据的数据。
- 数据字典的内容构成:数据字典通常存储的是数据库和表的元数据,即模式本身的信息
- 与关系相关的信息
- 用户与账户信息,包括密码
- 统计与描述性数据:如每个关系中元组的数目
- 物理文件组织信息
- 关系是如何存储的
- 关系的物理位置
- 索引相关的信息
- SQLDA(SQLDescriptorArea)
- SQLDA是一个内存数据结构,内可装载关系模式的定义信息,如列的数目,每一列的名字和类型等等
- 通过读取SQLDA信息可以进行更为复杂的动态SQL的处理
- 不同DBMS提供的SQLDA格式并不是一致的
- 构造复杂的动态SQL需要了解数据字典及SQLDA,以获知关系模式信息
4. ODBC和JDBC简介
- ODBC(Open DataBase Connection):不同语言的应用程序与不同数据库服务器之间通讯的标准
- 一组API(应用程序接口),支持应用程序与数据库服务器的交互
- 应用程序通过调用ODBC API, 实现
- 与数据服务器的连接
- 向数据库服务器发送SQL命令
- 一条一条的提取数据库检索结果中的元组传递给应用程序的变量
- 具体的DBMS提供一套驱动程序,即Driver库函数,供ODBC调用,以便实现数据库与应用程序的连接
- ODBC可以配合很多高级语言来使用,如C,C++, C#, Visual Basic, Power-Builder等等
- JDBC(Java DataBase Connection):一组Java版的应用程序接口API,提供了Java应用程序与数据库服务器的连接和通讯能力
- 功能
• java.sql.DriverManager——处理驱动的调入并且对产生新数据库连接提供支持
• Java.sql.Driver——通过驱动进行数据库访问,连接到数据库的应用程序必须具备该数据库的特定驱动
• java.sql.Connection——代表对特定数据库的连接
• java.sql.Statement——对特定的数据库执行SQL语句
• java.sql.PreparedStatement —— 用于执行预编译的SQL语句
• java.sql.CallableStatement ——用于执行对数据库内嵌过程的调用
• java.sql.ResultSet——从当前执行的SQL语句中返回结果数据