#include <stdio.h>
#include <windows.h>
#include <sqlext.h>
//char *szDSN = "Driver={Microsoft Access Driver (*.mdb)};DSN='';DBQ=DB.mdb;";
char *szDSN = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=localhost;Database=DB;User=root;Password=soleil;Option=3;";
SQLCHAR *cEqualJoin=(SQLCHAR *)" Student INNER JOIN (Course INNER JOIN CourseSelection ON Course.iNum = CourseSelection.Course_id) ON Student.iNum = CourseSelection.Student_id" ;
HENV hEnv;//准备环境句柄
HDBC hDbc;//准备连接句柄
HSTMT hStmt;//准备语句句柄
RETCODE rcRecord;
SQLCHAR Course_cTitle[128];
SQLCHAR Student_cName[128],Student_cClass[128];
SQLINTEGER Course_iNum=0,Course_iCredit=0;
SQLINTEGER Student_iNum=0,Student_age=0;
SQLINTEGER CourseSelection_id=0,CourseSelection_St_id=0,CourseSelection_Course_id=0;
int main()
{
int iTopMenu;
void Init();
void ShowSecondMenu(int iTopMenu);
void Finish();
Init();
do{
system("cls");
printf("\t\t\t---------------------------------\t\n");
printf("\t\t\t|\t课程选修管理系统!\t|\n");
printf("\t\t\t|\t 欢迎使用!\t\t|\n");
printf("\t\t\t---------------------------------\n");
printf("\n\n");
printf("\t\t\t-------------主菜单--------------\t\n");
printf("\t\t\t|\t \t\t|\n");
printf("\t\t\t|\t1.课程管理\t\t|\n");
printf("\t\t\t|\t \t\t|\n");
printf("\t\t\t|\t2.学生管理\t\t|\n");
printf("\t\t\t|\t \t\t|\n");
printf("\t\t\t|\t3.选课管理\t\t|\n");
printf("\t\t\t|\t \t\t|\n");
printf("\t\t\t|\t0.退出系统\t\t|\n");
printf("\t\t\t---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~3):\n");
scanf("%d",&iTopMenu);
if(iTopMenu!=0)
{
ShowSecondMenu(iTopMenu);
}
else
{
break;
}
}while(1);
Finish();
return 0;
}
void ShowSecondMenu(int iTopMenu)
{
int ShowRecord(int DbSource,SQLCHAR *cSELECTString);
void SearchMenu(int iTopMenu);
void InsertRecord(int iTopMenu);
void EditRecord(int DBSource);
void DeleteRecord(int DBSource);
int iChoice=0;
SQLCHAR cStr_DB[200],SplicSQL[200];
while(1)
{
switch (iTopMenu)
{
case 1:
strcpy(cStr_DB,"Course");
system("cls");
printf("---------------------------------\t\n");
printf("|\t课程管理菜单\t\t|\n");
printf("---------------------------------\n");
printf("|\t1.课程录入\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.课程查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t3.全部显示\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~3):\n")
scanf("%d",&iChoice);
break;
case 2:
strcpy(cStr_DB,"Student");
system("cls");
printf("---------------------------------\t\n");
printf("|\t学生管理菜单\t\t|\n");
printf("---------------------------------\n");
printf("|\t1.学籍录入\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.学籍查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t3.全部显示\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返 回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~3):\n");
scanf("%d",&iChoice);
break;
case 3:
system("cls");
strcpy(cStr_DB,cEqualJoin);
printf("---------------------------------\t\n");
printf("|\t选课管理菜单\t\t|\n");
printf("---------------------------------\n");
printf("|\t1.选课操作\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.信息查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t3.全部显示\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~3):\n");
scanf("%d",&iChoice);
break;
}
switch(iChoice)
{
case 1:
InsertRecord(iTopMenu);
system("pause");
break;
case 2:
SearchMenu(iTopMenu);
break;
case 3:
if(iTopMenu!=3)
{
sprintf(SplicSQL,"SELECT * FROM %s ORDER BY iNum",cStr_DB);
}
else
{
sprintf(SplicSQL,"SELECT CourseSelection.id,Student.st_name,Course.Title,Student.class,Course.Credit,CourseSelection.Course_id,CourseSelection.Student_id FROM %s",cStr_DB);
}
ShowRecord(iTopMenu,SplicSQL);
system("pause");
break;
case 0:
return;
}
}
}
void InsertRecord(int DBSource)
{
SQLCHAR SplicSQL[200];
int iSt_id,iCo_id,rowCount;
int ShowRecord(int DbSource,SQLCHAR *cSELECTString);
int Student_age;
rcRecord=SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//在环境句柄、连接句柄基础上,申请SQL语句句柄
if (SQL_SUCCEEDED(rcRecord))//判断连接是否成功
{
switch(DBSource)
{
case 1:
printf("-------课程插入---------\n");
printf("请输入课程名称:");
scanf("%s",Course_cTitle);
printf("请输入课程学分:");
scanf("%ld",&Course_iCredit);
sprintf(SplicSQL,"INSERT INTO Course(Title,Credit) VALUES ('%s',%ld)",Course_cTitle,Course_iCredit);
break;
case 2:
printf("-------学生插入---------\n");
printf("请输入学生姓名:");
scanf("%s",Student_cName);
printf("请输入学生班级:");
scanf("%s",Student_cClass);
printf("请输入学生年龄:");
scanf("%d",&Student_age);
sprintf(SplicSQL,"INSERT INTO Student(st_name,class,age) VALUES ('%s','%s',%d)",Student_cName,Student_cClass,Student_age);
break;
case 3:
ShowRecord(2,(SQLCHAR *)"SELECT * from Student");
printf("请选择选课学生编号:");
scanf("%d",&iSt_id);
sprintf(SplicSQL,"SELECT * from Student WHERE iNum=%d",iSt_id);
rowCount=ShowRecord(2,SplicSQL);
if(rowCount==1)
{
ShowRecord(1,(SQLCHAR *)"SELECT * from Course");
printf("正在为%5s同学选课:\n",Student_cName);
printf("请选择课程编号:");
scanf("%d",&iCo_id);
sprintf(SplicSQL,"INSERT INTO CourseSELECTion(Course_id,Student_id) VALUES (%d,%d)",iCo_id,iSt_id);
rcRecord=SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//重新申请语句句柄
}
else
{
system("cls");
printf("输入学生编号不正确!按任意键继续...\n");
system("pause");
return;
}
break;
}
rcRecord = SQLPrepare(hStmt, SplicSQL,SQL_NTS);
rcRecord=SQLExecute(hStmt);//直接执行SQL语句
if(SQL_SUCCEEDED(rcRecord))
{
printf("成功插入1条记录!\n");
}
else
{
printf("插入未成功!\n");
}
}
else
{
printf("不能连接%s.\n", szDSN);
return;
}
rcRecord = SQLFreeStmt(hStmt, SQL_DROP);//释放语句句柄
}
void EditRecord(int DBSource)
{
SQLCHAR SplicSQL[200];
int iSt_id, iCo_id,rowCount;
int scanf_isEnter(char *sFormat,...);
rcRecord=SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//获得环境句柄、连接句柄基础上,申请SQL语句句柄
if(SQL_SUCCEEDED(rcRecord))//判断连接是否成功
{
switch(DBSource)
{
case 1:
printf("--------课程更改----------\n");
printf("你正在修改记录编号为:%ld:\n",Course_iNum) ;
printf("请输入课程名称,当前值为%5s\n(可按回车保持原值)\n",Course_cTitle);
scanf_isEnter("%s",Course_cTitle);
printf("请输入课程学分,当前值为%5ld\n(可按回车保持原值)\n",Course_iCredit);
scanf_isEnter("%d",&Course_iCredit);
sprintf(SplicSQL,"UPDATE Course SET Title='%s',Credit=%ld WHERE iNum=%ld",Course_cTitle,Course_iCredit,Course_iNum);
break;
case 2:
printf("------学籍更改----------\n");
printf("你正在修改记录编号为:%ld:\n",Student_iNum) ;
printf("请输入姓名,当前值为%5s\n(可按回车保持原值)\n",Student_cName);
scanf_isEnter("%s",Student_cName);
printf("请输入班级,当前值为%5s\n(可按回车保持原值)\n",Student_cClass);
scanf_isEnter("%s",Student_cClass);
printf("请输入年龄,当前值为%5ld\n(可按回车保持原值)\n",Student_age);
scanf_isEnter("%d",&Student_age);
sprintf(SplicSQL,"UPDATE Student SET st_name='%s',class='%s',age=%ld WHERE iNum=%ld",Student_cName,Student_cClass,Student_age,Student_iNum);
break;
case 3:
printf("------选课更改----------\n");
ShowRecord(2,(SQLCHAR *)"SELECT * from Student");
printf("请选择学生编号,当前值为%d(可按回车保持原值):\n",CourseSelection_St_id);
scanf_isEnter("%d",&CourseSelection_St_id);
sprintf(SplicSQL,"SELECT * from Student WHERE iNum=%d",CourseSelection_St_id);
rowCount=ShowRecord(2,SplicSQL);
if(rowCount==1)
{
ShowRecord(1,(SQLCHAR *)"SELECT * from Course");
printf("正在为%5s同学选课:\n",Student_cName);
printf("请选择课程编号:");
scanf_isEnter("%d",&CourseSelection_Course_id);
sprintf(SplicSQL,"UPDATE CourseSelection SET Course_id=%ld,student_id=%ld WHERE id=%ld",CourseSelection_Course_id,CourseSelection_St_id,CourseSelection_id);
SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//重新申请语句句柄
}
else
{
system("cls");
printf("输入学生编号不正确!按任意键继续...\n");
system("pause");
return;
}
break;
}
rcRecord=SQLPrepare(hStmt,SplicSQL,SQL_NTS);//SQL_NTS,读取sql字符串时,以NULL为结束标志
rcRecord=SQLExecute(hStmt);//直接执行SQL语句
if(SQL_SUCCEEDED(rcRecord))
{
printf("成功修改!\n");
}
else
{
printf("修改未成功!\n");
}
}
rcRecord = SQLFreeStmt(hStmt, SQL_DROP);//释放语句句柄
}
void DeleteRecord(int DBSource)
{
SQLCHAR SplicSQL[200];
int iChoice=0;
rcRecord=SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//在环境句柄、连接句柄基础上,申请SQL语句句柄
if (SQL_SUCCEEDED(rcRecord))//判断连接是否成功
{
switch(DBSource)
{
case 1:
sprintf(SplicSQL,"DELETE FROM Course WHERE iNum =%ld",Course_iNum);
printf("准备删除第 %ld 号记录:请确认:\n 1.确认删除 0.放弃\n",Course_iNum);
break;
case 2:
sprintf(SplicSQL,"DELETE FROM Student WHERE iNum =%ld",Student_iNum);
printf("准备删除第 %ld 号记录:请确认:\n 1.确认删除 0.放弃\n",Student_iNum);
break;
case 3:
sprintf(SplicSQL,"DELETE FROM CourseSelection WHERE id =%ld",CourseSelection_id);
printf("准备删除第 %ld 号记录:请确认:\n 1.确认删除 0.放弃\n",CourseSelection_id);
break;
}
scanf("%d",&iChoice);
if(iChoice==1)
{
rcRecord = SQLPrepare(hStmt, SplicSQL,SQL_NTS);
rcRecord = SQLExecute(hStmt);//执行SQL语句
}
else
{
return;
}
if(SQL_SUCCEEDED(rcRecord))
{
printf("成功删除!\n");
}
else
{
printf("未能删除!\n");
}
}
rcRecord = SQLFreeStmt(hStmt, SQL_DROP);//释放语句句柄
}
int ShowRecord(int DBSource,SQLCHAR *cSELECTString)
{
int *colLeng=NULL,rowCount=0;
rcRecord = SQLAllocHandle(SQL_HANDLE_STMT,hDbc,&hStmt);//在环境句柄、连接句柄基础上,申请SQL语句句柄
rcRecord = SQLPrepare(hStmt, cSELECTString ,SQL_NTS);//对即将执行的query语句进行预处理
if (SQL_SUCCEEDED(rcRecord))//判断SQL执行预编译是否成功
{
switch(DBSource)
{
case 1:
/* 将变量与数据库值一一绑定 */
rcRecord = SQLBindCol(hStmt, 1, SQL_C_SSHORT, &Course_iNum, 0, 0);
rcRecord = SQLBindCol(hStmt, 2, SQL_C_CHAR, Course_cTitle, 128, colLeng);
rcRecord = SQLBindCol(hStmt, 3, SQL_C_SSHORT, &Course_iCredit, 0, 0);
rcRecord = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rcRecord))
{
rcRecord = SQLFetch(hStmt);
printf("|-------------------------------------------------------|\n");
printf("|\t编号\t|\t课程名称\t|\t学分\t|\n");
printf("|-------------------------------------------------------|\n");
while (SQL_SUCCEEDED(rcRecord))
{
printf("|\t%ld\t",Course_iNum);
printf("|%-20s\t",Course_cTitle);
printf("|\t%ld\t|",Course_iCredit);
printf("\n|-------------------------------------------------------|\n");
rcRecord = SQLFetch(hStmt);
rowCount++;
}
}
printf("一共找到 %d 条记录\n", rowCount);
break;
case 2:
rcRecord = SQLBindCol(hStmt, 1, SQL_C_SSHORT, &Student_iNum, 0, 0);
rcRecord = SQLBindCol(hStmt, 2, SQL_C_CHAR, Student_cName, 128,colLeng);
rcRecord = SQLBindCol(hStmt, 3, SQL_C_CHAR, Student_cClass, 128,colLeng);
rcRecord = SQLBindCol(hStmt, 4, SQL_C_SSHORT, &Student_age, 0, 0);
rcRecord = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rcRecord))
{
rcRecord = SQLFetch(hStmt);
printf("|---------------------------------------------------------------|\n");
printf("|\t编号\t|\t姓名\t|\t班级\t|\t年龄\t|\n");
printf("|---------------------------------------------------------------|\n");
while (SQL_SUCCEEDED(rcRecord))
{
printf("|\t%ld\t",Student_iNum);
printf("|%-10s\t",Student_cName);
printf("|%-10s\t",Student_cClass);
printf("|\t%ld\t|",Student_age);
printf("\n|---------------------------------------------------------------|\n");
rcRecord = SQLFetch(hStmt);
rowCount++;
}
}
printf("一共找到 %d 条记录\n", rowCount);
break;
case 3:
rcRecord = SQLBindCol(hStmt, 1, SQL_C_SSHORT, &CourseSelection_id, 0, 0);
rcRecord = SQLBindCol(hStmt, 2, SQL_C_CHAR,Student_cName, 128, colLeng);
rcRecord = SQLBindCol(hStmt, 3, SQL_C_CHAR,Course_cTitle, 128, colLeng);
rcRecord = SQLBindCol(hStmt, 4, SQL_C_CHAR,Student_cClass, 128, colLeng);
rcRecord = SQLBindCol(hStmt, 5, SQL_C_SSHORT, &Course_iCredit, 0, 0);
rcRecord = SQLBindCol(hStmt, 6, SQL_C_SSHORT, &CourseSelection_Course_id, 0, 0);
rcRecord = SQLBindCol(hStmt, 7, SQL_C_SSHORT, &CourseSelection_St_id, 0, 0);
rcRecord = SQLExecute(hStmt);
if (SQL_SUCCEEDED(rcRecord))
{
rcRecord = SQLFetch(hStmt);
printf("|---------------------------------------------------------------------------------------|\n");
printf("|\t编号\t|\t姓名\t|\t班级\t|\t课程名称\t|\t学分\t|\n");
printf("|---------------------------------------------------------------------------------------|\n");
while (SQL_SUCCEEDED(rcRecord))
{
printf("|\t%ld\t",CourseSelection_id);
printf("|%-10s\t",Student_cName);
printf("|%-10s\t",Student_cClass);
printf("|%-20s\t",Course_cTitle);
printf("|\t%ld\t|",Course_iCredit);
printf("\n|---------------------------------------------------------------------------------------|\n");
rcRecord = SQLFetch(hStmt);
rowCount++;
}
}
break;
}
}
else
{
printf("不能执行\n%s\n",cSELECTString);
}
rcRecord = SQLFreeStmt(hStmt, SQL_DROP);//释放语句句柄
return rowCount;
}
void SearchMenu(int iTopMenu)
{
int ShowRecord(int DbSource,SQLCHAR *cSELECTString);
void EditRecord(int DBSource);
void DeleteRecord(int DBSource);
SQLCHAR SplicSQL[400],cStr[100],cStr_DB[200],cStr_ColName_Str[20],cStr_ColName_Num[20];
int iChoice,iNumMin,iNumMax,rowCount;
while(1)
{
switch(iTopMenu)
{
case 1:
system("cls");
strcpy(cStr_DB,"Course");
strcpy(cStr_ColName_Str,"Title");
strcpy(cStr_ColName_Num,"Credit");
printf("t---------------------------------\t\n");
printf("|\t课程查找(修改)菜单\t|\n");
printf("---------------------------------\n");
printf("|\t1.按课程名称查找\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.按学分查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~2):\n");
fflush(stdin);//清空键盘缓存,保证scanf每次都能得到执行。
scanf("%d",&iChoice);
break;
case 2:
system("cls");
strcpy(cStr_DB,"Student");
strcpy(cStr_ColName_Str,"st_name");
strcpy(cStr_ColName_Num,"age");
printf("---------------------------------\t\n");
printf("|\t学生查找(修改)菜单\t|\n");
printf("---------------------------------\n");
printf("|\t1.按姓名查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.按年龄查找\t\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~2):\n");
fflush(stdin);//清空键盘缓存,保证scanf每次都能得到执行。
scanf("%d",&iChoice);
break;
case 3:
system("cls");
strcpy(cStr_DB,cEqualJoin);
strcpy(cStr_ColName_Str,"Student.st_name");
strcpy(cStr_ColName_Num,"Course.Credit");
printf("---------------------------------\t\n");
printf("|\t选课查找(修改)菜单\t|\n");
printf("---------------------------------\n");
printf("|\t1.按学生姓名查找\t|\n");
printf("|\t \t\t|\n");
printf("|\t2.按课程学分查找\t|\n");
printf("|\t \t\t|\n");
printf("|\t0.返回上一级\t\t|\n");
printf("---------------------------------\t\n");
printf("\n选择功能前面的数字进入功能(0~2):\n");
fflush(stdin);//清空键盘缓存,保证scanf每次都能得到执行。
scanf("%d",&iChoice);
break;
case 0:
return;
}
switch(iChoice)
{
case 1://字符类型查找
printf("请输入需要查找的字符串:");
scanf("%s",cStr);
if(iTopMenu!=3)
{
sprintf(SplicSQL,"SELECT * from %s WHERE %s='%s'",cStr_DB,cStr_ColName_Str,cStr);
}
else
{
sprintf(SplicSQL,"SELECT CourseSELECTion.id,Student.st_name,Course.Title,Student.class,Course.Credit,CourseSelection.Course_id,\
CourseSelection.Student_id FROM %s WHERE %s='%s'", cStr_DB,cStr_ColName_Str,cStr);
}
break;
case 2://数字类型查找
printf("请输入学分范围(格式:3~5 表示查询3至5分间的记录):");
scanf("%d~%d",&iNumMin,&iNumMax);
if(iTopMenu!=3)
{
sprintf(SplicSQL,"SELECT * from %s WHERE %s between %d and %d",cStr_DB,cStr_ColName_Num,iNumMin,iNumMax);
}
else
{
sprintf(SplicSQL,"SELECT CourseSELECTion.id,Student.st_name,Course.Title,Student.class,Course.Credit FROM %s WHERE %s between %d and %d",
cStr_DB,cStr_ColName_Num,iNumMin,iNumMax);
}
break;
case 0:
return;
}
rowCount=ShowRecord(iTopMenu,SplicSQL);
if(rowCount==1)
{
printf("需要对以上记录进行什么操作?\n1.修改 2.删除 0.退出 (0~2)\n请选择:");
scanf("%d",&iChoice);
switch (iChoice)
{
case 1:
EditRecord(iTopMenu);
system("pause");
break;
case 2:
DeleteRecord(iTopMenu);
system("pause");
break;
case 0:
return;
}
}
else
{
printf("无相关记录或记录大于1。不能进行修改、删除操作!\n");
system("pause");
}
}
}
void Init()
{
int iConnStrLength2Ptr;
char szConnStrOut[256];
rcRecord = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &hEnv);//申请环境句柄
rcRecord = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION,(SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);//设置环境属性参数 , 设置ODBC环境版本号为3.0
rcRecord = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc);//在获得环境句柄基础上,获得连接句柄
rcRecord = SQLDriverConnect(hDbc, NULL, szDSN,strlen((char *)szDSN), szConnStrOut,255, (SQLSMALLINT*)&iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);//开始对数据库进行连接
if (SQL_SUCCEEDED(rcRecord))//判断连接是否成功
{
printf("成功连接%s.\n", szDSN);
}
else
{
printf("数据库不能成功连接%s.\n", szDSN);
system("pause");
exit(0);
}
}
void Finish()
{
SQLDisconnect(hDbc);
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}
int scanf_isEnter(char *sFormat,...)
{
va_list arg;
va_start(arg,sFormat);//arg初始化
int i=0,*iPar;
char *cInput=NULL,*cPar=NULL;
cInput=(char *)malloc(128);
fflush(stdin);
while((cInput[i++]=getchar()) != '\n');
cInput[i]='\0'; //为字符串加上结尾
if(cInput[0]=='\n')//判断是否只有一个回车
{
return 1;
}
else if(*sFormat=='%')
{
sFormat++;
switch(*sFormat)
{
case 'd':
iPar=va_arg(arg,int *);
*iPar=atoi(cInput);
break;
case 's':
cInput[--i]='\0'; //将最后1个\n设置为结束(\0),否则写入数据库时,将把\n写入数据库
cPar=va_arg(arg,char *);
strcpy(cPar,cInput);
break;
}
}
return 0;
}
逐行解释