使用vb.net在大型excel文件上执行SQL查询的最佳方法是什么?

时间:2014-03-14 15:42:15

标签: .net vb.net excel vsto openxml

设置环境:

我正在使用带有.NET framework 4的vb.net开发Excel 2010应用程序级外接程序。


我的目标:

  1. 让用户输入多个名称来搜索
  2. 使用名称列表在LARGE电子表格(30,000多行)上执行SQL查询
  3. 返回记录集并粘贴到新工作表
  4. 表现是我的首要任务。我想通过利用.NET框架了解最快的方法。

    在我的代码中使用ADO连接对象可以正常工作,但这个过程需要很长时间(5 - 8秒)。


    这是我在名为的表格中使用的SQL查询:

        SELECT * 
        FROM wells 
        WHERE padgroup in 
    
        (SELECT padgroup 
         FROM wells 
         WHERE name LIKE 'TOMCHUCK 21-30'
                 OR name LIKE 'FEDERAL 41-25PH')
    


    以下是表格的一部分:

    Excel Table


    我现在正在使用此代码创建一个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的本机支持。

    经过研究,我发现了几个不同的选择:


    有人可以提供一个指针,指出最好的方法吗?我真的很感激。


    附加说明:

    • 所有查询都需要能够在没有连接的情况下执行 在线数据库
    • 我只需要访问电子表格一次即可从行中提取原始数据


    现在我只是将电子表格作为项目资源嵌入。

    然后,在运行时我创建文件,运行查询,将结果存储在内存中,然后删除文件。

       '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())
    

3 个答案:

答案 0 :(得分:2)

您正在以错误的方式执行VSTO;)不要将SQL与Excel一起使用。如果您需要速度,请利用VSTO和本机Excel API。您可以跳过ADODB / OLEDB图层的开销,直接进入Excel对象模型,在Excel中使用超快速自动过滤器,SpecialCells方法只将可见单元格放入多区域范围,{ {1}}将范围快速复制到数组的方法。

以下是VSTO 2010自定义工作簿示例,可快速搜索包含“aba”,“cat”或“zon”的a list of 58k words for words

Value

答案 1 :(得分:0)

Excel 2010文件不完全是XML。获取XLSX(或XMSM)文件,并使用.zip扩展名重命名该文件。然后将其解压缩到一个新文件夹。子文件夹中的文件将是XML文件,是的,但实际的XLSX文件是一个zip文件,其中包含一组包含XML文件的文件夹。

我认为,最好的办法是使用ACE驱动程序(不再支持JET)并通过ODBC访问它。如果这还不够快,您可以在特定时间提取摘录并将其上传到可以运行查询的数据库;查询应该更快,但可能会过时。

答案 2 :(得分:0)

我的解决方案:

我尝试了三种不同的方法:

  • 带有SQL的ADO连接对象(最慢)
  • VSTO和Excel的自动过滤器(可靠)
  • LINQ to XML(最快)

LINQ to XML提供了最佳性能。我将我的表转换为XML文件:

XML Table


然后,在我的代码中,我使用StringReader引入 XMLwellData 文件(保存为项目资源)。

    'welldoc will be the file to do queries on using LINQ to XML
    Dim stream As System.IO.StringReader
    stream = New StringReader(My.Resources.XMLwellData)

    welldoc = XDocument.Load(stream)

    'clean up stream now that it's no longer needed
    stream.Close()
    stream.Dispose()


    '***** later in the code perform my query on XML file *********

        Dim query = _
     From well In welldoc.<wellList>.<well> _
     Where well.<name>.Value Like "TOMCHUCK 21-30" _
     Select well

     For Each well in query

        MessageBox.Show(well.<padgroup>.value)

     Next

做我想做的事情非常简单,最重要的是它很快。

感谢您提供的所有帮助和建议。这对我来说很有意义。


使用Excel自动过滤器的替代方法


如果您尝试使用其他答案中建议的代码,则只会过滤两个值:

    worksheet.Cells.AutoFilter(column, criteria, Excel.XlAutoFilterOperator.xlOr);


因此,对于filter with multiple criteria using Excel's Auotfilter,您必须将参数作为数组传递并过滤xlFilterValues。


    Dim wrkbk As Excel.Workbook
    Dim wrksht As Excel.Worksheet
    Dim myRange As Excel.Range
    Dim cell As Excel.Range

    'You would add all of your wellnames to search to this List
    Dim wellNames As New List(Of String)

    wrksht = wrkbk.Sheets(1)

    'In my excel file there is a Named Range which includes the all the information
    myRange = wrksht.Range("WellLookUpTable")

    'Notice, for `Criteria1:=` you MUST convert the List to an array
    With wrksht.Range("WellLookUpTable")
        .AutoFilter(Field:=2, Criteria1:=wellNames.ToArray, Operator:=Excel.XlAutoFilterOperator.xlFilterValues)
    End With

    myRange = wrksht.Range("A2", wrksht.Range("A2").End(Excel.XlDirection.xlDown)).Cells.SpecialCells(Excel.XlCellType.xlCellTypeVisible)

    For Each cell In myRange

        'column 11 is padgroup
        MessageBox.Show(cell.Offset(0, 11).Value)

    Next
相关问题