2017-04-26 1 views
0

ストアドプロシージャの知識が非常に基本的であると言って始めましょう。私はVBAで基本的なクエリと戻り値を書き込む方法を知っています。私は、基本的に私の知識が壊れているSQL内のプログラムを書くことができることも知っています。私はそれだけで十分ではありません。とにかく、VBAでは、私は一連のクエリを実行します。このプロジェクトの構想段階で恐れていたように、単一のルーチンから多すぎるクエリを実行するために、実際のパフォーマンス上の問題が発生します。ここにルーチンがあります。VBAで複数のクエリを使用するストアドプロシージャ

Public Sub linePoll() 

    errorPosition = "aofResults.linePoll" 
    On Error GoTo errorTrap 
    Err.Clear 

    Dim rst As ADODB.Recordset 
    Dim rstA As ADODB.Recordset 
    Dim rstB As ADODB.Recordset 
    Dim rstC As ADODB.Recordset 
    Dim rstD As ADODB.Recordset 
    Dim rstE As ADODB.Recordset 
    Dim packQty As Integer 
    Dim m As Integer 
    Dim formFactor As Integer 

    m = 0 
    constr = "Provider=sqloledb;data source=i.p.add.ress;initial catalog=catalog;user id=user;password=password" 
    Set conn = New ADODB.connection 
    Set cmd = New ADODB.Command 
    conn.Open constr 
    cmd.ActiveConnection = conn 
    LogDiagnosticsMessage "Getting order quantity" 
    cmd.CommandText = "SELECT ISNULL(SUM(lQ.[QUANTITY]), 0) FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] AS oQ ON lQ.[SALES_ORDER_NUMBER] = oQ.[SALES_ORDER_NUMBER]" 
    Set rst = cmd.execute      'Get total order quantity, may change if inventory depletes. 
    If Not rst.EOF = True Then 
     LogDiagnosticsMessage "Found order quantity as " & rst(0) 
     Set eTag = ThisDisplay.eGroup.item("AOF\soQuantity") 
     eTag.value = rst(0) 
    Else 
       LogDiagnosticsMessage "No order found in line queue DB" 
    End If 
    If Not rst(0) = 0 Then 
     LogDiagnosticsMessage "Getting optic order quantity packed" 
     cmd.CommandText = "SELECT Count(rL.SERIAL_NUMBER) FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_OPTIC_RESULTS] AS rL WHERE EXISTS (SELECT [SO_LINE_NUMBER] FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] AS oQ ON lQ.[SALES_ORDER_NUMBER] = oQ.SALES_ORDER_NUMBER) AND [REJECT] = 'False'" 
     Set rst = cmd.execute 
     If Not rst.EOF = True Then 
      LogDiagnosticsMessage "Found optics order quantity packed as " & rst(0) 
      Set eTag = ThisDisplay.eGroup.item("AOF\soQuantityPacked") 
      eTag.value = rst(0) 
     Else 
        LogDiagnosticsMessage "No packed optics found in results DB" 
     End If 
     Set eTag = ThisDisplay.eGroup.item("Machine\itoSettings0") 'Evaluate packing quantity against machine settings (stored in DB, written to PLC at first startup) 
     LogDiagnosticsMessage "Evaluating manual pack need" 
     If rst(0) < eTag.value Then 
      Set eTag = ThisDisplay.eGroup.item("AOF\manualPack") 'Evaluate packing quantity 
      eTag.value = True 
     Else 
      eTag.value = False 
     End If 
     LogDiagnosticsMessage "Getting the top line order information" 
     cmd.CommandText = "SELECT lQ.[SO_LINE_NUMBER],lQ.[QUANTITY],lQ.[SELECTED],lQ.[FORM_FACTOR_ID], lQ.[FINISHED_PART_NUMBER], ISNULL(lQ.[OEM_PART_NUMBER], ''),ISNULL(lQ.[COMPATIBILITY], ''), oQ.[INDIVIDUAL_PACKAGING], oQ.[SALES_ORDER_NUMBER] FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] AS oQ LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ ON oQ.[SALES_ORDER_NUMBER] = lQ.[SALES_ORDER_NUMBER] WHERE lQ.[SO_LINE_NUMBER] IS NOT NULL ORDER BY lQ.[SELECTED] DESC,lQ.[COMPLETED] ASC" 
     Set rstA = cmd.execute()      'Returns the line orders associated to the sales order 
     If Not rstA.EOF = True Then 
      Set eTag = ThisDisplay.eGroup.item("AOF\SOLineNumber") 
      If Not eTag.value = rstA(0) Then  '************************************Updates the line order if the line order is different than what's already selected 
       Set eTag = ThisDisplay.eGroup.item("AOF\SOLineNumber") 
       eTag.value = rstA(0) 
       Set eTag = ThisDisplay.eGroup.item("AOF\QuantityOrdered") 
       eTag.value = rstA(1) 
       Set eTag = ThisDisplay.eGroup.item("AOF\FinishedPartNumber") 
       eTag.value = rstA(4) 
       Set eTag = ThisDisplay.eGroup.item("AOF\OEMPartNumber") 
       eTag.value = rstA(5) 
       Set eTag = ThisDisplay.eGroup.item("AOF\Compatibility") 
       eTag.value = rstA(6) 
       Set eTag = ThisDisplay.eGroup.item("AOF\IndividualPack") 'PLC expects "Double Pack" true\false, ITO sends "Single Pack" true\false 
       eTag.value = Not rstA(7) 
      End If         '************************************ 
      LogDiagnosticsMessage "Getting the quantity of parts passed for this line order" 
      cmd.CommandText = "SELECT COUNT(oL.[SERIAL_NUMBER]) FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_OPTICS] AS oL WHERE NOT EXISTS (SELECT [SERIAL_NUMBER] FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_OPTIC_RESULTS] rL WHERE oL.[SERIAL_NUMBER] = rL.[SERIAL_NUMBER]) AND oL.[SO_LINE_NUMBER] = " & rstA(0) 
      Set rstB = cmd.execute()     'Returns the count of the parts associated to the above line order that passed 
      If Not rstB.EOF = True Then 
       Set eTag = ThisDisplay.eGroup.item("AOF\QuantityPassed") 
       eTag.value = rstB(0) 
       LogDiagnosticsMessage "Evaluating parts remaining for this line order as " & rstB(0) 
       Select Case rstB(0)  'Evaluate Qty left to process in active line order 
        Case Is = 0       'Qty Zero (Line order complete) 
          LogDiagnosticsMessage "Setting line order as completed" 
          cmd.CommandText = "UPDATE [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] SET [SELECTED] = 'False', [COMPLETED] = 'True' WHERE [SO_LINE_NUMBER] = " & rstA(0) 
          cmd.execute      'Unselect the currently index line order and Set order as completed 
          LogDiagnosticsMessage "Checking line order quantity against sales order quantity" 
          cmd.CommandText = "SELECT ((SELECT COUNT(lQ.[SO_LINE_NUMBER]) FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] AS oQ ON oQ.[SALES_ORDER_NUMBER] = lQ.[SALES_ORDER_NUMBER]) - (SELECT COUNT(lQ.[SO_LINE_NUMBER]) FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] AS oQ ON oQ.[SALES_ORDER_NUMBER] = lQ.[SALES_ORDER_NUMBER] WHERE lQ.[COMPLETED] = 'True'))" 
          Set rstD = cmd.execute()   'Check line queue quantity associated to the sales order, count the line orders associated to the current sales order in the queue that are incomplete 
          'Set the currently indexed line order as selected 
          If rstD(0) = 0 Then 
          cmd.CommandText = "SELECT [ID] FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_BOXES] WHERE [SELECTED] = 'True'" 
          Set rstE = cmd.execute() 
           If Not rstE.EOF = False Then 
            Set eTag = ThisDisplay.eGroup.item("AOF\soFinished") 
            eTag.value = True 
            Set eTag = ThisDisplay.eGroup.item("AOF\PLC_FinishBox") 
            If eTag.value = 1 Then 
             LogDiagnosticsMessage "Checking whether or not the PLC ready to complete the order" 
             Set eTag = ThisDisplay.eGroup.item("AOF\PLC_CompleteOrder") 'Checks that order fulfillment mode is turned off 
             If eTag.value = 1 Then 
              boxNum = 0 
              LogDiagnosticsMessage "Unselecting sales order " & rstA(8) & ", deleting results for this sales order, and setting status to ERP" 
              cmd.CommandText = "UPDATE [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_QUEUE] SET [SELECTED] = 'False' WHERE [SALES_ORDER_NUMBER] = '" & rstA(8) & "'" 
              cmd.execute   'Set's the current sales order selected bit to off 
              cmd.CommandText = "UPDATE [ROBOTICS_OPTICS_MECHUAT].[dbo].[MACHINE_STATE] SET [STATUS] = 'USER' where [OPERATING_STATE] = 2" 
              cmd.execute   'sets the status back to USER 
              cmd.CommandText = "DELETE FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_OPTIC_RESULTS]" 
              cmd.execute 
              Set eTag = ThisDisplay.eGroup.item("AOF\orderFulfillmentMode") 
              eTag.value = 0 
              Set eTag = ThisDisplay.eGroup.item("AOF\PLC_CompleteOrder") 
              eTag.value = 0 
             End If 
            End If 
           End If 
           rstE.Close 
          Else 
           rstA.MoveNext    'Index to the next line order in the record set 
           LogDiagnosticsMessage "Indexing to the next order in the list, setting" & rstA(0) & " selected." 
           cmd.CommandText = "UPDATE [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] SET [SELECTED] = 'True' WHERE [SO_LINE_NUMBER] = " & rstA(0) 
           cmd.execute 
           rstD.Close 
          End If 
        Case Is > 0       'Qty Remaining > Line Order Qty (Line Order Select) 
         LogDiagnosticsMessage "Getting the form factor for this line order" 
         cmd.CommandText = "SELECT fF.[FORM_FACTOR_DESCRIPTION] FROM [ROBOTICS_OPTICS_MECHUAT].[dbo].[FORM_FACTOR] AS fF LEFT JOIN [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] AS lQ ON lQ.[FORM_FACTOR_ID] = fF.[FORM_FACTOR_ID] WHERE lQ.[SELECTED] = 'True'" 
         Set rstC = cmd.execute()   'Returns the form factor description that is currently selected in the order line queue 
         If Not rstC.EOF = True Then 
          Set eTag = ThisDisplay.eGroup.item("AOF\FormFactor") 
          eTag.value = rstC(0) 
          Set eTag = ThisDisplay.eGroup.item("AOF\NextOpticXFP") 
          Select Case rstC(0) 
          Case Is = "XFP" 
           eTag.value = True 
          Case Is <> "XFP" 
           eTag.value = Not True 
          End Select 
         End If 
         rstC.Close 
         LogDiagnosticsMessage "Setting " & rstA(0) & " as selected" 
         cmd.CommandText = "UPDATE [ROBOTICS_OPTICS_MECHUAT].[dbo].[AOF_ORDER_LINE_QUEUE] SET [SELECTED] = 'True' WHERE [SO_LINE_NUMBER] = " & rstA(0) 
         cmd.execute      'Set line as selected 
        Case Else 
        End Select 
       Else 
        MsgBox ("Error: No line orders exist for sales order " & rstA(4) & ".") 
       End If 
     ElseIf rstA.EOF = True Then 
      MsgBox ("Error: No sales order exists or no line orders associated to sales order: " & rstA(4) & " exists.") 
     End If 
    End If 
    Set eTag = ThisDisplay.eGroup.item("AOF\ITO_OpticsReady") 
    eTag.value = True 

    GoTo cleanExit 

