记一次实验 —— VS2019 + Microsoft SQL Server 2019 + C++
首先,本实验基于你已会基本的数据库操作,SQL语句,准备写一个类似管理系统的小程序,本文会给出基本的C++操作数据库存储数据的方法。
如何安装SQL SERVER不再做介绍,网上应该有很多资料,安装完成后,关键在ODBC源的配置,参考博客https://blog.csdn.net/nanyouWSH/article/details/47681903,它完美的解决了这个问题。然后我们就可以在VS中连接该数据库了。
然后我们可以插入一些基础数据,当然为了后面的统计更具体,可以再适当新增一些合理的数据
很显然我们只需要在main里设置简单的选择菜单,并实现6个函数即可。别看代码1k行,实际上有大量的重复,思想其实是一样的,只需要弄清楚一个函数的实现流程,其余的就是基础C操作。一些关键的地方我已经给出注释,主要就是用户输入相关数据,我们拼接成合适的sql语句执行。功能4,5,6实现了获取sql返回信息的功能,可以在我们主程序中显示出来。所以,建议直接看4,5,6中的某一个,可以大致了解如何在VS主程序中输入信息然后执行sql语句,并回显结果。(或者把结果存储到一些主程序的变量中进行处理再输出)。
至于更加权威的参考示例,见微软官方给出的:
https://docs.microsoft.com/zh-cn/sql/connect/odbc/cpp-code-example-app-connect-access-sql-db?view=azuresqldb-current
代码如下,你可以选择性的看某些函数,只需要弄清楚实现流程即可
/*
每一个ODBC API函数都返回一个代码——返回码,指示函数执行的成功与否。
如果函数调用成功,返回码为SQL_SUCCESS或SQL_SUCCESS_WITH_INFO。
SQL_SUCCESS指示可通过诊断记录获取有关操作的详细信息,
SQL_SUCCESS_WITH_INFO指示应用程序执行结果带有警告信息,可通过诊断记录获取详细的信息。
如果函数调用失败,返回码为SQL_ERROR
一般地,编写ODBC程序主要有以下几个步骤:
1.分配ODBC环境 Open Database Connectivity
2.分配连接句柄
3.连接数据源
4.构造和执行SQL语句
5.取得执行结果
6.断开同数据源的连接
7.释放ODBC环境
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXBUFLEN 255
SQLLEN cbSno, cbCno, cbCname, cbCpno, cbSname, cbSsex, cbSdept, cbScholarship,cbSage,cbGrade,cbCcredit;
SQLCHAR szSno[10], szCno[5], szCname[45], szCpno[5], szSname[25], szSsex[3], szSdept[25], szScholarship[5];
SQLSMALLINT szSage, szGrade, szCcredit;
SQLINTEGER sCustID, cbName, cbCustID, cbPhone; //cb是指向绑定数据列使用的长度的指针.
//后面统计需要
struct Stu {
int grade;
int credit;
string sno;
Stu(int g, int c, string s) : grade(g), credit(c), sno(s) {}
};
SQLRETURN retcode;
SQLHENV henv = SQL_NULL_HENV; //环境句柄
SQLHDBC hdbc = SQL_NULL_HDBC; //连接句柄
SQLHSTMT hstmt = SQL_NULL_HSTMT; //语句句柄
//处理错误返回时需要
SQLCHAR SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER NativeError;
SQLSMALLINT i, MsgLen;
SQLRETURN rc;
SQLLEN numRecs = 0;
void showmenu()
{
system("cls");
printf("-----------------------欢迎----------------------------\n请输入需要执行的操作:\n");
printf("1.学生信息维护\n");
printf("2.课程信息维护\n");
printf("3.学生成绩维护\n");
printf("4.学生成绩统计\n");
printf("5.学生成绩排名\n");
printf("6.学生的基本信息和选课信息\n");
printf("-------------------------------------------------------\n\n");
}
///
/// 新生入学信息增加,学生信息修改
///
void Maintain_Student_Table()
{
string Sno, Sname, Ssex, Sage, Sdept, Scholarship;
while (true)
{
char op;
system("cls");
printf("请输入需要的操作 q退出:\n");
printf("1.新生入学信息增加 2.已有学生信息修改 3.学生信息删除\n");
rewind(stdin);
scanf_s("%c", &op, 1);
if (op == 'q' || op == 'Q')
{
printf("学生信息维护结束!\n");
system("pause");
break;
}
else if (op == '1')
{
printf("请依次输入学生信息Sno Sname Ssex Sage Sdept Scholarship:\n");
cin >> Sno>> Sname >> Ssex >> Sage >> Sdept >> Scholarship;
string sql = "insert into Student values('";
sql += Sno; sql += "','"; sql += Sname; sql += "','"; sql += Ssex; sql += "',";
sql += Sage; sql += ",'"; sql += Sdept; sql += "','"; sql += Scholarship; sql += "')";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else if (op == '2')
{
printf("请输入需要修改的学生的学号\n");
rewind(stdin);
cin >> Sno;
string sql = "delete from Student where Sno = '";
sql += Sno; sql += '\'';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败! 不存在该位同学!\n");
system("pause");
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else
{
printf("请依次输入修改后的学生信息Sno Sname Ssex Sage Sdept Scholarship:\n");
rewind(stdin);
cin >> Sno >> Sname >> Ssex >> Sage >> Sdept >> Scholarship;
string sql = "insert into Student values('";
sql += Sno; sql += "','"; sql += Sname; sql += "','"; sql += Ssex; sql += "',";
sql += Sage; sql += ",'"; sql += Sdept; sql += "','"; sql += Scholarship; sql += "')";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
}
else if (op == '3')
{
printf("请输入需要删除的学生的学号\n");
cin >> Sno;
string sql = "delete from Student where Sno = '";
sql += Sno; sql += '\'';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else
{
printf("输入错误!请重新输入!\n");
system("pause");
}
}
}
///
/// 课程信息维护(增加新课程,修改课程信息,删除没有选课的课程信息)
///
void Maintain_Course_Table()
{
string Cno, Cname, Cpno, Ccredit;
while (true)
{
char op;
system("cls");
printf("请输入需要的操作 q退出\n");
printf("1.增加新课程 2.修改课程信息 3.删除课程信息\n");
rewind(stdin);
scanf_s("%c", &op, 1);
if (op == 'q' || op == 'Q')
{
printf("课程信息维护结束!\n");
system("pause");
break;
}
else if (op == '1')
{
printf("请依次输入课程号Cno, 课程名称Cname, 先修课Cpno, 学分Ccredit:\n");
rewind(stdin);
cin >> Cno >> Cname >> Ccredit >> Cpno;
string sql = "insert into Course values('";
sql += Cno; sql += "','"; sql += Cname; sql += "','"; sql += Cpno; sql += "',"; sql += Ccredit; sql += ')';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else if (op == '2')
{
printf("请输入需要修改的课程号\n");
rewind(stdin);
cin >> Cno;
string sql = "delete from Course where Cno = '";
sql += Cno; sql += '\'';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败! 不存在该课程!\n");
system("pause");
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else
{
printf("请依次输入修改后的课程信息 课程号Cno, 课程名称Cname, 先修课Cpno, 学分Ccredit:\n");
rewind(stdin);
cin >> Cno >> Cname >> Ccredit >> Cpno;
string sql = "insert into Course values('";
sql += Cno; sql += "','"; sql += Cname; sql += "','"; sql += Cpno; sql += "',"; sql += Ccredit; sql += ')';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
}
else if (op == '3') //自动删除所有没有人选的课程
{
string sql = "delete from Course where Cno not in (select Cno from SC)";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else
{
printf("输入错误!请重新输入!\n");
system("pause");
}
}
}
///
/// 录入学生成绩,修改学生成绩
///
void Maintain_SC_Table()
{
string Sno, Cno, Grade;
while (true)
{
char op;
system("cls");
printf("请输入需要的操作 q退出\n");
printf("1.录入成绩 2.修改成绩\n");
rewind(stdin);
scanf_s("%c", &op, 1);
if (op == 'q' || op == 'Q')
{
printf("学生信息维护结束!\n");
system("pause");
break;
}
else if (op == '1')
{
printf("请依次输入学生学号Sno,考试课程号Cno, 成绩Grade:\n");
rewind(stdin);
cin >> Sno >> Cno >> Grade;
string sql = "insert into SC values('";
sql += Sno; sql += "','"; sql += Cno; sql += "',"; sql += Grade; sql += ')';
//cout << sql << endl;
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!\n");
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else if (op == '2')
{
printf("请依次输入需要修改的学生学号Sno,考试课程号Cno, 成绩Grade:\n");
rewind(stdin);
cin >> Sno >> Cno >> Grade;
string sql = "update SC set Grade = ";
sql += Grade; sql += " where Sno = '"; sql += Sno; sql += "' and Cno = '"; sql += Cno; sql += '\'';
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!\n");
system("pause");
}
else
{
printf("操作成功!");
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
else
{
printf("输入错误!请重新输入!\n");
system("pause");
}
}
}
bool cmp(const pair<string, double>& a, const pair<string, double>& b) {
return a.second > b.second;
}
///
/// 按系统计学生的平均成绩、最好成绩、最差成绩、优秀率、不及格人数
///
void Grade_Statistic_By_Sdept()
{
string sql;
int count = 0;
int totalnum[100], excellent[100], low[100]; //总人数,优秀人数,不及格人数
double excellent_rate[100];
SQLINTEGER num = 0; int i = 0; SQLSMALLINT x = 0;
//先返回各个系的考试总人数
i = 0;
sql = "select Sdept, count(*) from Student, SC where Student.Sno = SC.Sno group by Sdept";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
SQLBindCol(hstmt, 2, SQL_SMALLINT, &x, 0, &num);
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
//show_error();
printf("错误!\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
totalnum[i++] = x;
else
break;
}
}
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
count = i;
//再返回各个系的优秀人数
i = 0;
sql = "select Sdept, count(*) from Student, SC where SC.Sno = Student.Sno and Grade > 90 group by Sdept";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
SQLBindCol(hstmt, 2, SQL_SMALLINT, &x, 0, &num);
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
printf("错误!\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
excellent[i++] = x;
else
break;
}
}
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
//再返回各个系的不及格人数
i = 0;
sql = "select Sdept, count(*) from Student, SC where SC.Sno = Student.Sno and Grade < 60 group by Sdept";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
SQLBindCol(hstmt, 2, SQL_SMALLINT, &x, 0, &num);
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
printf("错误!\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
low[i++] = x;
else
break;
}
}
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
i = 0;
for (int i = 0; i < count; i++)
{
excellent_rate[i] = double(excellent[i]) / totalnum[i];
//low_rate[i] = double(low[i]) / totalnum[i];
//printf("%d%% %d%%\n", int(excellent_rate[i]*100), int(low_rate[i]*100));
}
SQLSMALLINT max_grade, avg_grade, min_grade;
SQLINTEGER max_l, avg_l, min_l;
//最后输出统计信息
sql = "select Sdept, Avg(Grade) avg_grade, MAX(Grade) max_grade, MIN(Grade) min_grade from Student, SC where SC.Sno = Student.Sno group by Sdept";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
//位数一定要比数据库里定义的至少多一位
SQLBindCol(hstmt, 1, SQL_C_CHAR, szSdept, 25, &cbSdept);
SQLBindCol(hstmt, 2, SQL_SMALLINT, &avg_grade, 0, &avg_l);
SQLBindCol(hstmt, 3, SQL_SMALLINT, &max_grade, 0, &max_l);
SQLBindCol(hstmt, 4, SQL_SMALLINT, &min_grade, 0, &min_l);
i = 0;
printf("%s %s %s %s %s %s\n","院系","平均分","最高分","最低分","优秀率","不及格人数");
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
printf("错误!\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
szSdept[5] = '\0';
printf("%s %d %d %d %d%% %d\n", szSdept, avg_grade, max_grade, min_grade, int(excellent_rate[i] * 100), low[i]);
i++;
}
else
break;
}
}
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
system("pause");
}
///
/// 按系对学生成绩进行排名,同时显示出学生、课程和成绩信息
///
void Grade_Rank_By_Sdept()
{
map<string, vector<Stu> > m;
string sql = "select Sdept,Student.Sno,Grade,Ccredit from Student, Course, SC where Student.Sno = SC.Sno and SC.Cno = Course.Cno";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
SQLBindCol(hstmt, 1, SQL_C_CHAR, szSdept, 25, &cbSdept);
SQLBindCol(hstmt, 2, SQL_C_CHAR, szSno, 10, &cbSno);
SQLBindCol(hstmt, 3, SQL_SMALLINT, &szGrade, 0, &cbGrade);
SQLBindCol(hstmt, 4, SQL_SMALLINT, &szCcredit, 0, &cbCcredit);
while (TRUE)
{
string sno,sdept;
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
//show_error();
printf("错误!\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
//zSdept[5] = '\0';
for (int i = 0; i < 3; i++)
sdept.push_back(szSdept[i]);
for (int i = 0; i < 10; i++)
sno.push_back(szSno[i]);
m[sdept].push_back(Stu(szGrade, szCcredit, sno));
}
else
{
break;
}
}
//按系统计
map<string, double> stu_grade; //加权成绩
for (auto it = m.begin(); it!= m.end(); it++)
{
system("cls");
stu_grade.clear();
int stu_num = it->second.size();
int sum = 0, i;
int class_count = 0; //一共多少学分
for (i = 0; i < stu_num; i++)
{
if (stu_grade.find(it->second[i].sno) == stu_grade.end() && i!=0) //出现了新同学,计算之前的,并重新初始化
{
stu_grade[it->second[i - 1].sno] = double(sum) / class_count;
sum = 0;
class_count = 0;
}
class_count += it->second[i].credit;
sum += it->second[i].credit * it->second[i].grade;
}
stu_grade[it->second[i-1].sno] = double(sum) / class_count; //最后一个同学单独计算
vector<pair<string, double>> vec(stu_grade.begin(), stu_grade.end());
//对线性的vector进行排序
sort(vec.begin(), vec.end(), cmp);
printf("开始展示:%s系学生排名\n", it->first.c_str());
for (int i = 0; i < vec.size(); ++i)
{
printf("排名 学号 加权成绩\n");
printf("Rank%d %s %.2f\n", i + 1, vec[i].first.c_str(), vec[i].second);
printf("成绩如下:\n");
string sql = "select Sname, Cname, Grade from Student, SC, Course where Student.Sno = '";
sql += vec[i].first;
sql += "' and SC.Sno = Student.Sno and Course.Cno = SC.Cno";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
SQLBindCol(hstmt, 1, SQL_C_CHAR, szSname, 25, &cbSname);
SQLBindCol(hstmt, 2, SQL_C_CHAR, szCname, 45, &cbCname);
SQLBindCol(hstmt, 3, SQL_SMALLINT, &szGrade, 0, &cbGrade);
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
//show_error();
printf("错误!\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
szSname[8] = '\0'; szCname[15] = '\0';
printf("%s %s %d\n",szSname, szCname, szGrade);
}
else
{
break;
}
}
printf("\n");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
printf("\n");
system("pause");
}
//system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
///
/// 输入学号,显示该学生的基本信息和选课信息
///
void Get_Stu_Info()
{
string sname, sdept, cname;
string Sno;
while (true)
{
system("cls");
printf("请输入需要查询的学生学号Sno 按q退出\n");
rewind(stdin);
cin >> Sno;
if (Sno == "q" || Sno == "Q")
{
printf("查询结束!\n");
system("pause");
break;
}
else
{
string sql = "select Student.Sno,Sname,Ssex,Sage,Sdept,Scholarship,SC.Cno,Cname,Grade from Student, Course, SC where Student.Sno = '";
sql += Sno; sql += "' and Student.Sno = SC.Sno and SC.Cno = Course.Cno";
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), sql.length());
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("操作失败!错误信息如下:\n");
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
cout << Msg << endl;
i++;
}
system("pause");
}
else
{
//位数一定要比数据库里定义的至少多一位
SQLBindCol(hstmt, 1, SQL_C_CHAR, szSno, 10, &cbSno);
SQLBindCol(hstmt, 2, SQL_C_CHAR, szSname, 25, &cbSname);
SQLBindCol(hstmt, 3, SQL_C_CHAR, szSsex, 3, &cbSsex);
SQLBindCol(hstmt, 4, SQL_SMALLINT, &szSage, 0, &cbSage);
SQLBindCol(hstmt, 5, SQL_C_CHAR, szSdept, 25, &cbSdept);
SQLBindCol(hstmt, 6, SQL_C_CHAR, szScholarship, 5, &cbScholarship);
SQLBindCol(hstmt, 7, SQL_C_CHAR, szCno, 5, &cbCno);
SQLBindCol(hstmt, 8, SQL_C_CHAR, szCname, 45, &cbCname);
SQLBindCol(hstmt, 9, SQL_SMALLINT, &szGrade, 0, &cbGrade);
printf("%s %s %3s %s %s %s %s %s %s\n", "Sno", "Sname", "Ssex", "Sage", "Sdept", "Scholarship", "Cno", "Cname", "Grade");
while (TRUE)
{
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
{
//show_error();
printf("错误!\n");
// Execute the SQL statement and return any errors or warnings.
SQLGetDiagField(SQL_HANDLE_STMT, hstmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// Get the status records.
i = 1;
while (i <= numRecs && (rc = SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA)
{
//DisplayError(SqlState, NativeError, Msg, MsgLen);
cout << SqlState << Msg << endl;
i++;
}
system("pause");
}
else if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
szSname[8] = '\0'; szSdept[5] = '\0'; szCname[15] = '\0';
printf("%-10s %-5s %-3s %d %-5s %-3s %-2s %-10s%d\n", szSno, szSname, szSsex, szSage, szSdept, szScholarship, szCno, szCname, szGrade);
}
else
{
break;
}
}
system("pause");
}
//释放语句句柄
retcode = SQLCloseCursor(hstmt);
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
}
}
int main()
{
SQLCHAR szDSN[15] = "mysql"; //数据源名称
SQLCHAR userID[6] = "sa";//数据库用户ID
SQLCHAR passWORD[29] = "";//用户密码
//1.连接数据源
//1.环境句柄
//对于任何ODBC应用程序来说,第一步的工作是装载驱动程序管理器,然后初始化ODBC环境,分配环境句柄。
//首先,程序中声明一个SQLHENV类型的变量,然后调用函数SQLAllocHandle,向其中传递分配的上述SQLHENV类型的变量地址和SQL_HANDLE_ENV选项。
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); //执行该调用语句后,驱动程序分配一个结构,该结构中存放环境信息,然后返回对应于该环境的环境句柄。
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
//2.连接句柄
//分配环境句柄后,在建立至数据源的连接之前,我们必须分配一个连接句柄,每一个到数据源的连接对应于一个连接句柄。
//首先,程序定义了一个SQLHDBC类型的变量,用于存放连接句柄,然后调用SQLAllocHandle函数分配句柄。
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLConnect(hdbc, szDSN, SQL_NTS, userID, SQL_NTS, passWORD, SQL_NTS);
/*
SQLConnect
该函数提供了最为直接的程序控制方式,我们只要提供数据源名称、用户ID和口令,就可以进行连接了。
函数格式:
SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,SQLCHAR ServerName,SQLSMALLINT NameLength1,SQLCHAR UserName,SQLSMALLINT NameLength2,SQLCHAR *Authentication,SQLSMALLINT NameLength3);
参数:
ConnectionHandle 连接句柄
ServerName 数据源名称
NameLength1 数据源名称长度
UserName 用户ID
NameLength2 用户ID长度
Authentication 用户口令
NameLength3 用户口令长度
返回值:
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, or SQL_INVALID_HANDLE.
成功返回SQL_SUCCESS,如果返回值为SQL_ERROR或SQL_SUCCESS_WITH_INFO,可以用函数SQLGetDiagRec获取相应SQLSTATE的值。
*/
//判断连接是否成功
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
printf("连接到数据库失败!\n");
}
else
{
char op;
while (true)
{
system("cls");
showmenu();
printf("请输入需要执行的操作,按q退出!\n");
rewind(stdin);
scanf_s("%c", &op, 1);
if (op == 'q' || op == 'Q')
{
printf("再见,欢迎下次使用!\n");
break;
}
else
{
switch (op)
{
case '1': Maintain_Student_Table(); break;
case '2': Maintain_Course_Table();; break;
case '3': Maintain_SC_Table(); break;
case '4': Grade_Statistic_By_Sdept(); break;
case '5': Grade_Rank_By_Sdept(); break;
case '6': Get_Stu_Info(); break;
default: printf("输入错误,请重新输入!\n"); break;
}
}
}
}
//3.断开数据库连接
/*
1. 断开数据库连接
2.释放连接句柄.
3.释放环境句柄(如果不再需要在这个环境中作更多连接)
*/
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return(0);
}
对于你自己而言,不同的数据库,只需要修改main函数里的数据源名称(ODBC源配置里设置的),数据库用户ID(一般就是sa)和用户密码(自己设置的sa密码),在你也建立好之前的三个表并插入数据后,该程序可以直接运行。