2013-07-08 63 views
1

我已經繼承了一組excel VBA宏,它們從電子表格中抓取數據並將數據上傳到數據庫(SQL DB)。問題是數據「很大」(特定表單上的46列* 10,500行)需要的瘋狂時間。在我看來,將數據分塊到數據庫會更好,但這是正確的嗎?如果是這樣,那麼最好的方法是什麼?我目前正在嘗試在for循環中封裝下面的代碼,將它分成500行,但它並不優雅,因爲vba不是我的特長。大數據上傳到服務器,更好的塊?

Sub Upload_Claims() 

    Dim SubmissionNumber As Integer 
    Dim LoopVar As Integer, row As Integer 

    Set cnnConn = New ADODB.Connection 
    cnnConn.ConnectionString = "driver={SQL Server};server=" & Server & ";database=happyfunserver" 
    cnnConn.Open 

    SubmissionNumber = Sheets("Quality Check").Range("SubID").Value 

    'Upload HPL - PPL 
    Set cmdCommand = New ADODB.Command 
    Set cmdCommand.ActiveConnection = cnnConn 
    With cmdCommand 
     .CommandText = "Select * from losses where submission_id = " & SubmissionNumber 
     .CommandType = adCmdText 
     .Execute 
    End With 

    ' Open the recordset. 
    Set rstRecordset = New ADODB.Recordset 
    Set rstRecordset.ActiveConnection = cnnConn 
    rstRecordset.Open cmdCommand, , adOpenStatic, adLockBatchOptimistic 

    'upload ' 

    Sheets("PL").Select 
    row = 8 

    Do While Range("C" & row).Value <> vbNullString 

     With rstRecordset 
     .AddNew 
     .Fields("submission_id") = SubmissionNumber 

     If Range("A" & row).Value <> vbNullString Then 
      .Fields("tag_id") = Range("A" & row).Value 
     End If 
     If Range("B" & row).Value <> vbNullString Then 
      .Fields("batch_tag_id") = Range("B" & row).Value 
     End If 
     If Range("C" & row).Value <> vbNullString Then 
      .Fields("source") = Left(Range("C" & row).Value, 250) 
     End If 
     If IsDate(Range("D" & row).Value) Then 
      .Fields("evaluation_date") = Range("D" & row).Value 
     End If 



     If Range("E" & row).Value <> vbNullString Then 
      If Range("E" & row).Value = "HPL" Then 
      .Fields("coverage_type_id") = 22 
      ElseIf Range("E" & row).Value = "PL" Then 
      .Fields("coverage_type_id").Value = 2 
      End If 
     End If 
     '--------------' 

     If Range("F" & row).Value <> vbNullString Then 
      .Fields("claim_no") = Left(Range("F" & row).Value, 250) 
     End If 
     If Range("G" & row).Value <> vbNullString Then 
      .Fields("claimant") = Left(Range("G" & row).Value, 200) 
     End If 


     'upload layer' 

     If Range("H" & row).Value <> vbNullString Then 
      If UCase(Range("H" & row).Value) = "UNKNOWN" Then 
      .Fields("layer_id") = 0 
      ElseIf UCase(Range("H" & row).Value) = "AAA" Then 
      .Fields("layer_id") = 1 
      ElseIf UCase(Range("H" & row).Value) = "BBBBBB" Then 
      .Fields("layer_id") = 2 
      ElseIf UCase(Range("H" & row).Value) = "CCCCC" Then 
      .Fields("layer_id") = 3 
      ElseIf UCase(Range("H" & row).Value) = "DDDDDDDD" Then 
      .Fields("layer_id") = 4 
      ElseIf UCase(Range("H" & row).Value) = "EEE" Then 
      .Fields("layer_id") = 5 
      End If 
     End If 
     '-------------------' 

     If Range("I" & row).Value <> vbNullString Then 
      .Fields("aaaaaaaa_name") = Left(Range("I" & row).Value, 100) 
     End If 
     If IsNumeric(Range("J" & row).Value) And Range("J" & row).Value <> 0 Then 
      .Fields("bbb_id") = Left(Range("J" & row).Value, 7) 
     End If 
     If Not IsError(Range("K" & row).Value) Then 
      .Fields("ccc_id_verified") = Range("K" & row).Value 
     End If 
     If Not IsError(Range("L" & row).Value) Then 
      If Range("L" & row).Value <> vbNullString And Range("L" & row).Value <> 0 Then 
       .Fields("dddddddd_city") = Left(Range("L" & row).Value, 80) 
      End If 
     End If 
     If Range("M" & row).Value <> vbNullString And Range("M" & row).Value <> 0 Then 
      .Fields("eeeeeeee_fips") = Left(Range("M" & row).Value, 5) 
     End If 
     If Not IsError(Range("N" & row).Value) Then 
      If Range("N" & row).Value <> vbNullString And Range("N" & row).Value <> 0 Then 
      .Fields("ffffffff_stateabbr") = Left(Range("N" & row).Value, 2) 
      End If 
     End If 
     If IsDate(Range("O" & row).Value) Then 
      .Fields("gggggggg_date") = Range("O" & row).Value 
     End If 
     If IsDate(Range("P" & row).Value) Then 
      .Fields("hhhhhh_date") = Range("P" & row).Value 
     End If 
     If IsNumeric(Range("Q" & row).Value) Or Range("Q" & row).Value = 0 Then 
      .Fields("iiiiiiiii_paid") = Range("Q" & row).Value 
     End If 
     If IsNumeric(Range("R" & row).Value) Or Range("R" & row).Value = 0 Then 
      .Fields("jjjjjjjjj_reserve") = Range("R" & row).Value 
     End If 
     If IsNumeric(Range("S" & row).Value) Or Range("S" & row).Value = 0 Then 
      .Fields("kkkk_paid") = Range("S" & row).Value 
     End If 
     If IsNumeric(Range("T" & row).Value) Or Range("T" & row).Value = 0 Then 
      .Fields("llll_reserve") = Range("T" & row).Value 
     End If 


     'upload claim status' 

     If Range("U" & row).Value <> vbNullString Then 
      If UCase(Range("U" & row).Value) = "CLOSED" Then 
      .Fields("status_id") = 1 
      ElseIf UCase(Range("U" & row).Value) = "OPEN" Then 
      .Fields("status_id") = 0 
      ElseIf UCase(Range("U" & row).Value) = "REOPEN" Then 
      .Fields("status_id") = 2 
      End If 
     End If 
     '---------------------------' 

     If IsDate(Range("V" & row).Value) Then 
      .Fields("closed_date") = Range("V" & row).Value 
     End If 
     If Range("W" & row).Value <> vbNullString Then 
      .Fields("description") = Range("W" & row).Value 
     End If 


      If IsNumeric(Range("AN" & row).Value) Then 
       .Fields("manual") = Range("AN" & row).Value 
      End If 
      If IsNumeric(Range("AB" & row).Value) Then 
       .Fields("11111") = Range("AB" & row).Value 
      End If 
      If IsNumeric(Range("AC" & row).Value) Then 
       .Fields("2222222") = Range("AC" & row).Value 
      End If 
      If IsNumeric(Range("AD" & row).Value) Then 
       .Fields("33333333333") = Range("AD" & row).Value 
      End If 
      If IsNumeric(Range("AE" & row).Value) Then 
       .Fields("444444444") = Range("AE" & row).Value 
      End If 
      If IsNumeric(Range("AF" & row).Value) Then 
       .Fields("55555555") = Range("AF" & row).Value 
      End If 
      If IsNumeric(Range("AG" & row).Value) Then 
       .Fields("666666666") = Range("AG" & row).Value 
      End If 
      If IsNumeric(Range("AH" & row).Value) Then 
       .Fields("7777777777777") = Range("AH" & row).Value 
      End If 
      If IsNumeric(Range("AI" & row).Value) Then 
       .Fields("other") = Range("AI" & row).Value 
      End If 
      If IsNumeric(Range("AJ" & row).Value) Then 
       .Fields("88") = Range("AJ" & row).Value 
      End If 
      If IsNumeric(Range("AK" & row).Value) Then 
       .Fields("cause") = Range("AK" & row).Value 
      End If 
      If IsNumeric(Range("AL" & row).Value) Then 
       .Fields("dept") = Range("AL" & row).Value 
      End If 
      If IsNumeric(Range("AM" & row).Value) Then 
       .Fields("outcome") = Range("AM" & row).Value 
      End If 
      If IsNumeric(Range("AS" & row).Value) Then 
       .Fields("report_lag") = Range("AS" & row).Value 
      End If 
      If IsNumeric(Range("AT" & row).Value) Then 
       .Fields("closed_lag") = Range("AT" & row).Value 
      End If 


     .Update 
    End With 
    row = row + 1 
    If row Mod 25 = 0 Then 
     Application.StatusBar = "PL" & " - " & row 
     DoEvents 
    End If 
