本文仅供参考学习使用,谢谢


文章目录

  • 从主语言访问数据库的基本步骤
  • 1.建立数据库连接
  • 2.定义主变量与数据通讯区
  • 3.执行SQL语句
  • 4.关闭数据库连接
  • 嵌入式SQL语句的基本格式
  • 嵌入式SQL语句与主语言之间的通信
  • 1.SQL通信区
  • 2.主变量
  • 3.游标
  • 查询结果为多条记录的SELECT语句
  • 1.申明游标
  • 2.打开游标
  • 3.推进游标指针并取当前记录
  • 4.关闭游标
  • CURRENT形式的UPDATE/DELETE语句



从主语言访问数据库的基本步骤

  • 打开数据库
  • 定义必要的主变量和数据通信区
  • 用SQL访问数据库,并对返回结果进行处理
  • 关闭数据库

eg:

#include <stdio.h> 
#include <stdlib.h>
EXEC SQL BEGIN DECLARE SECTION; /** 主变量说明开始*/ 
	char HSno[9];
	char HSname[20]; 
	char HSex[2];
	int HSage;
	char Hdept[20];
EXEC SQL END DECLARE SECTION; /** 主变量说明结束*/ 
long SQLCODE;
EXEC SQL INCLUDE sqlca;/** 定义SQL通信区 */

int main() {
	printf("Please input the sno:");/** 输入要查找的学生学号*/ 
	scanf("%s", HSno);

/**	连接数据库(数据库名字是TEST,主集名字是localhost,端口号为54321,用户名密码为“SYSTEM/krms”*/
	EXEC SQL CONNECT TO TEST@localhost:54321 AS CONN1 USER "SYSTEM“ USING “manager";

	EXEC SQL
		SELECT Sno,Sname,Ssex,Sage,Sdept INTO:Hsno,:Hname,:Hsex,:Hage,:Hdept
		FROM Student
		WHERE Sno=:HSno;

	if (sqlca.sqlcode == 0) {
		printf("\n% - 9s% - 20s% - 2s% - 4s% - 20s\n", "Sno", "Sname","Ssex", "Sage", "Sdept");
		printf("% - 9s% - 20s% - 2s% - 4s% - 20s\n", Hsno, Hname, Hsex, HSage, Hdept);
	}

	EXEC SQL DISCONNECT CONN1; 
	return 0;
}

1.建立数据库连接

EXEC SQL CONNECT TO target 
[AS connection-name] 
[USER user-name];
  • target是要链接的数据库服务器的名字
  • 常见的服务器表示串,如@:
  • 包含服务器标识的SQL串常量
  • DEFAULT
  • 􏰁 connect-name是可选的连接名
  • 连接名必须是一个有效的标识符
  • 在整个程序内只有一个连接时可以不指定连接名
  • 程序运行过程中可以修改当前连接
EXEC SQL SET CONNECTION connection-name
|DEFAULT;

2.定义主变量与数据通讯区

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通信区*/

3.执行SQL语句

  • 所有的SQL语句都可以以嵌入式的方式使用
  • DDL数据定义语言(CREATE)
  • DML数据控制语言(GRANT,REVOKECOMMITROBACK)
  • DCL数据更新语言(UPDATE, INSERT, DELETE)
  • DQL数据查询语言􏰁 (SELECT)

eg:

//根据学生号码查询学生的信息
EXEC SQL SELECT Sno,Sname,Ssex,Sage,Sdept
	INTO:Hsno,:Hname,:Hsex,:Hage,:Hdept
	FROM Student
	WHERE Sno=:givensno;
//增加了一个INTO子句,用于保存查询结果
//前面带有 “ : ” 标识的变量成为主变量,即主语言的变量
  • INTO子句,WHERE子句和HAVING短语的条件表达式中均可以使用主变量
  • 查询返回的记录中,可能存在某些列为空值NULL
  • 注意:如果查询结果实际上并不是单条记录,而是多条记录,则程序出错,关系数据库管理系统会返回错误信息

  • 在UPDATE的SET子句和WHERE子句中可以使用主变量
//修改某个学生选修1号课程的成绩
EXEC SQL UPDATE SC
SET Grade=:newgrade 	/*修改的成绩已赋给主变量:newgrade*/
WHERE Sno=:givensno AND Cno=1; /*学号赋给主变量:givensno*/

4.关闭数据库连接

EXEC SQL DISCONNECT [connection];

实例:

//打印指定学号的学生记录

//主变量定义区
EXEC SQL BEGIN DECLARE SECTION; 
	char Deptname[20];
	char HSNo[9];
	char HSName[20];
	char HSSex[2];
	int HSAge;
EXEC SQL END DECLARE SECTION;

//定义SQL通讯区
long SQLCODE;
EXEC SQL INCLUDE SQLCA;

