將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裡了。
採用這種方式,
二、 在查詢分析器裡,直接寫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)
{
//
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");