admin 管理员组

文章数量: 887021


2024年1月22日发(作者:怎样查看jdk版本)

电脑编程技巧与维护 用Web将数据从Excel导入到SQL Server中遇到的问题 及其解决方法 田亚灵 (西双版纳职业技术学院,西双版纳摘666100) 要:分析Web方式下将数据从Excel导入到Microsoft SQL Server数据库遇到的问题,并提出了相应的解决方 法,给出了实现数据校验和导入功能的C#程序。 关键词:导入数据;Excel;SQL Server;问题;解决方法 e Problem,and Solutions about Import Data from Excel to Based on 舢 (Xishuangbanna Vocational and Technical Institute,Xishuangbanna 666100) Abstract:This paper analyzes the problems about impotr data from Excel to SQL Server based on Web,and put forward the corresponding solutions.At last.it provides a C#program with function of the data validation and impoa. Key words:import data;Excel;SQL Server;problems;solutions l概述 数据的完整性和准确性是进一步利用数据的前提。在开 发B/S应用程序时,为保证采集的数据完整和准确,通常采用 表单形式让用户填写,校验后添加到数据库中。如果采集的 题及其解决方法。 数据量很大时,通过表单形式提交数据已不能满足需要,程 序设计员不得不考虑增加批量数据导人的功能。Microsotf Ex— cel是大家都非常熟悉的办公应用软件,在现代办公活动中应 用极为广泛和频繁,像人事档案、学生学籍档案、学生成绩 等往往是通过Excel进行采集的。因此,应用程序一般会提供 将Excel的数据导入到数据库中的功能。 为确保导人成功和导入的数据完整、准确,一般都会对 Excel中数据的填写格式、必填栏目进行规定和说明,并让用 户下载预先编制的Excel模板(模板中含校验宏代码),让用 图1新生档案 表1 Stu_temp表结构 列名 Stu ID Stu name 、 Genger Brith Nation IDcard CandidateID Score Major Academicstmctme Class name Entrydate 户按规定和说明采集数据,在客户端完成校验,最后再导人。 这种方法的优点是:不占服务器资源,可以逐条核对Excel中 的数据类型和数据格式是否符合要求;可以在Excel模板中对 录入的数据采用选择项让用户选择,以确保用户录入的数据 格式是所需的格式。缺点是:当数据库结构发生变化时,Ex— cel模板连同校验宏代码也得及时同步修改,并且编写校验宏 .数据类型 Char Char Char Char Char Char Char Cbar Chat Char Char Char 长度 50 50 50 50 50 50 50 50 50 50 50 50 允许空 主键 、/ 、/ 、/ 、/ 、/ 、/ 、/ 、/ 、/ 1v/ 、/ 代码的工作量亦不可小觑。另外在导人过程中还得再次对Ex— cel中的数据进行校验。本文讨论的是略去编写客户端Excel 2创建客户端上传导入Excel文件的页面 启动Visual Studio 2010,点击[New Web Site],选择Vi— sual C#,ASP.NET Web Site,确定。加入新项importExee1.as— 模板校验宏代码工作,让用户按规定和说明采集数据,在B/S 程序中一次完成校验与导入的方法。为便于说明问题及进行 讨论,以“新生档案.xls”为导入的Excel文件,如图1所示。 以Microsoft SQL Server下student数据库中的Stu_temp表表结 px。在页面中插入1行2列的table,第1列的align属性设置 为right,布置Labell控件,第2列的align属性设置为left, 布置FileUploadl和Buttonl控件;再插入3行l列的table, 各行的列align属性设置为center,在每行上添加Label2、La— bel3和TextBox1控件。各控件的属性设置见表2。点击『New 构详见表1为导入目的,说明编写导人程序时具体遇到的问 本文收稿日期:2010—03—06 ——40—— 