cleanExit: 
    On Error Resume Next 
    If Not rst Is Nothing Then 
     rst.Close 
    End If 
    If Not rstA Is Nothing Then 
     rstA.Close 
    End If 
    If Not rstB Is Nothing Then 
     rstB.Close 
    End If 
    If Not rstC Is Nothing Then 
     rstC.Close 
    End If 
    If Not rstD Is Nothing Then 
     rstD.Close 
    End If 
    If Not rstE Is Nothing Then 
     rstE.Close 
    End If 
    conn.Close 
    Exit Sub 

errorTrap: 
    LogDiagnosticsMessage "_Eventwatcher2.gfx, Position: " & errorPosition & " , Error Code: [ " & Hex(Err.number) & "], Description: " & Err.Description & "" 
    Resume cleanExit 

End Sub 

ここで私の考えは、サーバー側にもっと処理を加えることです。これらのクエリのほとんどをカプセル化するために個別のストアドプロシージャを作成しましたが、パフォーマンスには十分強い影響はありませんでした。ここに私を連れて来る私の主な考えは、これをすべて単一のストアドプロシージャに入れることができますか?ストアドプロシージャから7つのクエリを実行すると、VBAコードでどのように処理できますか? 1つのクエリは次のクエリとどのように区別されますか?ストアドプロシージャ内の別のクエリの入力としてクエリの出力を使用するにはどうすればよいですか?

