数据库 之数据库编程浅知识(代码结合PPT理解)

备注:本文为自学记录,如有需要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语句
图片

二、过程化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、数据源

图片

1、ODBC应用程序包括的内容

  • 请求连接数据库
  • 向数据源发送SQL语句
  • 为SQL语句执行结果分配存储空间,定义所读取的数据格式
  • 获取数据库操作结果或处理错误
  • 进行数据处理并向用户提交处理结果
  • 请求事务的提交和回滚操作
  • 断开与数据源的连接

2、驱动程序管理器:用来管理各种驱动程序

3、ODBC通过驱动程序来提供应用系统与数据库平台的独立性
ODBC驱动程序类型:单束(本地机器/单机)、多束(网络中)

4、数据源:是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象

4.2 ODBC API

1、句柄:句柄是32位整数值,代表一个指针

2、ODBC 3.0中句柄分类:环境句柄、连接句柄、语句句柄、描述符句柄

3、应用程序句柄之间的关系

  • 每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景
  • 一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接
图片

4、ODBC数据类型

  • SQL数据类型:用于数据源
  • C数据类型 :用于应用程序的C代码

5、SQL数据类型和C数据类型之间的转换规则

图片

4.3 ODBC工作流程

图片

《详情版(有代码)》

一、嵌入式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 翻译:拿来

图片

二、过程化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、 数据源

图片

1、ODBC应用程序包括的内容

  • 请求连接数据库
  • 向数据源发送SQL语句
  • 为SQL语句执行结果分配存储空间,定义所读取的数据格式
  • 获取数据库操作结果或处理错误
  • 进行数据处理并向用户提交处理结果
  • 请求事务的提交和回滚操作
  • 断开与数据源的连接

2、驱动程序管理器:用来管理各种驱动程序

3、ODBC通过驱动程序来提供应用系统与数据库平台的独立性
ODBC驱动程序类型:单束(本地机器/单机)、多束(网络中)

4、数据源:是最终用户需要访问的数据,包含了数据库位置和数据库类型等信息,是一种数据连接的抽象

4.2 ODBC API

1、句柄:句柄是32位整数值,代表一个指针

2、ODBC 3.0中句柄分类:环境句柄、连接句柄、语句句柄、描述符句柄

3、应用程序句柄之间的关系

  • 每个ODBC应用程序需要建立一个ODBC环境,分配一个环境句柄,存取数据的全局性背景
  • 一个环境句柄可以建立多个连接句柄,每一个连接句柄实现与一个数据源之间的连接
图片

4、ODBC数据类型

  • SQL数据类型:用于数据源
  • C数据类型 :用于应用程序的C代码

5、SQL数据类型和C数据类型之间的转换规则

图片

4.3 ODBC工作流程

图片

[例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;
	}
发布了33 篇原创文章 · 获赞 5 · 访问量 5964

猜你喜欢

转载自blog.csdn.net/qq_41956139/article/details/104317211