导师布置了一作业:
主要目的是学习数据库最基本的操作:创建用户、创建库表,和用程序访问数据库的相关技能(编码、编译等)
1,交易流水表(包含但不限于以下字段):交易日期、交易流水(用sequence实现)、交易机构、交易柜员、交易时间、交易渠道、交易金额、用户账号、用户号、交易状态(0-成功 1-失败 )、响应码、响应信息
2,功能:编写程序
A往交易流水表增加一条记录(信息来源是一个定长字符串,字符串包含交易要素:机构、柜员、账号、金额 等,程序解析这个字符串,然后插表)
B 生成统计文件,查询流水表,按机构、渠道等不同维度统计交易信息,生成类似下面的报表文件
交易日期 渠道 机构 成功笔数 成功金额 失败笔数 失败金额
20140101 柜面 10022011 100 30000 12 2000
20140101 柜面 10022012 100 30000 10 1000
20140101 网银 10022000 2000 450000 50 10000
20140102 柜面 10022011 100 30000 12 2000
20140102 柜面 10022012 100 30000 10 1000
20140102 网银 10022000 2000 450000 50 10000
首先是连接数据库,这个简单:
1 int ConnectDB() { 2 /*connect to database*/ 3 EXEC SQL BEGIN DECLARE SECTION; 4 char s_conn[1215]; 5 EXEC SQL END DECLARE SECTION; 6 7 memset( s_conn, 0x00, sizeof( s_conn )); 8 sprintf( s_conn, "finance/[email protected]" ); 9 EXEC SQL CONNECT :s_conn ; 10 if (0 != sqlca.sqlcode) { 11 printf("failed!:%s\n", sqlca.sqlerrm.sqlerrmc); 12 exit(0); 13 } 14 else { 15 printf("success!:%s\n", sqlca.sqlerrm.sqlerrmc); 16 } 17 18 return 0; 19 }
1 1 void insert(){ 2 2 EXEC SQL BEGIN DECLARE SECTION; 3 3 char buf[11][20]; 4 4 EXEC SQL END DECLARE SECTION; 5 5 6 6 static char input[400]="2014-05-17,10022002,yannic,2014-05-17,incase,1000,1003,3,1,1,success"; 7 7 int i=0; 8 8 9 9 char *p=strtok(input,","); 10 10 while(p!=NULL) 11 11 { 12 12 strcpy(buf[i++],p); 13 13 p=strtok(NULL,","); 14 14 } 15 15 for(i=0;i<11;i++) 16 16 { 17 17 printf("%d %s \n",i,buf[i]); 18 18 } 19 19 20 20 /*将string转换为number*/ 21 21 organization=atoi(buf[1]); 22 22 money=atoi(buf[5]); 23 23 user_account=atoi(buf[6]); 24 24 user_id=atoi(buf[7]); 25 25 state=atoi(buf[8]); 26 26 answer_id=atoi(buf[9]); 27 27 28 28 ConnectDB(); 29 29 EXEC SQL insert into business values(0,:buf[0],:organization,:buf[2],:buf[3],:buf[4],:money,:user_account,:user_id,:state,:answer_id,:buf[10]); 30 30 if (0 != sqlca.sqlcode) { 31 31 printf("[%s]\n",sqlca.sqlerrm.sqlerrmc ); 32 32 } 33 33 EXEC SQL COMMIT WORK RELEASE; /* 提交事务并断开数据库连接 */ 34 34 35 35 }
最后是查询了,要把结果生成报表输出到文件中,最麻烦的是要打印成Excel的样式,要很有耐心呢:
void selectDB() { FILE *fp; int i=0; ConnectDB(); /*定义游标*/ EXEC SQL DECLARE emp_cursor CURSOR FOR select t.trade_date,t.channel,t.ORGANIZATION, NVL(s.SUCCESS,0) as succeed,//查询成功的记录,如果没有就默认为0.使用函数NVL(字段,0),设置默认值为0. NVL(s.success_money,0) as succeed_money, (t.total-NVL(s.SUCCESS,0)) as FAIL, (t.total_money-NVL(s.success_money,0)) as FAIL_MONEY from VIEW_TOTAL t ,VIEW_SUCCESS s where s.trade_date(+)=t.trade_date and s.channel (+)=t.channel and s.organization (+)= t.organization;//通过左连接,只要查询到有记录就要输出来。 EXEC SQL OPEN emp_cursor; /* 以覆盖的方式写数据到文件*/ if((fp=fopen("excel.txt","wt+"))==NULL) { printf("Cannot open file strike any key exit!"); exit(1); } char column[][20]={{"TRADE_DATE"},{"CHANNEL"},{"ORGANZATION"},{"SUCCEED"},{"SUCCEED_MONEY"},{"FAIL"},{"FAIL_MONEY"}}; fputs(" TRADE INFORMATION\n",fp); fputs(xline,fp); for(i=0;i<7;i++) { fprintf(fp,"|%-21s",column[i]); } fputs("|\n",fp); fputs(xline,fp);//xline 是我宏定义的一行横线,方便后面使用。 for(;;){ EXEC SQL WHENEVER NOT FOUND DO break; EXEC SQL FETCH emp_cursor INTO :trade_date,:channel,:organization,:succeed,:succeed_money,:fail,:fail_money; fprintf(fp,"|%-21s|%-21s|%-21d|%-21d|%-21d|%-21d|%-21d|\n",trade_date,channel,organization,succeed,succeed_money,fail,fail_money);//控制每一列数据占位长度,用格式控制符.-代表左对齐,21代表每列占位21个字符。 fputs(xline,fp); } EXEC SQL CLOSE emp_cursor; EXEC SQL COMMIT WORK RELEASE; fclose(fp); }
最后打印效果:
最后导师提出来了两个问题一个是char数组定义长度太小,真正项目中可能会来很长一字符串那就造成内存溢出。还有一个就是文件打开那儿我直接失败就退出,老师建议不要这样,实际项目中流程退出再重新建流程要初始化等会浪费资源,所以异常时关闭游标等资源好了,不释放这些资源的话时间长了会造成内存泄漏。