备注:本文为自学记录,如有需要PPT的可以私聊
文章目录
《精缩版(无代码)》
一、嵌入式SQL:预编译,指示变量,游标
游标:用来协调SQL语句和主语言(一条SQL语句产生或处理多条记录,而主语言中的一组主变量一次只能存放一条记录)
游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果
1.1 建立和关闭数据库连接(使用游标)
使用游标的步骤:
- 说明游标
- 打开游标
- 推进游标指针并取当前记录
- 关闭游标
EXEC SQL DECLARE SX CURSOR FOR /*定义游标SX*/
EXEC SQL OPEN SX; /*打开游标SX,指向查询结果的第一行*/
EXEC SQL FETCH SX INTO :HSno,:Hsname,:HSsex,:HSage; /*推进游标,将当前数据放入主变量*/
EXEC SQL UPDATE Student SET Sage = :NEWAGE WHERE CURRENT OF SX; /*对当前游标指向的学生年龄进行更新*/
EXEC SQL CLOSE SX; /*关闭游标SX,不再和查询结果对应*/
1.2 不使用游标的SQL语句
只需用INTO子句指定存放查询结果的主变量
1、不用游标的SQL语句的种类:
- 说明性语句
- 数据定义语句
- 数据控制语句
- 查询结果为单记录的SELECT语句
- 非CURRENT形式的增删改语句
2、使用游标的SQL语句
必须使用游标的SQL语句:
- 查询结果为多条记录的SELECT语句
- CURRENT形式的UPDATE语句
- CURRENT形式的DELETE语句
![图片](https://i-blog.csdnimg.cn/blog_migrate/9c73f7f703239a9a9100edc0759a469d.png)
二、过程化SQL:块结构、变量和常量、控制语句
1、常量:作用域内不允许修改
2、控制语句
- 条件控制语句:IF-THEN,IF-THEN-ELSE和嵌套的IF语句
- 循环控制语句:LOOP,WHILE-LOOP和FOR-LOOP
三、存储过程和函数:命名块和匿名块、存储过程、函数
1、命名块:编译后保存在数据库中,可以被反复调用,运行速度较快,过程和函数是命名块
2、匿名块:每次执行时都要进行编译,它不能被存储到数据库中,也不能在其他过程化SQL块中调用
简言之,命名块可复用,匿名块不可复用
3、存储过程:存储到数据库中
4、函数和存储过程的异同
同:都是持久性存储模块
异:函数必须指定返回的类型
综上,命名块、存储过程、函数,都是永久性存储
四、ODBC编程:ODBC工作原理、ODBC API、
ODBC目的:统一多种数据库,可移植性
4.1 ODBC工作原理
ODBC应用系统的体系结构
1、用户应用程序
2、ODBC驱动程序管理器
3、数据库驱动程序
4、数据源
![图片](https://i-blog.csdnimg.cn/blog_migrate/f26f65c81a953b179ddeef30c74b72d6.png)
1、ODBC应用程序包括的内容
- 请求连接数据库
- 向数据源发送SQL语句
- 为SQL语句执行结果分配存储空间,定义所读取的数据格式
- 获取数据库操作结果或处理错误
- 进行数据处理并向用户提交处理结果
- 请求事务的提交和回滚操作
- 断开与数据源的连接
2、驱动程序管理器:用来管理各种驱动程序
3、ODBC通过驱动程序来提供应用系统与数据库平台的独立性
ODBC驱动程序类型:单束(本地机器/单机)、多束(网络中)
4、数据源:是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象
4.2 ODBC API
1、句柄:句柄是32位整数值,代表一个指针
2、ODBC 3.0中句柄分类:环境句柄、连接句柄、语句句柄、描述符句柄
3、应用程序句柄之间的关系
- 每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景
- 一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接
![图片](https://i-blog.csdnimg.cn/blog_migrate/15a8515c30b365e2d4e0963c5c758ae9.png)
4、ODBC数据类型
- SQL数据类型:用于数据源
- C数据类型 :用于应用程序的C代码
5、SQL数据类型和C数据类型之间的转换规则
![图片](https://i-blog.csdnimg.cn/blog_migrate/d6ccdd687b9fdf03d61e4c0e3b8a01cd.png)
4.3 ODBC工作流程
![图片](https://i-blog.csdnimg.cn/blog_migrate/e6ba35c0fb53dff440568625eb8b9473.png)
《详情版(有代码)》
一、嵌入式SQL:预编译,指示变量,游标
游标:用来协调SQL语句和主语言(一条SQL语句产生或处理多条记录,而主语言中的一组主变量一次只能存放一条记录)
游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果
1.1 建立和关闭数据库连接(使用游标)
[例8.1] 依次检查某个系的学生记录,交互式更新某些学生年龄。
EXEC SQL BEGIN DECLARE SECTION; /*主变量说明开始*/
char Deptname[20];
char Hsno[9];
char Hsname[20];
char Hssex[2];
int HSage;
int NEWAGE;
EXEC SQL END DECLARE SECTION; /*主变量说明结束*/
long SQLCODE;
EXEC SQL INCLUDE SQLCA; /*定义SQL通信区*/
int main(void) /*C语言主程序开始*/
{
int count = 0;
char yn; /*变量yn代表yes或no*/
printf("Please choose the department name(CS/MA/IS): ");
scanf("%s",deptname); /*为主变量deptname赋值*/
EXEC SQL CONNECT TO TEST@localhost:54321 USER "SYSTEM"/"MANAGER"; /*连接数据库TEST*/
EXEC SQL DECLARE SX CURSOR FOR /*定义游标SX*/
SELECT Sno,Sname,Ssex,Sage /*SX对应的语句*/
FROM Student
WHERE SDept = :deptname;
EXEC SQL OPEN SX; /*打开游标SX,指向查询结果的第一行*/
for ( ; ; ) /*用循环结构逐条处理结果集中的记录*/
{
EXEC SQL FETCH SX INTO :HSno,:Hsname,:HSsex,:HSage;
/*推进游标,将当前数据放入主变量*/
if (SQLCA.SQLCODE!= 0) /*SQLCODE != 0,表示操作不成功*/
break; /*利用SQLCA中的状态信息决定何时退出循环*/
if(count++ == 0) /*如果是第一行的话,先打出行头*/
printf("\n%-10s %-20s %-10s %-10s\n","Sno“,"Sname“,"Ssex", "Sage");
printf("%-10s %-20s %-10s %-10d\n“,HSno,Hsname,Hssex,HSage); /*打印查询结果*/
printf(“UPDATE AGE(y/n)?”); /*询问用户是否要更新该学生的年龄*/
do{scanf("%c",&yn);}
while(yn != 'N' && yn != 'n' && yn != 'Y' && yn != 'y');
if (yn == 'y' || yn == 'Y') /*如果选择更新操作*/
{
printf("INPUT NEW AGE:");
scanf("%d",&NEWAGE); /*用户输入新年龄到主变量中*/
EXEC SQL UPDATE Student SET Sage = :NEWAGE WHERE CURRENT OF SX; /*嵌入式SQL更新语句*/
} /*对当前游标指向的学生年龄进行更新*/
}
EXEC SQL CLOSE SX; /*关闭游标SX,不再和查询结果对应*/
EXEC SQL COMMIT WORK; /*提交更新*/
EXEC SQL DISCONNECT TEST; /*断开数据库连接*/
}
1.2 不使用游标的SQL语句
只需用INTO子句指定存放查询结果的主变量
不用游标的SQL语句的种类:
- 说明性语句
- 数据定义语句
- 数据控制语句
- 查询结果为单记录的SELECT语句
- 非CURRENT形式的增删改语句
[例8.2] 根据学生号码查询学生信息
EXEC SQL SELECT Sno,Sname,Ssex,Sage,Sdept
INTO:Hsno,:Hname,:Hsex,:Hage,:Hdept
FROM Student
WHERE Sno=:givensno;
/*把要查询的学生的学号赋给为了主变量givensno*/
3、使用游标的SQL语句
必须使用游标的SQL语句:
- 查询结果为多条记录的SELECT语句
- CURRENT形式的UPDATE语句
- CURRENT形式的DELETE语句
使用游标的步骤:
(1)说明游标
(2)打开游标
(3)推进游标指针并取当前记录
(4)关闭游标
//使用DECLARE语句
//语句格式
EXEC SQL DECLARE <游标名> CURSOR FOR <SELECT语句>;
//使用OPEN语句
//语句格式
EXEC SQL OPEN <游标名>;
//使用FETCH语句
//语句格式
EXEC SQL FETCH <游标名> INTO <主变量>[<指示变量>][,<主变量>[<指示变量>]]...;
//使用CLOSE语句
//语句格式
EXEC SQL CLOSE <游标名>;
fetch 翻译:拿来
![图片](https://i-blog.csdnimg.cn/blog_migrate/9c73f7f703239a9a9100edc0759a469d.png)
二、过程化SQL:块结构、变量和常量、控制语句
常量:作用域内不允许修改
控制语句
1、条件控制语句:IF-THEN,IF-THEN-ELSE和嵌套的IF语句
(1)IF-THEN
IF condition THEN
Sequence_of_statements;
END IF;
(2)IF-THEN-ELSE
IF condition THEN
Sequence_of_statements1;
ELSE
Sequence_of_statements2;
END IF;
(3)在THEN和ELSE子句中还可以再包含IF语句,即IF语句可以嵌套
2、循环控制语句:LOOP,WHILE-LOOP和FOR-LOOP
(1)简单的循环语句LOOP
LOOP
Sequence_of_statements;
END LOOP;
多数数据库服务器的过程化SQL都提供EXIT、BREAK或LEAVE等循环结束语句,保证LOOP语句块能够结束
(2)WHILE-LOOP
WHILE condition LOOP
Sequence_of_statements;
END LOOP;
(3)FOR-LOOP
FOR count IN [REVERSE] bound1 … bound2 LOOP
Sequence_of_statements;
END LOOP;
三、存储过程和函数:命名块和匿名块、存储过程、函数
1、命名块:编译后保存在数据库中,可以被反复调用,运行速度较快,过程和函数是命名块
2、匿名块:每次执行时都要进行编译,它不能被存储到数据库中,也不能在其他过程化SQL块中调用
简言之,命名块可复用,匿名块不可复用
3、存储过程:存储到数据库中
4、函数和存储过程的异同
同:都是持久性存储模块
异:函数必须指定返回的类型
四、ODBC编程:ODBC工作原理、ODBC API、
ODBC目的:统一多种数据库
4.1 ODBC工作原理
ODBC应用系统的体系结构
1、用户应用程序
2、ODBC驱动程序管理器
3、 数据库驱动程序
4、 数据源
![图片](https://i-blog.csdnimg.cn/blog_migrate/f26f65c81a953b179ddeef30c74b72d6.png)
1、ODBC应用程序包括的内容
- 请求连接数据库
- 向数据源发送SQL语句
- 为SQL语句执行结果分配存储空间,定义所读取的数据格式
- 获取数据库操作结果或处理错误
- 进行数据处理并向用户提交处理结果
- 请求事务的提交和回滚操作
- 断开与数据源的连接
2、驱动程序管理器:用来管理各种驱动程序
3、ODBC通过驱动程序来提供应用系统与数据库平台的独立性
ODBC驱动程序类型:单束(本地机器/单机)、多束(网络中)
4、数据源:是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象
4.2 ODBC API
1、句柄:句柄是32位整数值,代表一个指针
2、ODBC 3.0中句柄分类:环境句柄、连接句柄、语句句柄、描述符句柄
3、应用程序句柄之间的关系
- 每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景
- 一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接
![图片](https://i-blog.csdnimg.cn/blog_migrate/15a8515c30b365e2d4e0963c5c758ae9.png)
4、ODBC数据类型
- SQL数据类型:用于数据源
- C数据类型 :用于应用程序的C代码
5、SQL数据类型和C数据类型之间的转换规则
![图片](https://i-blog.csdnimg.cn/blog_migrate/d6ccdd687b9fdf03d61e4c0e3b8a01cd.png)
4.3 ODBC工作流程
![图片](https://i-blog.csdnimg.cn/blog_migrate/e6ba35c0fb53dff440568625eb8b9473.png)
[例8.11] 将KingbaseES数据库中Student表的数据备份到SQL Server数据库中
创建数据源的详细过程
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <Sqltypes.h>
#define SNO_LEN 30
#define NAME_LEN 50
#define DEPART_LEN 100
#define SSEX_LEN 5
int main()
{ /* Step 1 定义句柄和变量 */
/*以king开头的表示的是连接KingbaseES的变量*/
/*以server开头的表示的是连接SQLServer的变量*/
SQLHENV kinghenv,serverhenv; /*环境句柄*/
SQLHDBC kinghdbc,serverhdbc; /*连接句柄*/
SQLHSTMT kinghstmt,serverhstmt; /*语句句柄*/
SQLRETURN ret;
SQLCHAR sName[NAME_LEN],sDepart[DEPART_LEN], sSex[SSEX_LEN],sSno[SNO_LEN];
SQLINTEGER sAge;
SQLINTEGER cbAge=0,cbSno=SQL_NTS,cbSex=SQL_NTS, cbName=SQL_NTS,cbDepart=SQL_NTS;
/* Step 2 初始化环境 */
/* 调用SQLAllocHandle分配连接句柄,通过SQLConnect、SQLDriverConnect或SQLBrowseConnect与数据源连接 ;SQLConnect连接函数的输入参数为:配置好的数据源名称\用户ID、口令 */
ret=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&kinghenv);
ret=SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&serverhenv);
ret=SQLSetEnvAttr(kinghenv,SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
ret=SQLSetEnvAttr(serverhenv,SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
/* Step 3 建立连接 */
ret=SQLAllocHandle(SQL_HANDLE_DBC, kinghenv, &kinghdbc);
ret=SQLAllocHandle(SQL_HANDLE_DBC, serverhenv, &serverhdbc);
ret=SQLConnect(kinghdbc,“KingbaseES ODBC”, SQL_NTS, “SYSTEM”,SQL_NTS, "MANAGER",SQL_NTS);
if (!SQL_SUCCEEDED(ret)) /*连接失败时返回错误值*/
return -1;
ret=SQLConnect(serverhdbc, "SQLServer", SQL_NTS, "sa“,SQL_NTS,"sa",SQL_NTS);
if (!SQL_SUCCEEDED(ret) ) /*连接失败时返回错误值*/
return -1;
/* Step 4 初始化语句句柄 */
ret=SQLAllocHandle(SQL_HANDLE_STMT,kinghdbc, &kinghstmt);
ret=SQLSetStmtAttr(kinghstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) SQL_BIND_BY_COLUMN, SQL_IS_INTEGER);
ret=SQLAllocHandle(SQL_HANDLE_STMT,serverhdbc, &serverhstmt);
/* Step 5 两种方式执行语句 */
/* 预编译带有参数的语句 */
ret=SQLPrepare(serverhstmt,"INSERT INTO STUDENT(SNO,SNAME, SSEX, SAGE,SDEPT) VALUES (?, ?, ?, ?, ?)", SQL_NTS);
if (ret==SQL_SUCCESS || ret==SQL_SUCCESS_WITH_INFO)
{
ret=SQLBindParameter(serverhstmt,1,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR,SNO_LEN,0,sSno,0, &cbSno);
ret=SQLBindParameter(serverhstmt,2,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR,NAME_LEN,0,sName,0,&cbName);
ret=SQLBindParameter(serverhstmt,3,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR,2,0,sSex,0,&cbSex);
ret=SQLBindParameter(serverhstmt,4,SQL_PARAM_INPUT, SQL_C_LONG,SQL_INTEGER,0,0,&sAge,0,&cbAge);
ret=SQLBindParameter(serverhstmt,5,SQL_PARAM_INPUT, SQL_C_CHAR,SQL_CHAR, DEPART_LEN, 0, sDepart,0, &cbDepart);}
/*执行SQL语句*/
ret=SQLExecDirect(kinghstmt,"SELECT * FROM STUDENT",SQL_NTS);
if (ret==SQL_SUCCESS || ret==SQL_SUCCESS_WITH_INFO)
{
ret=SQLBindCol(kinghstmt,1,SQL_C_CHAR,sSno, SNO_LEN,&cbSno);
ret=SQLBindCol(kinghstmt,2,SQL_C_CHAR,sName, NAME_LEN,&cbName);
ret=SQLBindCol(kinghstmt,3,SQL_C_CHAR,sSex, SSEX_LEN,&cbSex);
ret=SQLBindCol(kinghstmt,4,SQL_C_LONG,&sAge, 0,&cbAge);
ret=SQLBindCol(kinghstmt,5,SQL_C_CHAR,sDepart, DEPART_LEN,&cbDepart);
}
/* Step 6 处理结果集并执行预编译后的语句*/
while ((ret=SQLFetch(kinghstmt))!=SQL_NO_DATA_FOUND)
{
if(ret==SQL_ERROR)
printf("Fetch error\n");
else
ret=SQLExecute(serverhstmt);
}
/* Step 7 中止处理:释放语句句柄、释放数据库连接、与数据库服务器断开、释放ODBC环境 */
SQLFreeHandle(SQL_HANDLE_STMT,kinghstmt);
SQLDisconnect(kinghdbc);
SQLFreeHandle(SQL_HANDLE_DBC,kinghdbc);
SQLFreeHandle(SQL_HANDLE_ENV,kinghenv);
SQLFreeHandle(SQL_HANDLE_STMT,serverhstmt);
SQLDisconnect(serverhdbc);
SQLFreeHandle(SQL_HANDLE_DBC,serverhdbc);
SQLFreeHandle(SQL_HANDLE_ENV,serverhenv);
return 0;
}