ありがとうございます!

編集:私はselect文を使用するクエリを統合しています。私は次のようになりました。これはうまくいくようです。

Private Sub Button1_Released() 

    Dim rst(1 To 8) As ADODB.Recordset 

    errorPosition = "ThisDisplay.Button1 Test" 
    On Error GoTo errorTrap 
    Err.Clear 


    Set conn = New ADODB.Connection 
    Set cmd = New ADODB.Command 
    constr = "Provider=sqloledb;data source=i.p.add.ress;initial catalog=CATALOG;user id=user;password=pass" 
    conn.Open constr 

    With cmd 
     .ActiveConnection = conn 
     .CommandText = "rt_test" 
     .CommandType = adCmdStoredProc 
     .CommandTimeout = 2 
    End With 

    Set rst(1) = cmd.Execute() 
    For i = 2 To 8 
     Set rst(i) = rst(i - 1).NextRecordset 
    Next 
    i = 1 
    GoTo cleanExit 

cleanExit: 
    On Error Resume Next 
    For i = 1 To 8 
     If Not rst(i) Is Nothing Then 
      rst(i).Close 
     End If 
    Next 
    conn.Close 

    Exit Sub 

errorTrap: 
    LogDiagnosticsMessage "_Eventwatcher2.gfx, Position: " & errorPosition & " , Error Code: [ " & Hex(Err.Number) & "], Description: " & Err.Description & "" 
    Resume cleanExit 

