1. 程式人生 > >將Excel資料快速大批量匯入資料庫的程式碼

將Excel資料快速大批量匯入資料庫的程式碼

兩種途徑將資料從EXCEL中匯入到SQL SERVER。

一、        在程式中,用ADO.NET。程式碼 如下:

//連線串

string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" + [EXCEL檔案,含路徑] + ";";

OleDbConnection conn = new OleDbConnection(strConn);

conn.Open();

DataTable dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,new object[] {null, null, null, "TABLE"});

DataSet ds = new DataSet();

//一個EXCEL檔案可能有多個工作表,遍歷之

foreach( DataRow dr in dtSchema.Rows )

{

   string table = dr["TABLE_NAME"].ToString();

   string strExcel = "SELECT * FROM [" + table + "]";

   ds.Tables.Add(table);

   OleDbDataAdapter myCommand = new OleDbDataAdapter(strExcel,conn);

   myCommand.Fill(ds,table);

}

conn.Close();

這樣,讀取出來的資料就藏在DataSet裡了。

採用這種方式,

資料庫 所在機器不必裝有EXCEL。

二、        在查詢分析器裡,直接寫SQL語句:

如果是匯入資料到現有表,則採用

INSERT INTO 表 SELECT * FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0'

,'Excel 5.0;HDR=YES;DATABASE=c:\test.xls',sheet1$)

的形式

如果是匯入資料並新增表,則採用

SELECT * INTO 表 FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0'

,'Excel 5.0;HDR=YES;DATABASE=c:\test.xls',sheet1$)

的形式。

以上語句是將EXCEL檔案裡SHEET1工作表中所有的列都讀進來,如果只想導部分列,可以

INSERT INTO 表(a1,a2,a3) SELECT a1,a2,a3 FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0'

,'Excel 5.0;HDR=YES;DATABASE=c:\test.xls',sheet1$)

其實可以將OPENROWSET('MICROSOFT.JET.OLEDB.4.0'

,'Excel 5.0;HDR=YES;DATABASE=c:\test.xls',sheet1$)當成一個表,例如我就寫過這樣一個句子:

INSERT INTO eval_channel_employee(channel,employee_id)

SELECT CASE a.渠道 WHEN 'DIY' THEN 1 WHEN 'RDC' THEN 0 WHEN 'KCM' THEN 2 ELSE 3 END

,b.id FROM

OPENROWSET('MICROSOFT.JET.OLEDB.4.0'

,'Excel 5.0;HDR=YES;DATABASE=c:\temp\name.xls',sheet1$) AS a,pers_employee b

WHERE a.員工編碼=b.code

不管是哪種方式,哪種途徑,系統都會預設將第一行上的內容作為欄位名。

在做專案時,經常遇到要將Excel中的大量資料匯入到Access資料庫中,原來的做法是讀一條寫一條,若匯入上萬條的資料需要幾分仲時間,速度很慢。有沒有最快的方法呢?經本人研究、反覆的實驗,終於寫出了最快速的批量匯入大批量資料的方法,上萬條資料只需幾秒鐘就可全部匯入,夠快了吧。程式碼公佈出來與大家分享。

Sql程式碼
Set  conn = Server.CreateObject( "adodb.Connection" )   
connstr =  "Provider=Microsoft.Jet.OLEDB.4.0; Data source="  & Server.MapPath( "test.mdb" )   
conn. Open  connstr   
sql =  "insert into userinfo select userName,userAccount,userStatus from [userinfo$] in '"  & Server.MapPath( "hbwlUserInfo.xls" )   
&  "' 'Excel 8.0;' where userAccount is not null"   
conn. Execute  (sql)  

SQL Server

  大部分人都知道用oledb來讀取資料到dataset,但是讀取之後怎麼處理dataset就千奇百怪了。很多人通過迴圈來拼接sql,這樣做不但容易出錯而且效率低下,System.Data.SqlClient.SqlBulkCopy 對於新手來說還是比較陌生的,這個就是傳說中效率極高的bcp,6萬多資料從excel匯入到sql只需要4.5秒。 
using  System;
using  System.Data;
using  System.Windows.Forms;
using  System.Data.OleDb;
namespace  WindowsApplication2
{
      public   partial   class  Form1 : Form
      {
          public  Form1()
          {
             InitializeComponent();
         } 

          private   void  button1_Click( object  sender, EventArgs e)
          {
              // 
測試
,將excel中的sheet1匯入到sqlserver中 
              string  connString  =   " server=localhost;uid=sa;pwd=sqlgis;database=master " ;
             System.Windows.Forms.OpenFileDialog fd  =   new  OpenFileDialog();
              if  (fd.ShowDialog()  ==  DialogResult.OK)
              {
                 TransferData(fd.FileName,  " sheet1 " , connString);
             } 
         } 

