学生成绩管理系统-MySQL版-Part7-导入数据
好的,我们迎来了Part7-导入数据.
为了方便,我在导入的时候就进行对总分、平均分,当数据库中的数据变化时,使用之前曾经定义过的数据表重算函数对数据表中的总分和平均分进行重新汇总计算。
在导入数据这个问题中,总共分为三种情况,一种是向现有的成绩单中追加数据,一种是创建新的成绩单后追加数据,再一个就是从SQL文件导入。
第一种情况我需要先获得添加记录的数据表,之后用INSERT语句即可追加。然而这个数据表的选择却是个难题。首先,为了标识数据表的归属,我给每一个属于学生成绩管理系统的数据表添加了一个前缀”scm_class_”,如果让用户直接输入数据表的名称显然是缺乏合理性的,所以我选择了按照索引值来选择数据表。我可以先“SHOW DATABASES LIKE ‘scm_class_%%’”获取所有的数据表名(每个数据表对应一个班级),然后按照MySQL给出的顺序从1开始编号,之后让用户选择编号,随后再次执行相同的语句后根据这个编号即可得出对应的数据表。
第二种情况下就稍微简单些,直接CREATE一个表格即可。然而,这个表格的表头却是个问题,因为科目数量是不确定的,同时也是需要用户输入的,这个数量会直接影响到后面的追加数据,所以在这一步一定要将字段数量计算出来。用户输入的每一个字段都是一门课,这门课的每一个人的成绩将会按照浮点数(float)进行存储。排除用户输入的n个字段,还有ID,学号,姓名,总分,平均分五个字段,故总字段数目是n+5个。
第三种情况就比较好说了,直接读取文件后按照;分隔执行SQL语句即可。在这里需要注意一件事情,就是对注释的处理。在SQL中有两种注释:
-- 注释内容 /* 注释内容 */
这里我只支持了单行的注释内容,在读取后执行SQL前判断一下处于0位和1位的两个字符是否满足注释即可。
在这两种情况中,追加数据因为是相同的功能,所以就直接用一个函数即可。
//引入头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <windows.h>
#include <mysql.h>
#include <conio.h>
//继承变量
extern MYSQL mysql;
extern MYSQL_RES *result;
extern MYSQL_ROW row;
extern MYSQL_FIELD *field;
//其实并没有什么卵用的全局变量
char Host[15];
char Port[8];
char Username[10];
char Password[20];
char DB[10];
//共有函数原型列表
int LoadSettings();
int Install(int mode);
int Connect_DB();
void ChangeColorScreen(const char* color);
void ChangeWindowSize(int Width,int Height);
void Pause(int mode);
void CS();
void Login();
void Exit();
void ChangeWindowSize(int Width,int Height);
void ChangeWindowTitle(const char* title);
void strrpl(char* pDstOut, char* pSrcIn, const char* pSrcRpl, const char* pDstRpl);
//特有函数原型列表
int Add_Score();
int Sum_ints(int number);
int Add_Score_FromKey();
int Add_Score_FromKey_Insert(int classnum,int first);
int Add_Score_FromKey_AddClass();
int Add_Score_Fromsql();
int Get_Score_Table(int Index,char *str);
//导入数据模块入口
int Add_Score() {
//此函数只是提供一个菜单和选择,所以只有一个变量
char select;
ChangeWindowTitle("导入数据");
ChangeWindowSize(40,16);
printf("╔═════════════════╗n");
printf("║ 学生成绩管理系统 ║n");
printf("║ 导入数据 ║n");
printf("╟─────────────────╢n");
printf("║请输入对应的标号进行不同的操作: ║n");
printf("║ [1] 键入数据 ║n");
printf("║ [2] 从*.sql文件导入 ║n");
printf("╟─────────────────╢n");
printf("║ [B] 返回主菜单 ║n");
printf("╟─────────────────╢n");
printf("║ JerrySoft Copyright. ║n");
printf("╚═════════════════╝n>");
fflush(stdin);
//获取用户输入
select=getch();
switch(select) {
case '1':
//指向键入数据
Add_Score_FromKey();
break;
case '2':
//指向SQL文件导入
Add_Score_Fromsql();
break;
case 'B':
case 'b':
//返回就直接return个0
return 0;
break;
}
Add_Score();
return 0;
}
//键入数据
int Add_Score_FromKey() {
char sql[100],temp[100],select[10];
int lines=0,item=1;
int i;
//用于储存班级数据
MYSQL_ROW Class[1000];
ChangeWindowTitle("导入数据");
//构建SQL语句
sprintf(sql,"Show Tables like 'scm_class_%%'");
mysql_query(&mysql,sql);
//获取结果
result=mysql_store_result(&mysql);
while((Class[lines]=mysql_fetch_row(result))) {
lines++;
}
ChangeWindowSize(40,lines+14);
Add_Score_FromKey_UI:
printf("╔═════════════════╗n");
printf("║ 学生成绩管理系统 ║n");
printf("║ 导入数据 ║n");
printf("╟─────────────────╢n");
printf("║请选择操作: ║n");
//列举表格
for(item=0; item<lines; item++) {
strrpl(temp,Class[item][0],"scm_class_","");
printf("║ [%d] 向%s中追加数据",item+1,temp);
//这里纯粹在补齐空格
for(i=strlen(temp)+Sum_ints(item+1)-1; i<16; i++) {
printf(" ");
}
printf("║n");
//计算有几个表格,方便验证用户输入
item++;
}
printf("╟─────────────────╢n");
printf("║ [C] 增加新的班级 ║n");
printf("║ [B] 返回上级菜单 ║n");
printf("╟─────────────────╢n");
printf("║ JerrySoft Copyright. ║n");
printf("╚═════════════════╝n>");
fflush(stdin);
//由于可能输入字母或者数字,选用字符串储存
//此处不用int的原因就是BC的ASCII值可能会和相应序号的表重合,导致误操作
gets(select);
//atoi为字符串转int的函数,位于string.h
if(atoi(select)>0&&atoi(select)<item) {
Add_Score_FromKey_Insert(atoi(select),0);
} else if(strcasecmp(select,"C")==0) {
//stecasecmp()是忽略大小写的字符串比对
Add_Score_FromKey_AddClass();
} else if(strcasecmp(select,"B")==0) {
return 0;
} else {
printf("请输入有效数据!");
Sleep(1000);
}
CS();
goto Add_Score_FromKey_UI;
return 0;
}
//键入数据_插入
//classnum是指表格的索引,first是用来标记递归调用次数的
//每调用一次只能添加一条,递归调用即可插入多条
int Add_Score_FromKey_Insert(int classnum,int first) {
char sql[100],title[20],incert[3000],TableName[100];
char textin[100];
int i;
double sum=0;
//根据序号获取表名
Get_Score_Table(classnum,TableName);
//构建sql语句(插入)
sprintf(incert,"INSERT INTO %s (",TableName);
//构建sql语句(查询条数)
sprintf(sql,"Select 1 From %s",TableName);
mysql_query(&mysql,sql);
result=mysql_store_result(&mysql);
sprintf(title,"追加数据-已有%d条",(int)mysql_num_rows(result));
ChangeWindowTitle(title);
//窗口的宽度,对于一个字段用一个tab,长8字符,最后加加一个才能不换行
ChangeWindowSize(mysql_num_fields(result)*8+1,mysql_num_rows(result)+5);
field=mysql_fetch_field(result);
for(i=1; i<mysql_num_fields(result); i++) {
field=mysql_fetch_field(result);
printf("%st",field->name);
if(i+1!=mysql_num_fields(result)) {
sprintf(incert,"%s%s,",incert,field->name);
} else {
sprintf(incert,"%s%s",incert,field->name);
}
}
printf("n");
sprintf(incert,"%s) VALUES (",incert);
//把已经键入的内容对其放好
while((row=mysql_fetch_row(result))) {
for(i=1; i<mysql_num_fields(result); i++) {
printf("%st",row[i]);
}
printf("n");
}
if(first==0) {
//只有第一次调用提示信息,之后就没有必要再提示了
printf("请按标题顺序输入成绩信息(除总分与平均分外,Tab键分隔)!并在第一个字段输入over返回上级菜单!");
Sleep(1000);
for(i=0; i<93; i++) {
Sleep(1);
printf("b b");
}
}
printf(">");
fflush(stdin);
//当超过两个后允许使用over
for(i=1; i<mysql_num_fields(result)-2; i++) {
scanf("%s",textin);
if(i>2) {
sum+=atof(textin);
sprintf(incert,"%s%.1lf,",incert,atof(textin));
} else {
sprintf(incert,"%s'%s',",incert,textin);
}
if(strcasecmp(textin,"over")==0) {
ChangeWindowTitle("导入插入成功!");
ChangeWindowSize(63,13);
ChangeColorScreen("1f");
CS();
printf("╔═════════════════════════════╗n");
printf("║ 学生成绩管理系统 ║n");
printf("║ 基于MySQL ║n");
printf("╟─────────────────────────────╢n");
printf("║ 导入成功! ║n");
printf("║ 本次共导入了%d个同学的%d门成绩.",first,mysql_num_fields(result)-5);
for(i=0; i<29-Sum_ints(first)-Sum_ints(mysql_num_fields(result)-5); i++) {
printf(" ");
}
printf("║n");
printf("║ 按任意键返回上级菜单. ║n");
printf("╟─────────────────────────────╢n");
printf("║ JerrySoft Copyright. ║n");
printf("╚═════════════════════════════╝n");
Pause(0);
return 0;
}
}
sprintf(incert,"%s%.2lf,%.2lf",incert,sum/(mysql_num_fields(result)-5),sum);
sprintf(incert,"%s)",incert);
if(mysql_query(&mysql,incert)) {
printf("插入失败:%sn",mysql_error(&mysql));
Sleep(4000);
} else {
printf("插入成功!n");
}
Sleep(100);
Add_Score_FromKey_Insert(classnum,first+1);
return 0;
}
//键入数据_插入新表
//添加班级
int Add_Score_FromKey_AddClass() {
char sql[1000]="show tables like 'scm_class_%'";
char temp[100],input[100];
int lines,item=1,i,fields;
item=1;
//获取所有班级
mysql_query(&mysql,sql);
result=mysql_store_result(&mysql);
lines=mysql_num_rows(result);
ChangeWindowSize(40,lines+14);
printf("╔═════════════════╗n");
printf("║ 学生成绩管理系统 ║n");
printf("║ 创建成绩单 ║n");
printf("╟─────────────────╢n");
printf("║ 当前已经存在的班级: ║n");
//列举所有班级给用户,防止重名出现
while((row=mysql_fetch_row(result))) {
strrpl(temp,row[0],"scm_class_","");
printf("║ [%d] %s",item,temp);
for(i=strlen(temp)+Sum_ints(item)-1; i<28; i++) {
printf(" ");
}
printf("║n");
item++;
}
printf("╟─────────────────╢n");
printf("║ 请不要使用重复的班级名称! ║n");
printf("║ [B] 返回上级菜单 ║n");
printf("╟─────────────────╢n");
printf("║ JerrySoft Copyright. ║n");
printf("╚═════════════════╝n");
Add_NewClass_Exist:
printf("请输入班级名称(XXX_XXX>");
fflush(stdin);
scanf("%s",input);
//判断返回
if(strcasecmp(input,"B")==0) {
return 0;
} else {
//检测当前输入班级是否已经存在
sprintf(sql,"SELECT * FROM scm_class_%s",input);
if(!mysql_query(&mysql,sql)) {
printf("%s已被占用,请重新输入!n",input);
goto Add_NewClass_Exist;
}
}
//构建SQL语句
sprintf(temp,"scm_class_%s",input);
sprintf(sql,"CREATE TABLE scm_class_%s (`ID` int(11) NOT NULL AUTO_INCREMENT,`学号` text NOT NULL,`姓名` text NOT NULL,",input);
ChangeWindowSize(60,10);
//获取字段名
printf("请输入科目(空格间隔,over结束,至少1个)>n");
fields=0;
memset(input,0,100);
while(fields==0||strcasecmp(input,"over")!=0) {
//依次读取并连入sql语句
scanf("%s",input);
if(strcasecmp(input,"over")!=0) {
fields++;
sprintf(sql,"%s`%s` double NOT NULL,",sql,input);
}
}
//最后不全语句
sprintf(sql,"%s`平均分` text NOT NULL,`总分` text NOT NULL,PRIMARY KEY(`ID`))",sql);
if(!mysql_query(&mysql,sql)) {
//输出提示,b会向前退格,将光标退至'5'处
printf("添加成功!5S后开始添加数据!bbbbbbbbbbbbbbbbb");
for(i=4; i>=0; i--) {
Sleep(1000);
printf("%db",i);
}
//推算新插入的表的索引
mysql_query(&mysql,"show tables like 'scm_class_%'");
result=mysql_store_result(&mysql);
i=0;
while((row=mysql_fetch_row(result))) {
i++;
if(strcmp(row[0],temp)==0) {
break;
}
}
//进入插入函数
Add_Score_FromKey_Insert(i,0);
} else {
printf("添加失败:%s",mysql_error(&mysql));
Pause(1);
}
return 0;
}
//从*.sql读取
int Add_Score_Fromsql() {
int haveerr=0,insert=0;
char sql[50000],Ssql[50000];
char FileLocal[1000];
FILE *fp,*errlog=NULL;
CS();
printf("请输入SQL文件路径或者直接将文件拖进来!>");
Add_Score_Fromsql_re:
gets(FileLocal);
if((fp=fopen(FileLocal,"r"))==NULL) {
printf("%s不可读或不存在!n",FileLocal);
goto Add_Score_Fromsql_re;
}
while(!feof(fp)) {
//依照每行sql语句最长50000字符读取
if(fgets(Ssql,50000,fp)) {
//排除空行
if(Ssql[0]!='n') {
//判断注释
if((Ssql[0]=='-'&&Ssql[1]=='-')||(Ssql[0]=='/'&&Ssql[1]=='*')) {
} else {
//在末尾抵消掉一个字符(n),查看是否为结尾
Ssql[strlen(Ssql)-1]=0;
sprintf(sql,"%s%s",sql,Ssql);
//如果是;,就开始执行,否则追加下一行
if(Ssql[strlen(Ssql)-1]==';') {
if(mysql_query(&mysql,sql)){
//导入出错时建立日志,并没有什么卵用
if(haveerr==0){
errlog=fopen("sqllog.log","w");
}
printf("导入出错:%sn",mysql_error(&mysql));
fprintf(errlog,"执行:'%s'时出错:n",sql);
fprintf(errlog,"t%sn",mysql_error(&mysql));
haveerr++;
}else{
insert++;
}
sql[0]=0;
}
}
}
} else {
break;
}
}
fclose(fp);
if(haveerr>0){
fclose(errlog);
printf("成功导入%d条,失败%d条!按任意键查看错误信息.",insert,haveerr);
}else{
CS();
printf("成功将%d条sql语句导入!n",insert);
Sleep(5000);
}
return 0;
}




评论
您需要 先登录 才可以回复.