End Sub 

最終更新日:

上記に小さな変化が、私は必要な結果が得られました。その結果、ADOはNextRecordSetメソッドが呼び出されると自動的に前のレコードセットを閉じます。その代わりに、レコードセットを開いて配列にクローンし、次のレコードセットに移動する必要がありました。 プレースホルダとして機能する別のレコードセットを追加しました。あなたが思う、私は怖いよりも少し複雑です

conn.CursorLocation = adUseClient 'Needed to index through and clone recordsets 
conn.Open constr 

With cmd 'Run stored procedure 
    .ActiveConnection = conn 
    .CommandText = "rt_test" 
    .CommandType = adCmdStoredProc 
    .CommandTimeout = 2 
End With 

Set recordSet = cmd.execute() 

For i = 1 To 8 
    Set rst(i) = recordSet.Clone 
    Set recordSet = recordSet.NextRecordset 
Next 
... 
... 
... 
cleanExit: 
    On Error Resume Next 

    If Not recordSet Is Nothing Then 
     recordSet.Close 
    End If 

    For i = 1 To 8 
     If Not rst(i) Is Nothing Then 
      rst(i).Close 
     End If 
    Next 
    conn.Close 

    Exit Sub 

errorTrap: 
    LogDiagnosticsMessage "_Eventwatcher2.gfx, Position: " & errorPosition & " , Error Code: [ " & Hex(Err.number) & "], Description: " & Err.Description & "" 
    Resume cleanExit 

End Sub 
+0

おそらく、より良いアプローチは、必要な最終的な結果セットを得ることです。それが失敗した場合にのみ、より多くのクエリで理由を検出しようとします。 – Serg

答えて

1

を次のように

Dim recordSet, rst(1 To 8) As ADODB.recordSet 

はその後、私のコードを変更しました。

パフォーマンスの問題は、実行される方法ではなく、クエリ自体によるものかもしれません。 SSMSからすべての手順を実行する場合、どのようなパフォーマンスですか? Excelから実行するのと同じようにOKですか?おそらく簡単な作業ではなく、チューニングを行う必要がありますが、自動的に行うためのツールがあります。個々のクエリの見積もり実行計画を表示し、ツールが多くの助けになるインデックスを推奨するかどうかを確認します。

複数のレコードセットを返すSPを実行できます。一般的には、通常は最初のクエリの結果を持つ1つのオブジェクト(RecordSet)を取得します。通常は、NextRecordsetメソッドを呼び出した後、2回目のクエリのRecordSetにアクセスするなどの操作を行います。

残念ながら、T-SQLの部分は、あなたの質問に答えるだけでなく、もっと多くの作業のようです。

+0

私が考えているのは、すべてのクエリを1つのSPにまとめて、複数のクエリを作成するのではなく1回実行することです。私のパフォーマンスの問題はネットワーク速度かもしれないと感じています。私が一度だけ問い合わせなければならない場合、問題は消えるかもしれません。私がこれを書いた後に実現したことは、これらの問題がVPN経由で顧客ネットワークに接続された仮想マシンからテストしていることが原因である可能性があるということです。私は、サーバーにローカルであれば、パフォーマンスが大幅に向上することを喜んで賭けています。どのツールを参照していますか? – Jaberwocky

+0

複数のクエリでSPを作成すると、SP内の他のクエリで1つのクエリの結果をどのように使用できますか? – Jaberwocky

+1

オプションはほとんどありません。実行するのが最も簡単なのは、SELECT ... FROM ....のようなクエリがあれば、それを一時テーブルに入れることです。SELECT ... INTO #someName FROM ... ....プロシージャで必要な場所にテーブルのように#someNameを使用します。一時停止はspが終了した後に(実際には)消えてしまいます。つまり、他のテーブルなどとつなぐことができます。 – nimdil

関連する問題