          public   void  TransferData( string  excelFile,  string  sheetName,  string  connectionString)
          {
             DataSet ds  =   new  DataSet();
              try 
              {
                  // 獲取全部資料 
                  string  strConn  =   " Provider=Microsoft.Jet.OLEDB.4.0; "   +   " Data Source= "   +  excelFile  +   " ; "   +   " Extended Properties=Excel 8.0; " ;
                 OleDbConnection conn  =   new  OleDbConnection(strConn);
                 conn.Open();
                  string  strExcel  =   "" ;
                 OleDbDataAdapter myCommand  =   null ;
                 strExcel  =   string .Format( " select * from [{0}$] " , sheetName);
                 myCommand  =   new  OleDbDataAdapter(strExcel, strConn);
                 myCommand.Fill(ds, sheetName);

                  // 如果目標表不存在則建立 
                  string  strSql  =   string .Format( " if object_id('{0}') is null create table {0}( " , sheetName);
                  foreach  (System.Data.DataColumn c  in  ds.Tables[ 0 ].Columns)
                  {
                     strSql  +=   string .Format( " [{0}] varchar(255), " , c.ColumnName);
                 } 
                 strSql  =  strSql.Trim( & apos;, & apos;)  +   " ) " ;

                  using  (System.Data.SqlClient.SqlConnection sqlconn  =   new  System.Data.SqlClient.SqlConnection(connectionString))
                  {
                     sqlconn.Open();
                     System.Data.SqlClient.SqlCommand command  =  sqlconn.CreateCommand();
                     command.CommandText  =  strSql;
                     command.ExecuteNonQuery();
                     sqlconn.Close();
                 } 
                  // 用bcp匯入資料 
                  using  (System.Data.SqlClient.SqlBulkCopy bcp  =   new  System.Data.SqlClient.SqlBulkCopy(connectionString))
                  {
                     bcp.SqlRowsCopied  +=   new  System.Data.SqlClient.SqlRowsCopiedEventHandler(bcp_SqlRowsCopied);
                     bcp.BatchSize  =   100 ; // 每次傳輸的行數 
                     bcp.NotifyAfter  =   100 ; // 進度提示的行數 
                     bcp.DestinationTableName  =  sheetName; // 目標表 
                     bcp.WriteToServer(ds.Tables[ 0 ]);
                 } 
             } 
              catch  (Exception ex)
              {
                 System.Windows.Forms.MessageBox.Show(ex.Message);
             } 

         } 

          // 進度顯示 
          void  bcp_SqlRowsCopied( object  sender, System.Data.SqlClient.SqlRowsCopiedEventArgs e)
          {
              this .Text  =  e.RowsCopied.ToString();
              this .Update();
         } 


     } 
}  
  上面的TransferData基本可以直接使用,如果要考慮周全的話,可以用oledb來獲取excel的表結構,並且加入ColumnMappings來設定對照欄位,這樣效果就完全可以做到和sqlserver的dts相同的效果了。

記錄備忘

二快速匯入匯出
1.我們都知道當向db裡批量插入資料的時候我們會選擇SqlBulkCopy
if (dataTable!=null && dataTable.Rows.Count!=0)
            {
                sqlBulkCopy.WriteToServer(dataTable);
            } 
這個可以看 深山老林新發的一篇SQLServer中批量插入資料方式的效能對比下面是SqlBulkCopy的方法,這個方法有一個弊端就是當excel某一列即有文字,還有日期的時候,會出現null值,我在網上查了一些資料說連線字串加上;HDR=YES;IMEX=1'的時候會都當做字元處理,但是還是會出現一些bug,所以建議最好先把excel資料分析到datatable裡然後再用SqlBulkCopy倒入資料庫
1 // block copy to DB from Excel
2         //By xijun, 
3         //step 1 create an excel file  C:\Inetpub\wwwroot\test.xls , fill cell(1,1) with "Data",cell(1,2) with "name"
4         //step 2 create table named "Data" with 2 column ("data","name") in your DB
5         //there the code below:
6         DateTime t1 = DateTime.Now;
7         Response.Write("<br>start time:" + t1.ToString());
8         string ExcelFile = @"C:\\20090916_Hub_Report.xls";
9         string excelConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + ExcelFile + ";Extended Properties='Excel 8.0;HDR=YES;IMEX=1'";
10 
11         using (OleDbConnection excelConnection = new OleDbConnection(excelConnectionString))
12         {
13 
14             excelConnection.Open();
15             //Getting source data
16             //非空讀入資料
17             OleDbCommand command = new OleDbCommand("Select [Region],[CustomerPN],[RMA],[Date],[QTY],[Return/Pull] FROM [20090916_Hub_Report$]  ", excelConnection);
18             // Initialize SqlBulkCopy object
19 
20             using (OleDbDataReader dr = command.ExecuteReader())
21             {
22                 // Copy data to destination
23                 string sqlConnectionString = @"Data Source=MININT-G87PHNA\SQLEXPRESS;Initial Catalog=GDS_Service;Integrated Security=True";
24                 using (SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConnectionString))
25                 {
26                     bulkCopy.DestinationTableName = "GDS_Hub_data";
27                     //加入只加入一個列的話,那麼就會其他資料庫列都預設為空。
28                     bulkCopy.ColumnMappings.Add("Region", "region");
29                     bulkCopy.ColumnMappings.Add("CustomerPN", "customer_item_number");
30                     bulkCopy.ColumnMappings.Add("RMA", "Rma");
31                     bulkCopy.ColumnMappings.Add("Date", "date");
32                     bulkCopy.ColumnMappings.Add("QTY", "Qty_1");
33                     bulkCopy.ColumnMappings.Add("Return/Pull", "return_pull");
34                     //bcp.BatchSize = 100;//每次傳輸的行數
35                     //bcp.NotifyAfter = 100;//進度提示的行數
36                     bulkCopy.BatchSize = 100;
37                     bulkCopy.NotifyAfter = 100;
38                     bulkCopy.WriteToServer((IDataReader)dr);
39                     
40 
41                 }
42             }
43             //Closing connection
44             excelConnection.Close();
45         }
46 
47         DateTime t2 = DateTime.Now;
48         Response.Write("<br>End time:" + t2.ToString());
49         Response.Write("<br>use time:" + ((TimeSpan)(t2 - t1)).Milliseconds.ToString() + " Milliseconds");
50         Response.Write("<br>inser record count :3307");