VBA - Close workbook after acquiring necessary information

前端 未结 2 1622
太阳男子
太阳男子 2021-01-15 18:27

Your assistance is required on solving this world (Excel VBA) problem. I am using a VBA to populate an immense workbook (500 Cells per row), from a bucket load of workbooks(

相关标签:
2条回答
  • 2021-01-15 18:44

    Well how about querying the excel files using ADO instead?

    Function getField(Path As String, WorksheetName As String, CellRange As String) As Variant
        Const adOpenStatic = 3
        Const adLockOptimistic = 3
        Const adCmdText = &H1
    
        Set objConnection = CreateObject("ADODB.Connection")
        Set objRecordset = CreateObject("ADODB.Recordset")
    
        objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
            "Data Source=" & Path & ";" & _
                "Extended Properties=""Excel 8.0;HDR=NO;"";"
    
        objRecordset.Open "Select F" & Range(CellRange).Column & " as Val  FROM [" & WorksheetName & "$]", _
            objConnection, adOpenStatic, adLockOptimistic, adCmdText
    
        objRecordset.Move Range(CellRange).Row - 1
    
        getField = objRecordset("Val")
    
        objRecordset.Close
        objConnection.Close
    End Function
    
    0 讨论(0)
  • 2021-01-15 18:46

    Updated Answer

    To answer your original question, you have to activate the workbook first, then close the active workbook. However, doing this in a function is very poor practice and will more than likely perform in non-intuitive ways.

    The following is the fix to your original code:

    Function GetField(Path As String, WorksheetName As String, CellRange As String) As Variant
    
        'code
    
        wb.Activate 'Activate the opened workbook
        ActiveWorkbook.Saved = True
        ActiveWorkbook.Close 'Close the active workbook
    
    End Function
    

    Performing the .Close inside your function is not advised.

    Instead, to achieve the same thing without worry, make a Sub to close the workbooks that are opened by your function. We can achieve this by doing the following:

    Sub closeWB(Path As String)
        Dim wb As Workbook
        Set wb = GetObject(Path)
        wb.Activate
        ActiveWorkbook.Saved = True
        ActiveWorkbook.Close
    End Sub
    

    And then call on it from the same place you're calling your function. Just place it after the function call..

    Sub YourMainSub()
        Path = "C:\Users\you\Desktop\file example.xlsm"
        something.GetField(Path, "Sheet 1", "A1")
        Call closeWB(Path)
    End Sub
    

    After a lot of discussion between Allan and I, we discovered a solution to his problem. Ultimately using a UDF on the worksheet wasn't meeting his needs. As such we changed directions and made a routine that essentially did the same thing, but without having worksheet functions. This not only reduced the file size, but also made importing the data and setting up for the data import significantly faster. Below is a sample excerpt, in case anyone with this same issue wants a second option that may perform better.

    I could have put the data importing (Where we Call DataLoop()) in it's own For loop, but chose not to because maintaining a simple easy to edit code was more important than visual efficiency.

    'The function that imports the data
    Public Function GetField(Path, file, WorksheetName, CellRange) As Variant
       Dim wb As Workbook, ws As Worksheet, rng As Range, field As String
    
       If Right(Path, 1) <> "\" Then Path = Path & "\"
    
       If Dir(Path & file) = "" Then
           GetField = "File Not Found"
           Exit Function
       End If
    
       field = "'" & Path & "[" & file & "]" & WorksheetName & "'!" & Range(CellRange).Range("A1").Address(ReferenceStyle:=xlR1C1)
       GetField = ExecuteExcel4Macro(field)
    End Function
    
    'A loop that calls on the function
    Sub DataLoop(DataRange As Range, SourceRow As Long, SourceColumn As Integer, Path, file, WorksheetName)
        Dim rcell
    
        For Each rcell In DataRange
            rcell.Value = GetField(Path, file, WorksheetName, Cells(SourceRow, SourceColumn).Address(RowAbsolute:=False, ColumnAbsolute:=False))
            SourceColumn = SourceColumn + 1
        Next rcell
    End Sub
    
    'The main routine where we define where data goes and comes from
    Sub DataEntry()
        Dim dataWS As Worksheet, Path1 As String, WsName1 As String
    
        Dim testFileName As Range, file
    
        Dim avgDmmV As Range, avgPSTATADCV As Range, ppPSTATADCV As Range
    
        Dim gainLO0A As Range, gainLO0B As Range, gainLOm10A As Range, gainLOm10B As Range
        Dim gainLO10A As Range, gainLO10B As Range, gainLO20A As Range, gainLO20B As Range
        Dim gainLO60A As Range, gainLO60B As Range
    
        Set dataWS = ThisWorkbook.Sheets("DATA")
        Path1 = "\\server5\Operations\MainBoard testing central location DO NOT REMOVE or RENAME" 'File path Location
        WsName1 = "Summary"
    
        'The values of the cells in this range have the names of the .xls files
        Set testFileName = dataWS.Range("A6", dataWS.Range("A6").End(xlDown)) 
    
        For Each file In testFileName 'Loop through each file name
            dataRow = file.Row
    
            Set avgDmmV = dataWS.Range("C" & dataRow & ":F" & dataRow)
            Set avgPSTATADCV = dataWS.Range("H" & dataRow & ":M" & dataRow)
            Set ppPSTATADCV = dataWS.Range("Q" & dataRow & ":W" & dataRow)
    
            Set gainLO0A = dataWS.Range("Y" & dataRow & ":AG" & dataRow)
            Set gainLO0B = dataWS.Range("AI" & dataRow & ":AQ" & dataRow)
            Set gainLOm10A = dataWS.Range("AS" & dataRow & ":BA" & dataRow)
            Set gainLOm10B = dataWS.Range("BC" & dataRow & ":BK" & dataRow)
            Set gainLO10A = dataWS.Range("BM" & dataRow & ":BU" & dataRow)
            Set gainLO10B = dataWS.Range("BW" & dataRow & ":CE" & dataRow)
            Set gainLO20A = dataWS.Range("CG" & dataRow & ":CO" & dataRow)
            Set gainLO20B = dataWS.Range("CQ" & dataRow & ":CY" & dataRow)
            Set gainLO60A = dataWS.Range("DA" & dataRow & ":DI" & dataRow)
            Set gainLO60B = dataWS.Range("DK" & dataRow & ":DS" & dataRow)
    
            Call DataLoop(avgDmmV, 9, 5, Path1, CStr(file.Value), WsName1)
            Call DataLoop(avgPSTATADCV, 15, 5, Path1, CStr(file.Value), WsName1)
            Call DataLoop(ppPSTATADCV, 18, 5, Path1, CStr(file.Value), WsName1)
    
            Call DataLoop(gainLO0A, 31, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO0B, 32, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLOm10A, 33, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLOm10B, 34, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO10A, 35, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO10B, 36, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO20A, 37, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO20B, 38, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO60A, 39, 3, Path1, CStr(file.Value), WsName1)
            Call DataLoop(gainLO60B, 40, 3, Path1, CStr(file.Value), WsName1)
        Next file
    End Sub
    
    0 讨论(0)
提交回复
热议问题