DATABASE AND INFORMAT10N MANAGEMENT Folder]添加upload—temp目录。 表2控件属性 控件ID Text Width Height TextMode onclick Label1 导入Excel Fi|eUpload1 300px Buttonl 确定 Button l Click Label2 提示信息 Label3 T xtBOX1 400px 300px MultiLine 其中FileUpload1和Button1控件用于实现浏览和上传客 户端的Excel文件。Label3控件用于显示导入成功与失败的信 息。TextBox1控件用于显示Excel校验出错的信息。 打开Web.config配置文件,加入下列语句: <appSettings> <add key=”Connlink” value=”server=r loca1);database=students;uid=sa;pwd= llll”/> </appSettings> 3 代码文件 为能够上传、连接、读取Excel文件,引入System.IO、 System.Data、System.Data.OleDb命名空间;为能够连接、操作 SQL Server数据库,引入System.Data.SqlClien命名空间。打开 importExee1.aspx.CS,在namespace段中加入下列语句: using System.IO; using System.Data; using System.Data.OleDb; using System.Data.SqlClient; using System.Configuration; 在public partial class importExcel:System.Web.UI.Page段 中加入: string strsqlconn= _System.Configuration.ConfigurationManager.AppSettings[” Connlink”】.ToString 0; 在importExce1.aspx页面装入过程中将Label3、TextBox1 控件的可见属性设置为假: protected void Page_Load(object sender,EventArgs e) f Label3.Visible=false; TextBox1.Visible=false; ) 4遇到问题及解决方法 上传、导人和校验都将在Button 1控件被点击的事件处理 过程中完成(下列所有C#代码段按问题顺序可置于Button1 事件处理过程中)。实现过程如下:首先浏览Excel文件,上 传到服务器端upload—temp临时目录,然后对上传文件进行校 验,如果通过校验,导人数据库中;如果未通过校验,在 TextBoxl控件中显示校验出错信息。 问题1:在Button1事件处理过程中,如果用户未点击 [浏览]按钮就点击【确定],或者点击了【浏览】,但不是指定 的Excel文件,怎样校验? 数据库与信息管理 分析:误操作是不可避免的,针对上述误操作,程序应 当进行判断并给出相应提示。 解决办法:用FileUpload1控件的HasFile属性值真假判断 用户是否浏览了文件。用System.IO.Path类的GetExtension fFileUpload1.FileName)方法读取上传文件的扩展名,判断上传 的是否是Excel文件。用PostedFile对象的SaveAs 0方法将 上传文件保存在服务器的upload—temp临时目录中。 C#代码段如下: if fFileUpload1.HasFile==false) { Label3.Visible=true; Label3.Text:”请选择Excel文件!”: return; } string extname= Path.GetExtension(FileUpload1.FileName).ToString(). ToLower 0; string purl=…’: if(ext_name!=”.xls”)//N断扩展名 { Label3.Visible=true; Label3.Text=”你选择的文件不是Excel文件!”: return; ) else { stirng filename=FileUpload1.FileName;//获取上传文件名 stirng file_fullname=Server.MapPath C-\\upload temp\\” 、+ iflename; FileUpload1.PostedFile.SaveAs(ifle_fullname);,/保存文件 purl=file_fullname;//含路径全名 } 问题2:如图1所示,导入的Excel工作表名称不是指定 的sheet1、sheet2,而是其他名称,如何读取Excel工作表的 名称? 分析:将Excel作为Ole Db数据源,创建OleDbConnec— tion对象实例excel_Conn,用OleDbConnection对象的 GetO1eDbSchemaTable()方法读取Excel结构信息到DataT— able对象实例dt中,DataTable对象的lOW n TABLE—NAME”】 值即是Excel工作表的名称。 解决办法:采用foreach循环,可将工作表的名称读取存 放在excelSheets【】数组中。 C}}代码段如下: string str_Conn= ”Provider=Microsoft.Jet.OLEDB.4.0;Data Source=’’+purl +”;Extended Properties= excel 8.0;IMEX=I;HDR=Yes ’: OleDbConnection excelConn= new OleDbConnection(str_Conn); excel_Conn.Open(); DataTable dt= excelConn.GetOleDbSchemaTable(OleDbSchemaGuid.Ta一 ——41—— 

电脑编程技巧与维护 bles,nul1); String[】excelSheets=new Stirng[dt.Rows.Count]; int k=0: foreach(DataRow row in dt.Rows) { excelSheets[k】=row[”TABLE_NAME”】.ToString(); k++: ) 其中:IMEX=I表示将强制混合数据转换为文本; HDR=Yes表示Excel工作表的第1行为字段名; excelSheets【o]的值即为第1张工作表的名称,ex— celSheets…1的值即为第2张工作表的名称,依次类推。 问题3:当用户提交的Excel工作表列数多于或少于数据 库中表的指定必填项列数时,或者用户提交的Excel工作表是 空表,如何检查?如何检查Excel工作表中数据为空的单元 格?如果Excel工作表的表头名称被用户修改,不是指定的名 称,如何校验? 分析:Excel工作表的名称已存放在excelSheets Il数组 中,并且已创建了OleDbConnection对象实例exeel Conn,因 此可用“SELECT FROM【',+excelSheets【】+“】”查询 语句将指定工作表的数据读取到DataSet对象实例中,从而可 获取Excel工作表列数和行数。 采用SqlCommand对象访问Students数据库,创建Sql— DataReader对象实例sql—rd读取Stu—temp表的数据,用 sql_rd.FieldCount可获得Stu—temp表的列数。 解决办法:创建OleDbDataAdapter对象实例ole_adpt,读 取Excel工作表(本例为第1张工作表excelSheets【O])数据 存放在DataSet对象实例ds中,ds.Tables【0】.Columns.Count 的值即是Excel工作表的列数,ds.Tables【0].Rows.Count的值 即是Excel工作表的行数。 用if语句可判断Excel工作表的列数多于还是少于数据库 中表的指定必填项列数。 如果ds.Tables[O】.Rows.Count值为零,说明用户提交的 Excel工作表是空表。 用f0r循环嵌套检查Excel工作表中数据为空的单元格。 下列c#代码中还用数组xls_listname口、field_name f1分 别存放Excel工作表的表头列名和Stu—temp表的列名。这样做 的好处是在程序中可间接引用Excel工作表的表头名称和 Stu_temp表的列名,使导入程序与数据结构无关,即使修改 Stu_temp表的结构,只要Excel工作表与Stu_temp表的列顺序 相同,无须修改导人程序也可实现校验和导人,程序更具有 通用性。 C}}代码段如下: string str_xls=”SELECT FROM[”+excelSheets【0】 +”】._; OleDbDataAdapter oleadpt= new OleDbDataAdapter(str_xls,excel_Conn); DataSet ds=new DataSet 0; ole_adpt.Fill(ds,” 【”+excelSheets[0】+”l"); int xls _fieldnum dsTabl= . es 0 Col【】. umnsCount;. 一42一 ,/电子表的列数 int xls_rows=ds.Tables[0】.Rows.Count;//电子表的行数 excel_Conn.Close(); SqlConnection conn=new SqlConnection(strsql_conn); conn.Open 0; string str_select=”SELECT FROM Sm_mmp”: SqlCommand cmd=new SqlCommand(str_select,conn); SqlDataReader sql_rd=cmd.ExecuteReader 0; int sql_fieldnum=sql_rd.FieldCount; ,/数据库中Stu_temp表的列数 string[】field_name=new string[sql_fieldnum】; string[】xls—listname=new string【xls_fieldnum】; /,i卖取Excel工作表的表头列名赋值给xls_listname【】数 f|组 for(int i=O;i<xls_fieldnum一1;i++) { xls_listname【i]= ds.Tables【0】.Columns【i].ColumnName.ToString(); } ∥读取SqlDataReader的列名赋值给field_name【】数组 ofr(int i=0;i<sql_fieldnum—l;i++) { ifeldname[i】=sql_rd.GetName(i).ToString().Trim 0; ) sql_rd.Close 0; if(sql_ifeldnum<xls_fieldnum) { Label3.Visible=flue; Label3.Text=”电子表的列数多于数据库中表的列数,请 检查。导人终止!..; File.Delete(pur1); retum; } else if(sql_fieldnum>xls_fieldnum) { Label3.Visible=true; Label3.Text=”电子表的列数少于数据库中表的列数,请 检查。导入终止!”; File.Delete(pur1); return; ) if(xls_rows==01 { Label3.Visible=true; Label3.Text=”电子表中无数据。导人终止!”; File.Delete(pur1); return; } string info= : Label3.Text=”正在对电子表进行校验,请稍后・・oi!; for(int i=0;i<xls_rows;i++) { ofr(int J=0;j<xls_fieldnum—l;j++) { if(ds.Tables【0】.Rows[i】啪.ToString().Trim 0=: 

DATABASE AND INF0RMATION MANAGEMENT ””) 数据库与信息管理 string【】str_temp3=new string[xls_rows】; for(int i=0;i<xls_rows;i++) { info+=”电子表第”+(i+2)+”行, [”+xls_list— nameⅢ十”】列为空,请检查!kn”; } } } { str_templ【i】=field_name【0】: temp2 fi】=ds.Tables[o】.Rows[i】 [0].ToString temp3【i]=field_name【1】+”= ’+ds.Tables[0]. str_0.Trim 0; str_其中语句File.Delete(pur1)的作用是删除上传的Excel文 件。对于用f0r循环嵌套检查出的Excel工作表中数据为空的 行、列信息,保存在info字符串中,在随后问题4的代码中 用TextBox1控件的Text属性进行显示。 问题4:当用户反复提交Excel文件时,如何对待? 分析:用户反复提交Excel文件,可能是用户修改了工作 表中的数据,也可能增加了工作表中的记录,还可能工作表 中的数据根本没有变化。 解决办法:为了防止导人的数据重复,目的表中一般均 有用于唯一标识的字段名。假定本例Stu_temp表的唯一字段 是Stu—ID,对应Excel工作表中的学号。因此,对于用户反复 提交的Excel文件,在完成前面的检查、校验后,可以这样处 理:当Excel工作表中的学号与Stu—temp表的学号相同时,做 更新处理,更新记数器update—count加1;当Stu—temp表中无 Excel工作表中的学号时,做插入处理,插入记数器in— sert_count加1。操作完毕显示更新、插入和出错条数的提示 信息。 用字符串数组str_temp1[]存储Stu_temp表的字段名子 串,用字符串数组str_temp2 f1存储Excel工作表各行的子串, 用字符串数组str_temp3[】存储“Stu_temp表字段名=Excel工 作表列值”的子串,以便于构成insert语句和update语句。在 表示Where子句的列名和生成insert、update子串时,没有直 接引用Stu temp表的列名,而是用数组field—name【]间接引 用,使得程序与数据结构无关。 C#代码段如下: if(info!=…’) { Label3.Visible=true; TextBox1.Visible=true: Label3.Text=”导人终止!”; TextBox1.Text=info; File.Delete(pur1); return; l else { TextBox1.Visible=false; Label3.Visible=true; TextBox1.Visible=false; int wrong_count=O;,/错误记数器置0 int insertcount=0;,/插入记数器置0 int update_count=0;,/更新记数器置0 string[]str_templ=new string【xls_rows]; string【1 str_temp2=new string【xls_rows]; Rows【ij[1].ToString 0.Trim 0+…”; ofr(intj=l;J<sql—fieldnum一1;j++) { ,/生成insert语句字段名子串和values子串 strtempl【i]+=”,”+field_name U】; str temp2【i】+=”,”+…”+ds.Tables【0】.Rows【i] [j】.ToString().Trim 0+…”; } ofr(int J=2;j<sql_fieldnum—l;j++) { ,/生成update语句的“字段名=值”子串 str_temp3【i】+=”,”+field_name[j】+”= ’+ds.Ta— bles【0】.Rows【i】D】.ToString 0.Trim 0+…”; } string sqlcheck=”select count( )from Stu_temp where ”+field_name[0】+”= ’+ds.Tables【O】.Rows【iJ 【0】.ToString 0.Trim 0+…”; SqlCommand sqlcmd=new SqlCommand(sqlcheck, conn); int count=(int)sqlcmd.ExecuteScalar 0; if fcount==01 //Stu—temp表中第1列与电子表第1列不重复 { SqlCommand insertcmd=new SqlCommand f”insert Stu—temp(”+str_templ[i】+”) values(”+ str_temp2【i】+”)”,conn); insertcmd.ExecuteNonQuery(); insert_count++; J else if(count>01 { SqlCommand updatecmd=new SqlCommand f”update Stutemp set” +str_temp3[i】 +” where” + ifeld_name【0】+”: ‘+ds.Tables[0】.Rows[ii 】【0】. ToString 0.Trim 0+…”,conn); updatecmd.ExecuteNonQuery 0; updatecount++; _) else { wrong_count++; } } Label3.Text=insert_count+”条数据已导人fI1+up— datecount+”条数据已更新!”+wrong_count+”条数 据有错Ifl: File.Delete(pur1); ) conn・Close 0; (下转到69页) 一43— 

NETW0RK AND C0MMUNICAT10N 系统从用户登录开始,登录时需要验证用户合法性,系 String query ”select from test”: 网络与通信 统对用户名,密码进行检验。检验过程对SDH数据库中的表 user进行查询,与用户输入的用户名,密码进行匹配,匹配成 功后进入用户操作界面。用户操作界面中可选的操作流程有 更换用户、关闭系统、设置、修改密码,如图1所示。其中 修改密码需要连接SDH数据库中表user,对表user中的密码 项进行数据更新。主体操作是启用部分,启用部分先发送连 Class.forName(”sunOdbc.odbc.JdbcOdbcDriver”); conn=DriverManager.getConnection(url,username,pass— word); Statement sta=conn.createStatement 0: result=sta.executeQuery(query); rsmd=result.getMetaData 0: for(int i=l;i<=rsmd.getColumnCount();++i) { columnHeads.addElement(rsmd.getColunmName(i)); 接请求给服务器,请求连接,等待服务器回答,若收到“拒 绝”则与服务器断开连接,收到“欢迎”则与服务器进行网 } 络通信。接着要求服务器发送告警信息,等待接收告警,将 接受到的数据进行存库处理,存为SDH数据库表rec。其后系 统会查询数据库,对数据库表rec的数据按告警格式进行解 析,解析后存入SDH数据库表recdb中,并统计其中各种告 警的总数,最后显示在界面的查询板块和统计板块。系统连 接服务器时,会定时发送一个心跳包与服务器进行确认连接, 已确保连接正常。 ■■●I while(result.next()) { rows.addElement(getrows(result,rsmd)); System.out.print(rows); NORTH); } jPanel2.add(table.getTableHeader() ,BorderLayout. jPanel2.add(atble); c.add(jPanel2, new XYConstraints(2,569,999,87)); c.setVisible(true); } catch(ClassNotFoundException e) { System.err.print(”加载JDBC/ODBC驱动失败∽; } catch(SQLException sqlex) { 妻 品l磊 l品 嚣}曼 ==}品I 浇 糍赫 ■ 麓 System.e/T.print(”无法连接数据库 : } 5 结语 研究并实现了SHD管理系统接口,对SDH的传输网综合 管理系统进行深层剖析,希望对类似系统的开发有很好地借 鉴作用。 参考文献 【1】向阳,季树滨,陈明贵.SDH网络管理系统维护基础【M】. 西安:电子科技大学出版社,2004. __蚺朋 jT_¨  -t{ {Itsl ̄- l_呐r -__  {} [2】DOUGLAS E.COMER.INTERNETWORKING WITH TCP3P, : T喇-R^ ■I●●■E■●…:。 扣t‘■柚 ■ 0 —----—■目■… 一——一 lt…’■■■&lⅡ■■■日一: §  拜・- 一 VOL 1(5TH EDITION) 【M】.PRENTICE HALL,2006. 图1程序界面 作者简介 主要报警代码如下: Connection conn; 麻铭武,男(1967一),本科,中级,河南油田信息中心,研 究方向:信息管理及数据安全。 乔银梅,女(1969一),中专,河南油田信息中心,研究方向: 信息管理及数据安全。 Stirng url=”jdbc:odbc:SDH”; ResultSet result; ResultSetMetaData rsmd; (上接第43页) } 参考文献 [1】Jason Bell Mike Clark,等.赵彦敏译.ASP.NET程序员参 考手册fK1.清华大学出版社,2002. 4 结语 为保证程序获取的数据完整、准确,除了对用户采集的数 据进行必要的规定和说明外,要充分考虑用户的操作,分析各 【2】Microsoft Corporation..NET Framework类库[EB/OL].MSDN 技术资源库.http://msdn.microsotf.com/zh—cn/library/ms2293 35.aspx. 种操作的原因及其影响,找出各种操作结果的检查方法,在程 序中给出应对各种操作的措施,做好校验工作,及时提示以帮 助用户正确完成操作。如本例中的误操作和重复提交Excel文 件的操作。另外,尽可能采用间接引用,使开发出的程序更具 通用性。本例由于采用了间接引用,程序与数据结构无关,即 使修改了Stu_temp表的结构,只要Excel工作表与Stu temp表 的列顺序相同,无须修改程序都可实现校验与导入。 作者简介 田亚灵,男(1963一),讲师,研究方向:信息处理、软件工 程、网络应用。 一69— 


本文标签: 数据 用户 工作 进行 校验