2017-11-14 17 views
2

VBAを使用してSQLクエリをループする際に問題があります。実行に時間がかかります。 合計ループ回数は15分で115回です。クエリ時間を短縮する方法はありますか? ここにありますが、私のコードです:ループを使用してSQLをクエリする最速の方法

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 
+0

コードが機能する場合は、[CodeReview.SE](https://codereview.stackexchange.com/)に投稿する必要があります。 StackOverflowは動作しないコード用です。 – Vegard

答えて

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 
0

いくつかの考え...

あなたのコードが動作すると、あなたは内のデータの実際の処理をスピードアップするために行うことができます多くはありませんので、ワークシート(115反復は何もありません)、私の推測は大部分の時間はデータベースとの通信に費やされます。

115ループの15分は特別なことです。私はすべて単一のインデックスとしてこれをお勧めします

scan_type, status, returned, pos_no 

:あなたがいない既に持っている場合は

、あなたは上のインデックスを持っていることを確認してください。

これはバンドです。あなたは同じテーブルを115回スキャンしていますが、これは各スキャンをより効率的にするだけです - 115アイテムの食料品店への115回の移動と歩行の代わりに車を運転するようなものです。

クエリをパラメータ化します。リテラルを渡す代わりに、パラメータを設定し、それを各ループで送信します。

これはバンド援助であり、パフォーマンスよりも礼儀正しさに関係しますが、文を一度コンパイルして115回コンパイルして実行するのではなく、115回実行するとパフォーマンスに影響します。

さらに、テーブルを1回スキャンします。クエリを一度実行し、結果をデータ構造体に格納して(Dictionaryオブジェクトはうまくいくかもしれません)、その結果をループして適用します。

この結果場合:

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

が十分に小さい(< 5000かそこらの記録)されており、私はちょうど前にそれを実行して、スプレッドシートを通して、ループ辞典、それを保存したいです。

本当に大きい場合は、最初にスプレッドシートをスキャンし、その115項目に対してクエリを実行してから、スプレッドシートを2回ループして値を割り当てます。 in-listをパラメータとして渡すことはおそらく不可能です(途中でPostgreSQLにあります)ので、動的SQLのアプローチで十分でしょう。

リストに何千ものアイテムがある場合は、これを一時テーブルにロードしてからテーブルに対してジョインするのが最適な方法です。

関連する問題