//C语言主程序开始
int main(void){
	printf("Please input the student number "); 
	scanf("%s", Hsno); //为主变量Hsno赋值
	
	//连接Test数据库
	EXEC SQL CONNECT TO TEST@localhost:54321 AS CONN1	
	USER "SYSTEM" USING "MANAGER"

	//执行SQL查询
	EXEC SQL SELECT Sno,Sname,Ssex,Sage,Sdept
		INTO:Hsno,:Hname,:Hsex,:Hage,:Hdept
		FROM Student 
		WHERE Sno=:HSno

	//
	if(sqlca.sqlcode == 0){ /* SQLCA中的SQLCODE == 0  表示操作成功*/ 
	printf("\n %-9s %-20s %-2s %-4s %-20s\n", "Sno", "Sname", "Ssex", "Sage", "Sdept");
	printf("% - 9s% - 20s% - 2s% - 4s% - 20s\n", Hsno, Hname, Hsex, HSage, Hdept);
	}
	EXEC SQL DISCONNECT CONN1;//关闭游标断开连接

嵌入式SQL语句的基本格式

  • 为了区分SQL语句与诸语言语句,所有的SQL语句必须加前缀EXEC SQL

主语言为C语言时,语句格式:

EXEC SQL <SQL 语句>;

eg:

EXEC SQL SELECT Sno,Sname,Ssex,Sage,Sdept 
	INTO:Hsno,:Hname,:Hsex,:Hage,:Hdept
	FROM Student
	WHERE Sno=:givensno;

嵌入式SQL语句与主语言之间的通信

  • 数据库工作单元与主程序工作单元之间的通讯
  • 向主语言传递SQL语句的执行状态信息,使主语言能够据此控制程序流程
    //主要用于SQL通信区实现
  • 主语言向SQL语句提供参数
    //主要用主变量实现
  • 将SQL语句查询数据库的结果返回给主语言处理
    //主要用主变量和游标实现

1.SQL通信区

  • SQLCA的用途
  • SQL语句执行后,系统反馈给应用程序信息
  • 描述系统当前工作状态
  • 描述运行环境
  • 这些信息将送到SQL通讯区中
  • 应用程序从SQL通信区中取出这些状态信息,据此决定接下来执行的语句

  • SQLCA:SQL Communication Area
  • SQLCA是一个数据结构
struct sqlca_t{
	char sqlcaid[8];
	long sqlabc;
	long sqlcode;
	
	struct{
		int sqlerrml;
		char sqlerrmc[SQLERRMC_LEN];
	}sqlerrmc;
	
	char sqlerrp[8];
	long sqlerrd[6];
	char sqlwarn[8];
	char sqlstate[5];
};

SQLCA使用方法:

  • 定义SQLCA
EXEC SQL INCLUDE SQLCA
  • 使用SQLCA
  • SQLCA中有一个存放每次执行SQL语句后返回代码的变量SQLCODE
  • 如果SQLCODE等于与定义的常量SUCCESS,则表示SQL语句成功,否则出错
  • 应用每执行完一条SQL语句之后都应该测试一下SQLCODE的值,以了解SQL语句执行情况并做相应处理

2.主变量

  • 主变量
  • 嵌入式SQL语句中可以使用主语言的程序变量来输入或输出数据
  • 在SQL语句中使用的主语言程序变量简称为主变量(Host Variable)
  • 主变量的类型
  • 输入主变量
  • 由应用程序对其赋值,SQL语句引用
  • 输出主变量
  • 由SQL语句对其赋值或设置状态信息,返回给应用程序
  • 指示变量
  • 是一个整型变量,用来“指示”所指主变量的值或条件
  • 一个主变量可以附带一个指示变量(Indicator Variable)
  • 指示变量的用途
  • 指示输入主变量是否为空值
  • 检测输出变量是否为空值,值是否被截断

eg1:

/*查询某个学生选修的某门课程的成绩,假设已经把将要查询的
学生学号赋给了主变量givensno
将课程号赋给了主变量givencno	*/

EXEC SQL SELECT Sno,Cno,Grade
	INTO :Hsno,:Hcno,:Hgrade:Gradeid 	/* 指示变量Gradeid*/
	FROM SC
	WHERE Sno=:givensno AND Cno=:givencno
	
//如果Gradeid < 0Hgrade,不论Hgrade为何值,均认为该学生成绩为空

eg2:

//某个学生选修了某门课程,将有关记录插入SC表中,
//假设插入的学号已赋值给主变量stdno,课程号已赋值给主变量couno

gradeid=-1 /*gradeid为指示变量,赋值为负值*/ 
EXEC SQL INSERT
	INTO SC(Sno,Cno,Grade) 
	VALUES(:stdno,:couno,:gr :gradeid);
	
//:stdno , :couno  ,  :gr为主变量
//由于该学生刚选修课程,成绩应为空,所以要把指示变量赋值为负值

在SQL语句中使用主变量和指示变量的方法

  1. 说明主变量和指示变量
BEGIN DECLARE SECTION
	... 
	... //在此说明
	...
END DECLARE SECTION
  1. 使用主变量
  • 说明之后的主变量可以在SQL语句中任何一个能够使用表达式的地方出现
  • 为了与数据库对象名(表名,视图名,列名etc)区别,SQL语句中的主变量名前面要加冒号(:)作为标志
  1. 使用指示变量
  1. 指示变量前也必须加冒号标志
  2. 必须紧跟在所指主变量之后
  1. 在SQL语句之外(主语言语句中)使用主变量和指示变量的方法
  1. 直接使用不用加冒号

3.游标

游标的定义:

  • 游标是系统为用户开设的一个数据缓冲区,存放SQL语句的执行结果
  • 每个游标区都有一个名字,也可以理解为该数据区的指针
  • 用户可以用SQL语句逐一从游标中(指针所指示的位置)获取记录,并赋给主变量,交由主语言进一步处理

为什么要使用游标:

  • SQL语言与主语言具有不同数据处理方式
  • SQL语言是面向集合的,一条SQL语句原则上可以产生或处理多条记录
  • 主语言是面向记录的,一组主变量一次只能存放一条记录
  • 仅使用主变量并不能完全满足SQL语句向应用程序输出数据的要求
  • 嵌入式SQL引入了游标的概念,用来协调这两种不同的处理方式

使用游标的步骤:

  1. 说明游标(DECLARE)
  2. 打开游标(OPEN)
  3. 推进游标指针并取当前记录( FETCH )
  4. 关闭游标(CLOSE)

必须使用游标的SQL语句:

  • 查询结果为多条记录的SELECT语句
  • CURRENT形式的UPDATE语句
  • CURRENT形式的DELETE语句
查询结果为多条记录的SELECT语句
1.申明游标
  • 使用DECLARE语句
EXEC SQL DECLARE <游标名> CURSOR
			FOR <SELECT语句>;
  • 功能
    是一条说明性语句,这时DBMS并不执行SELECT指定的查询操作。
2.打开游标
  • 使用OPEN语句
EXEC SQL OPEN <游标名>;
  • 功能
  • 打开游标实际上是执行相应的SELECT语句,把所有满足查询条件的记录从指定表取到缓冲区中
  • 这时游标处于活动状态,指针指向查询结果集中第一条记录
3.推进游标指针并取当前记录
  • 使用FETCH语句
EXEC SQL FETCH [  [NEXT|PRIOR|FIRST|LAST]  FROM ] <游标名> 
  INTO <主变量>[<指示变量>]
  [,<主变量>[<指示变量>]]...;

NEXT|PRIOR|FIRST|LAST:指定推动游标指针的方式
NEXT:向前推进一条记录
PRIOR:向回退一条记录
FIRST:推向第一条记录
LAST:推向最后一条记录
默认缺省值为NEXT
  • 功能
  • 指定方向推动游标指针,然后将缓冲区中的当前记录取出来送至主变量供主语言进一步处理
4.关闭游标
  • 使用CLOSE语句
EXEC SQL CLOSE <游标名>;
  • 功能
  • 关闭游标,释放结果集占用的缓冲区及其他资源
  • 说明
  • 游标被关闭后,就不再和原来的查询结果集相联系
  • 被关闭的游标可以再次被打开,与新的查询结果相联系

删除游标:

DEALLOCATE <游标名>;
CURRENT形式的UPDATE/DELETE语句

CURRENT形式的UPDATE语句和DELETE语句的用途
面向集合的操作: 一次修改或删除所有满足条件的记录

  • 如果只想修改或删除其中某个记录
  • 用带游标的SELECT语句查出所有满足条件的记录
  • 从中进一步找出要修改或删除的记录
  • 用CURRENT形式的UPDATE语句和DELETE语句修改或删除之
  • UPDATE语句和DELETE语句中的子句:
    WHERE CURRENT OF <游标名>
    表示修改或删除的是最近一次取出的记录,即游标指针指向的记录
  • 不能使用CURRENT形式的UPDATE语句DELETE语句 :
  • 当游标定义中的SELECT语句带有UNION或ORDER BY子句
  • 该SELECT语句相当于定义了一个不可更新的视图
//依次检查某个系的学生记录,交互式更新某些学生年龄
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; //主变量说明结束

//定义SQL通信区
long SQLCODE;
EXEC SQL INCLUDE SQLCA;

int main(void){ //c语言主程序开始
	int count = 0;
	char yn; 		//变量yn代表 yes或no
	printf("Please choose the department name(CS/MA/IS): "); 
	scanf("%s",deptname); 		//为主变量deptnumber赋值
	EXEC SQL CONNECT TO TEST@localhost:54321 USER
		"SYSTEM"/"MANAGER";  	//连接数据库Test
	EXEC SQL DECLARE SX CURSOR FOR 	//定义游标
		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) 	//SQLCA.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 	//嵌入式SQL更新语句
			SET Sage = :NEWAGE
			WHERE CURRENT OF SX;
		}
	}
	EXEC SQL CLOSE SX;		//关闭游标,不再和查询结果对应
	EXEC SQL COMMIT WORK;	//提交更新
	EXEC SQL DISCONNECT TEST;	//断开数据库连接
}