使用循环

时间:2017-11-14 07:17:43

标签: sql sql-server vba excel-vba excel

我在使用VBA循环SQL查询时遇到问题,需要很长时间才能运行。 总循环次数是15分钟内的115次。有什么办法可以缩短查询时间吗? 这是我的代码:

    Dim Conn As New ADODB.Connection
    Dim mrs As New ADODB.Recordset
    x = 1
    DBPath = ThisWorkbook.FullName
    sconnect = "Provider=SQLOLEDB;SERVER=DWSQL\BCAPP;Database=TEST;Uid=admin;Pwd=admin;"
    Conn.Open sconnect
    Do
        If Sheets("Foil (+)").Cells(12, 12) <> "" And Sheets("Data").Cells(x, 3).Value Like "E*" Then
            sSqlSting = "SELECT *FROM [TEST].[dbo].[process_details] where pos_no = '" & Sheets("Data").Cells(x, 3) & "' and scan_type = 'Anode Foil' and status = 'OK' and returned = 'N'"
        Else
            Sheets("Data").Cells(x, 3).Value = "E" & Sheets("Data").Cells(x, 3).Value
            sSqlSting = "SELECT *FROM [TEST].[dbo].[process_details] where pos_no = '" & Sheets("Data").Cells(x, 3) & "' and scan_type = 'Anode Foil' and status = 'OK' and returned = 'N'"
        End If

        mrs.Open sSqlSting, Conn, adOpenForwardOnly
        If Sheets("Data").Cells(1, 18) = "" Then
            Sheets("Data").Cells(1, 18).CopyFromRecordset mrs
        Else
            Sheets("Data").Cells(Rows.Count, 18).End(xlUp).Offset(1, 0).CopyFromRecordset mrs
        End If
        mrs.Close
        x = x + 1
    Loop Until Sheets("Data").Cells(x, 3) = ""
    Conn.Close

2 个答案:

答案 0 :(得分:0)

   sSqlSting = "SELECT *FROM [TEST].[dbo].[process_details] where scan_type = 'Anode Foil' and status = 'OK' and returned = 'N' and pos_no = in ('" 
enter code here

 Do
    If Sheets("Foil (+)").Cells(12, 12) <> "" And Sheets("Data").Cells(x, 3).Value Like "E*" Then
        sSqlSting = sSqlString &  Sheets("Data").Cells(x, 3) & "','"
    Else
        Sheets("Data").Cells(x, 3).Value = "E" & Sheets("Data").Cells(x, 3).Value
        sSqlSting = sSqlString &  '" & Sheets("Data").Cells(x, 3) & "','"
    End If
     x = x + 1
Loop Until Sheets("Data").Cells(x, 3) = ""

 sSqlSting = left(sSqlSting,len(sSqlsting)-1) & ")"


    mrs.Open sSqlSting, Conn, adOpenForwardOnly
    If Sheets("Data").Cells(1, 18) = "" Then
        Sheets("Data").Cells(1, 18).CopyFromRecordset mrs
    Else
        Sheets("Data").Cells(Rows.Count, 18).End(xlUp).Offset(1, 0).CopyFromRecordset mrs
    End If
    mrs.Close

答案 1 :(得分:0)

一些想法......

由于您的代码有效,并且您可以做很多事情来加快工作表中的数据实际处理(115次迭代什么都没有),我的猜测是花费大量时间与数据库进行通信

就此而言,115次循环的15分钟非同寻常。

如果您还没有,请确保您有索引:

scan_type, status, returned, pos_no

我建议将这一切作为单个索引。

这是一个创可贴。你正在对同一张桌子进行115次扫描,这只会使每次扫描更有效率 - 就像115次去杂货店购买115件物品而开车而不是走路一样。

参数化您的查询。不是传递文字,而是设置一个参数并在每个循环中发送它。

这也是一个创可贴,并且更多地与礼仪有关而不是表现,尽管会有性能影响,因为你正在编写一次声明并执行115次而不是编译和执行115次。

更好的是,对表进行一次扫描。执行一次查询,将结果存储在数据结构中(Dictionary对象可能做得很好),然后循环并应用这些结果。

如果结果如下:

scan_type = 'Anode Foil' and status = 'OK' and returned = 'N'

是否足够小(<5000左右的记录),我只是预先运行并将其存储在字典中,然后遍历电子表格。

如果它真的很大,那么首先扫描电子表格,仅针对这115个项目运行查询,然后再次遍历电子表格以分配值。传入一个列表作为参数可能是不可能的(顺便说一下,它在PostgreSQL中),所以你的动态SQL方法可能就足够了。

如果到达列表中有数千个项目的点,最好的方法是将这些项目加载到临时表中,然后对表格进行连接。