Loop 
Application.StatusBar = "Performing " & "PL" & " Batch Update..." 

rstRecordset.UpdateBatch 

'(Similar loop repeats for 5 different pieces) 


End Sub 

任何意見表示讚賞。我試圖保持簡短,但是當你不知道自己在做什麼或者要走什麼方向時很難。

+1

我估計處理記錄將總是慢 - 你會被更好地使用單個查詢具有閉合工作簿作爲數據源:'cnnConn.Execute「INSERT INTO損失(C1,C2,C3) SELECT * FROM [Excel 12.0; HDR = YES; Database = C:\ Development \ MyImport.xlsm]。[Sheet1 $]「'如果可以的話 – JosieP

+0

一個選項可能是將sql插入或更新語句寫入.sql文件可以直接在整個事務的最後一次提交對數據庫執行。插入或更新大約10k行不應該花很長時間。 – ChrisProsser

+0

這些是一些有趣的字段名稱。 「gggggggg_date」? 「7777777777777」?只是好奇。在發佈代碼之前,您是否隱藏了匿名代碼或者實際上是字段名稱? – PowerUser

回答

1

根據我們之間的對話以及我的認爲您的代碼的工作原理,這裏有一個未經測試的解決方案,您可以嘗試通過將大量處理移動到SQL來加速它。不幸的是,你必須跳過你已有的記錄集處理方法。根據谷歌,你不能使用ADO.Recordset作爲SQL查詢的來源(他們在內存的不同部分,並沒有看到對方)。所以,你可以試試這個:

  1. 在你的SQL Server上創建一個臨時表。我們稱之爲TblStaging,因爲爲什麼不。這個登臺表的數據類型不過是大字符串字段,所以它可以容納任何東西,包括錯誤。

  2. 在聲明連接字符串之後,嘗試使用JosieP的Insert語句將數據加載到TblStaging。之後評論所有的VBA。

  3. 製作一個.sql文件,根據VBA中的規則驗證您的數據,然後將其移至永久性SQL表。 (我假設你知道有足夠的SQL可以做到這一點。)由於這一切現在都在SQL中,而不是VBA,它應該快得多。

  4. 這個sql文件將不得不以某種方式運行。如果您不希望每次都手動執行此操作,則有兩個選項(假設您對SQL Server足夠好):
    4a。找出如何從命令行運行.sql並運行從VBA調用該命令行的批處理文件。 4b。將其設置爲定期經常性代理。通過記錄

+0

我認爲你和@JosieP是對的,所以我會嘗試這個解決方案。希望我可以很快把它放在一起,並將結果評論回來。 – SQLHound

+0

期待。另外,當前流程有多慢?是否值得重構代碼並可能產生新的錯誤? – PowerUser

+0

因此,今天提交後,我一起工作的小組決定擱置該項目(*拍頭*)。我仍然會自己嘗試一下,看看我能否更快地製作甜甜圈。謝謝。 – SQLHound

相關問題