设置环境:
我正在使用带有.NET framework 4的vb.net开发Excel 2010应用程序级外接程序.
我的目标:
>让用户输入多个名称进行搜索
>使用名称列表在LARGE电子表格上执行SQL查询(30,000行)
>返回记录集并粘贴到新工作表中
表现是我的首要任务.我想通过利用.NET框架了解最快的方法.
在我的代码中使用ADO连接对象可以工作,但这个过程需要很长时间(5 – 8秒).
这是我在名为wells的表上使用的SQL查询:
SELECT *
FROM wells
WHERE padgroup in
(SELECT padgroup
FROM wells
WHERE name LIKE 'TOMCHUCK 21-30'
OR name LIKE 'FEDERAL 41-25PH')
这是表格的一部分:
我现在正在使用此代码创建一个ADO连接对象来检索我的结果:
'Create Recordset Object
rsCon = CreateObject("ADODB.Connection")
rsData = CreateObject("ADODB.Recordset")
rsCon.Open(szConnect)
rsData.Open(mySQLQueryToExecute, rsCon, 0, 1, 1)
'Check to make sure data is received, then copy the data
If Not rsData.EOF Then
TargetRange.Cells(1, 1).CopyFromRecordset(rsData)
Else
MsgBox("No records returned from : " & SourceFile, vbCritical)
End If
'Clean up the Recordset object
rsData.Close()
rsData = Nothing
rsCon.Close()
rsCon = Nothing
根据我的了解,Excel电子表格以Open XML格式存储,.NET框架包含解析XML的本机支持.
在研究之后,我遇到了几个不同的选择:
> Open XML SDK
> Simple API for XML (SAX)
> LINQ to SQL
有人可以提供一个指针,指出最好的方法吗?我真的很感激.
补充说明:
>所有查询都需要能够在没有连接的情况下执行
在线数据库
>我只需要访问一次电子表格就可以从行中提取原始数据
现在我只是将电子表格作为项目资源嵌入.
然后,在运行时我创建文件,运行查询,将结果存储在内存中,并删除文件.
'Create temp file path in the commonapplicationdata folder
Dim excelsheetpath As StringBuilder
excelsheetpath = New StringBuilder(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData))
excelsheetpath.Append("\MasterList.xlsm")
'Save resources into temp location in HD
System.IO.File.WriteAllBytes(excelsheetpath.ToString, My.Resources.MasterList)
'Now call the function to use ADO to get records from the MasterList.xlsm file just created
GetData(excelsheetpath.ToString, "Sheet1", "A1:S40000", True, False)
'Store the results in-memory and display by adding to a datagridview control (in a custom task pane)
'Delete the spreadsheet
System.IO.File.Delete(excelsheetpath.ToString())
最佳答案 你正在以错误的方式做VSTO;)不要在Excel中使用SQL.如果您需要速度,请利用VSTO和本机Excel API.您可以跳过ADODB / OLEDB图层的开销,直接使用Excel对象模型在Excel中使用超快速自动过滤器,使用SpecialCells方法将可见单元格放入多区域范围,并使用Value方法快速复制范围到数组.
以下是VSTO 2010自定义工作簿示例,可快速搜索包含“aba”,“cat”或“zon”的a list of 58k words for words.
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using Microsoft.Office.Tools.Excel;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
namespace ExcelWorkbook1
{
public partial class ThisWorkbook
{
private void ThisWorkbook_Startup(object sender, System.EventArgs e)
{
const int Sheet1 = 1; // you can use Linq to find a sheet by name if needed
const int ColumnB = 2;
List<List<object>> results = Query(Sheet1, ColumnB, "aba", "cat", "zon");
foreach (List<object> record in results)
{
System.Diagnostics.Debug.Print("{0,-10} {1,30} {2}", record[0], record[1], record[2]);
}
}
private void ThisWorkbook_Shutdown(object sender, System.EventArgs e)
{
}
/// <summary>
/// Removes any existing Excel autofilters from the worksheet
/// </summary>
private void ClearFilter(Microsoft.Office.Interop.Excel._Worksheet worksheet)
{
if (worksheet.AutoFilter != null)
{
worksheet.Cells.AutoFilter();
}
}
/// <summary>
/// Applies an Excel Autofilter to the worksheet for search for an array of substring predicates
/// </summary>
private void ApplyFilter(Microsoft.Office.Interop.Excel._Worksheet worksheet, int column, params string[] predicates)
{
string[] criteria = new string[predicates.Length];
int i = 0;
ClearFilter(worksheet);
foreach (string value in predicates)
{
criteria[i++] = String.Concat("=*", value, "*");
}
worksheet.Cells.AutoFilter(column, criteria, Excel.XlAutoFilterOperator.xlOr);
}
/// <summary>
/// Returns a list of rows that are hits on a search for an array of substrings in Column B of Sheet1
/// </summary>
private List<List<object>> Query(int sheetIndex, int columnIndex, params string[] words)
{
Microsoft.Office.Interop.Excel._Worksheet worksheet;
Excel.Range range;
List<List<object>> records = new List<List<object>>();
List<object> record;
object[,] cells;
object value;
int row, column, rows, columns;
bool hit;
try
{
worksheet = (Microsoft.Office.Interop.Excel._Worksheet)Globals.ThisWorkbook.Sheets[sheetIndex];
if (null == worksheet)
{
return null;
}
// apply the autofilter
ApplyFilter(worksheet, columnIndex, words);
// get the
range = worksheet.Range["$A:$C"].SpecialCells(Excel.XlCellType.xlCellTypeVisible);
foreach (Excel.Range subrange in range.Areas)
{
// copy the cells to a multidimensional array for perfomance
cells = subrange.Value;
// transform the multidimensional array to a List
for (row = cells.GetLowerBound(0), rows = cells.GetUpperBound(0); row <= rows; row++)
{
record = new List<object>();
hit = false;
for (column = cells.GetLowerBound(1), columns = cells.GetUpperBound(1); column <= columns; column++)
{
value = cells[row, column];
hit = hit || (null != value);
if (hit)
{
record.Add(cells[row, column]);
}
}
if (hit)
{
records.Add(record);
}
}
}
}
catch { }
finally
{
// use GC.Collect over Marshal.ReleaseComObject() to release all RCWs per https://stackoverflow.com/a/17131389/1995977 and more
cells = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
return records;
}
#region VSTO Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisWorkbook_Startup);
this.Shutdown += new System.EventHandler(ThisWorkbook_Shutdown);
}
#endregion
}
}