在平時的項目中,將數據導出到Excel的需求是很常見的,在此對一些常見的方法做以總結,並提供一種大數據量導出的實現。
- OLEDB
使用OLEDB可以很方便導出Excel,思路很簡單,處理時將Excel當做Access處理,利用SQL建表、插入數據。不多說了,直接看代碼

生成的Excel是2003還是2007,就是通過連接字符串來控制的(代碼中的connString ),同時傳遞的文件名也要一致(xls or xlsx),不然會出現運行不成功或者生成的文件打不開的情況。
- Excel Com
Excel本身提供com組件來實現對Excel的操作,它的優點是顯而易見的,可以具體控制到操作excel中的任意一個單元格(內容+格式),利用oledb是做不到這一點的。當項目中需要使用現有模板生成Excel的時候使用該方法是很方便的。但該方法性能上慢,而且需要安裝Excel相關組件,生成文件后內存中有時仍舊有Excel進程。如果是web的話不建議使用該方法,否則管理員和服務器都會瘋掉的。

在使用com組件時,需要先在項目中添加“Microsoft.Office.Interop.Excel”引用。(代碼中的ExcelApp是我給相關命名空間提供的別名,using ExcelApp = Microsoft.Office.Interop.Excel;)
- Open xml
使用微軟提供的Open XML SDK也可以很方便的生成excel。(將office2007(Word、Excel、PPT) 的文件后綴名修改為”.zip”,將得到的壓縮包解壓,發現里面就是xml文件。),具體代碼我就不貼了,在使用中發現初始加載的時候也是比較慢的。
需要注意的是,該方法只能操作office 2007以上的版本,不支持0ffice 2003.
- NPOI
這個是朋友介紹的,一個開源的組件,使用時不需要安裝office(極大的優勢),也能具體到對一個單元格的控制。NPOI是POI的.NET版本,POI是一套用Java寫成的庫,能夠幫助開發者在沒有安裝微軟Office的情況下讀寫Office 97-2003的文件,支持的文件格式包括xls, doc, ppt等。官網(已遷移到googlecode)上提供了許多實際例子,而且atao也給了介紹和入門教程,代碼我就不復制了。
需要注意的是,目前該方法只能操作office2003。
- 大批量數據
上面幾種方法是比較常見的,但是當遇到大批量數據時,前兩種就太不給力了,特別是使用com組件那種,它們都是一條一條的生成。不過,com中可以使用QueryTable來提高效率。

{
ExcelApp.Application myExcel = new ExcelApp.Application();
ExcelApp._Workbook mybook = myExcel.Workbooks.Add();
try
{
mybook.Activate();
ExcelApp._Worksheet mysheet = mybook.Worksheets.Add();
string conn = "ODBC;Driver=SQL Server;Server=.;uid=sa;pwd=sa;database=sample;";
ExcelApp.QueryTable querytable = mysheet.QueryTables.Add(conn, mysheet.get_Range("A1"), strSQL);
querytable.Refresh(false);
mybook.SaveAs(Filename : filepath,AccessMode:ExcelApp.XlSaveAsAccessMode.xlNoChange);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
mybook.Close();
myExcel.Quit();
}
}
該方法比一條一條的插入不知道要快上多少倍,但是在我這測試時發現不穩定,同樣的代碼第一天還很快,到第二天就很慢了(相差特別大),同時,也存在excel進程關不掉的問題。
既然這樣,換個思路換個法子,既然一條一條的插入比較慢,那么批量插入呢,SQL語句中就有“select into”,能不能利用這個實現呢?查找資料后得知是可以的,在SQL Server中有OPENDATASOURCE(還有OPENROWSET)的 ,可以直接讀取excel中 的數據。
FROM OPENDATASOURCE('Microsoft.Jet.OLEDB.4.0',
'Data Source=D:\book.xls;Extended Properties=EXCEL 5.0')...[sheet1$] ;
也可以寫入,
'Data Source=D:\book.xls;Extended Properties=EXCEL 5.0')...[sheet1$]
select Customer .name ,Product .fullname
from [v_Order]
寫入的話得要求該文件存在,並且第一行有數據(表頭行)。
在使用OPENDATASOURCE前,需要先執行
RECONFIGURE
不然的話會報錯:“SQL Server 阻止了對組件 'Ad Hoc Distributed Queries' 的 STATEMENT 'OpenRowset/OpenDatasource' 的訪問”
但是,使用OPENDATASOURCE是在SQL Server進程中執行的,這也就導致生成的文件時在SQL Server服務器端的,無法在客戶端直接生成。
也可以利用 BCP 來導出,速度上非常快,但是導出的Excel並不是標准格式的,如果客戶不需要標准的格式,可以用這個來實現。
既然SQL Server中可以這樣做,在Access中是不是也可以呢?按照這個思路查找幫助,發現也是可以的,就是用in

在Access中運行上面的代碼后,就可以查詢中SQL Server數據庫中的數據,不過不支持連接查詢(用視圖唄),而且要注意保留字的處理(字段添加“[]”)。 當然,使用in不僅僅支持SQL Server,對其他數據庫也是支持的,可以看MSDN ,或者ACMAIN_CHM的這篇文章。
剛開始的時候已經說過,在用Oledb處理Excel時可以把excel當做access,那么只需要將OLEDB導出Excel中的創建表、插入記錄的SQL語句替換上面的查詢語句就可以了(得將代碼改為select into 才行,不然是生不成excel文件的),看看代碼

使用上面的方法時,傳遞的SQL
from product
in "" [ODBC;Driver=SQL Server;Server=.;uid=sa;pwd=sa;database=sample;]
如果需要添加where、orderby的話就放在上面SQL的后面(into后的表名在Excel中就是sheet的名稱)
into 商品
from product
in "" [ODBC;Driver=SQL Server;Server=.;uid=sa;pwd=sa;database=sample;]
where id_product >1
order by fullname
大批量數據導出的時候,需要注意這樣的一個問題,Excel2003格式一個sheet只支持65536行,excel 2007 就比較多,是1048576。