编程实例¶
本节将给出选择动态SQL的时机和动态SQL编程的一个完整的例子。分别包括以上几种是否选择动态SQL的情况:是否查询语句?是否多次执行?查询列表数是否已知?是否包含输入主变量?输入主变量数是否已知?
下例分别演示了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);
}