编程实例

本节将给出选择动态SQL的时机和动态SQL编程的一个完整的例子。分别包括以上几种是否选择动态SQL的情况:是否查询语句?是否多次执行?查询列表数是否已知?是否包含输入主变量?输入主变量数是否已知?

下例分别演示了5种情况下四种方法的选择时机:

  1. 非查询语句,无输入主变量,非多次执行情况下,选择方法一;
  2. 非查询语句,无输入主变量,多次执行,选择方法二;
  3. 非查询语句,有输入主变量,输入主变量数目已知,选择方法二;
  4. 查询语句,查询列表数目已知,主变量数目已知,选择方法三;
  5. 查询语句,查询列表数未知,选择方法四。

例 8-4

/******************************************************************************
这是一个简单的动态SQL编程实例。
该范例显示主菜单,用户可以根据提示信息选择,选择功能后,
根据提示信息进行输入,可以执行插入、删除、更新和查询操作。
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
void error()
{
	/*对错误情况不予处理,以防止死循环*/
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	/*输出错误信息*/
	sqlprint();
	EXEC SQL ROLLBACK WORK;
	exit(1);
}
int main() {
	/* 声明宿主变量*/
	EXEC SQL BEGIN DECLARE SECTION;
	char hnum[4]; /* 用于存放用户输入的empnum信息*/
	char hname[21]; /*以下3个变量用于存放查到的员工信息*/
	char hcity[16];
	int hgrade;
	int hbrchnum;
	int ind_name;
	int ind_grade;
	int ind_city;
	int hlen;
	char hcol[21];
	int htype;
	char hdata[21];
	int hindex;
	char command[80];
	varchar query[80];
	char query2[80];
	EXEC SQL END DECLARE SECTION;
	long SQLCODE; /* 用于取得系统执行语句返回的错误码 */
	char SQLSTATE[6]; /* 用于取得系统执行语句返回的错误状态,
比错误码更详细、精确 */
	int num = 0;
	int rowcnt = 0;
	char item[10];
	char a[2];
	/* 对错误情况进行处理 */
	EXEC SQL WHENEVER SQLERROR do error();
	
	/* 连接神通数据库,其中"@localhost"可省略 */
	EXEC SQL CONNECT TO osrdb@localhost USER
	sysdba USING szoscar55;
	if (SQLCODE != 0) {
		printf("连接数据库服务器失败.\n");
		exit(1);
	}
	
	EXEC SQL WHENEVER SQLERROR CONTINUE;
	/*建表之前删除已经存在的表*/
	EXEC SQL DROP TABLE employee;
	EXEC SQL WHENEVER SQLERROR do error();
	/* 创建表employee */
    EXEC SQL CREATE TABLE employee(
        empnum CHARACTER(3) PRIMARY KEY,
        empname CHAR(20),
        grade DECIMAL(4,0),
        city VARCHAR(15),
		brchnum INT);
    if (SQLCODE == 0)
	{
		printf("表employee成功创建!\n");
	}
        
	printf("=================欢迎来到简单员工管理系统!=================\n");
	/* 准备查询整表信息的语句和游标 */
	strcpy(query, "SELECT * FROM employee");
	EXEC SQL PREPARE prep_sel FROM :query;
	EXEC SQL DECLARE cur_sel CURSOR FOR prep_sel;
	
do_again:
	switch (num){
	case 0:
		goto do_insert;
	case 1:
		goto do_update;
	case 2:
		goto do_delete;
	case 3:
		goto do_exit;
	default:
		goto do_exit;
	}
	/* 第5种情况:查询表中的所有信息,并显示 */
do_select:
	EXEC SQL ALLOCATE DESCRIPTOR desc_emp WITH MAX 10;
	/* 最多只能有10列 */
	EXEC SQL OPEN cur_sel;
	rowcnt = 0;
	while (1) {
		EXEC SQL FETCH cur_sel INTO SQL DESCRIPTOR desc_emp;
		if (SQLCODE != 0)
		{
			break;
		}	
		rowcnt++;
		printf("行号#%d:\n", rowcnt);
		for (hindex = 1; ;hindex++) {
			EXEC SQL GET DESCRIPTOR desc_emp VALUE :hindex :hlen = LENGTH, \
				:htype = TYPE, :hcol =NAME, :hdata = DATA;
			if (SQLCODE != 0) {
				break;
			}else
			{
				printf("==列号#%d: TYPE = %d, NAME = %s, DATA = %s, \
					   LENGTH = %d\n", hindex, htype, hcol, hdata, hlen);
			}	
		}
	}
	EXEC SQL CLOSE cur_sel;
	EXEC SQL DEALLOCATE DESCRIPTOR desc_emp;
	num++;
	goto do_again;

	/* 第3种情况:向表中插入一个员工信息元组 */
do_insert:
	strcpy(command, "INSERT INTO employee \
		   VALUES (?, ?, ?, '杭州', ?)");
	EXEC SQL PREPARE prep_ins FROM :command;
	strcpy(hnum,"E8");//新员工的empnum
	strcpy(hname,"艾黎");//新的员工名字
	hgrade = 5;//新的员工级别
	hbrchnum = 8;//新员工所在子公司编号
	EXEC SQL EXECUTE prep_ins USING :hnum, :hname, :hgrade, :hbrchnum;
	if (SQLCODE == 0)
	{
		printf("已经成功插入新的元组: %s, %s, %d, 杭州, %d!\n", \
			   hnum, hname, hgrade, hbrchnum);
	}	
	EXEC SQL DEALLOCATE prep_ins;
	goto do_select;
	/* 第1种情况:根据用户输入的删除语句删除指定的行 */
do_delete:
	sprintf(command,"delete from employee where empnum = 'E8'");
	printf("输入要执行的DELETE语句:%s\n",command);
	EXEC SQL EXECUTE IMMEDIATE :command;
	if (SQLCODE == 0)
		printf("已经按照您的语句要求成功删除该元组!\n");
	else
	{
		sqlprint();
	}
	goto do_select;
	/* 第2种情况:根据用户的输入更新来自某些城市的职工信息的grade列 */
do_update:
	strcpy(command, "UPDATE employee SET grade = 8 WHERE \
		   city = ?");
	EXEC SQL PREPARE prep_upd FROM :command;
	if (SQLCODE != 0) {
		printf("准备要执行的UPDATE语句失败!\n");
	}
	strcpy(hcity,"杭州");
	EXEC SQL EXECUTE prep_upd USING :hcity;
	if (SQLCODE == 0)
	{
		printf("已经成功更新来自%s的员工的级别信息!\n", hcity);
	}
	EXEC SQL DEALLOCATE prep_upd;
	goto do_select;
do_error:
	error();
	goto do_again;
	
/* 退出程序 */
do_exit:
	EXEC SQL DROP TABLE employee;
	EXEC SQL COMMIT WORK;
	EXEC SQL DISCONNECT;
	exit(0);
}