1

I'm a newbie to VBA and this is my first post. I've searched but can't seem to find anything that matches my scenario without using set ranges.

I have a worksheet that holds a list of account numbers in column A (no blank cells in between) and dates across the top row. Each day the user downloads a balances report from the bank and imports it in to this macro.

I want the macro to vlookup the accounts that are in column A of my list (sheetname is Balances) and return the balances for each account from the imported list (sheetname is Todays Bals - Account is Col B and Balance is Col C).

I'm trying to get a vlookup to work from the next empty cell in the top data row (row 2) to the bottom of the account list but it's going past the last non-empty cell and overwriting totals (with #N/A) that are at the bottom of the sheet, formulated ready for when the vlookup is completed for that day. (The totals have a blank row in between the list of accounts).

I think I may have contradicted the lastrow and activecell in the code, but I don't know how to fix it.

Any help is appreciated.

Below is my code so far:

Sub Vlookup()

Dim LastRow As Long

Worksheets("Balances").Activate

    If Range("C2").Value > 0 Then             '1st day of balances start in C2
        Range("C2").End(xlToRight).Offset(0, 1).Select
    Else
        Range("C2").Select
    End If

    If Sheets("Todays Bals").Range("A2") <> Sheets("Balances").Cells(1, ActiveCell.Column) Then
        MsgBox "These balances are for a different day.  Please import the correct day"
    Exit Sub
    Else
    
'Above is fine
'Below is where the issue is 

    LastRow = Range("A" & Rows.Count).End(xlUp).Row
           
    Range(ActiveCell.Offset(0, 0), ActiveCell.Offset(0, 0).End(xlDown)).Offset(0, 0).Formula = _
    "= vlookup(A2,'Todays Bals'!B:C,2,FALSE)"
    
    End If

End Sub
braX
  • 11,506
  • 5
  • 20
  • 33
Adezzz
  • 13
  • 4
  • _The totals have a blank row in between the list of accounts_ is that just one blank row in the dataset? Try `LastRow = Range("A" & Rows.Count).End(xlUp).Row-2` to remove 2 from your last row. – Darren Bartrup-Cook Jul 10 '23 at 13:13
  • I tried -2 but didn't change anything. Column A has the list of accounts (blank cells underneath). Under the columns of data that the vlookup is returning is a blank cell (from a blank row) and then another blank cell that has a formula ready to total the column of the returned data (but left blank so I don't have a load of 0's going across the spreadsheet). The vlookup is currently returning past the end of the accounts list and finishes on the blank total cell. I'm wondering if it's something to do with the ActiveCell Offset in the Vlookup that's overriding the LastRow? – Adezzz Jul 10 '23 at 13:36
  • Could you post an image of your data structure. Doesn't have to be the actual data, just so we can see what you're talking about. Saying that I just noticed you're not actually using the last row - your formula is using `ActiveCell.End(xlDown)` - the offsets aren't doing anything as they offset by 0 rows and 0 columns. So the last row is whatever cell is active and pressing Ctrl+Down arrow. – Darren Bartrup-Cook Jul 10 '23 at 13:41
  • Try `Range(ActiveCell, Cells(lastrow, ActiveCell.Column)).Formula = _ "= vlookup(A2,'Todays Bals'!B:C,2,FALSE)"` and then have a read of [How to avoid using Select in Excel VBA](https://stackoverflow.com/questions/10714251/how-to-avoid-using-select-in-excel-vba) – Darren Bartrup-Cook Jul 10 '23 at 13:45
  • 1
    Yes, your range... suggestion has worked. Thank you so much. I'm sure I'll have other posts for this project soon but this one was bugging me. Cheers. – Adezzz Jul 10 '23 at 13:59
  • I seem to have a further issue after fixing this (please advise if I need a new post). After the vlookup has done it's job, how can I then change all of the returned values as Values (currency). It keeps the formula in the returned cells and they all turn to #N/A when the next day of balances are imported) NB: Each column in the s/s is a different day? – Adezzz Jul 10 '23 at 15:48
  • Thank you VBasic2008. This will come in very useful for something else I'm working on. However for this project the vlookup is only being run once each day to update the previous days balances downloaded from the bank (it's going to be a daily interest calculator). – Adezzz Jul 11 '23 at 13:21
  • The further issue I was having, I have managed to fix and I've also managed to protect the data after the vlookup so it can't be edited. – Adezzz Jul 11 '23 at 13:23

1 Answers1

1

A Multi VBA Lookup (Application.Match)

enter image description here

  • To not further complicate matters (e.g. by using the Find method), I have used the strange condition that cell A3 in the destination can't be empty to ensure the success of xlDown. It is assumed that there is an empty row between the accounts and the totals row.
  • Also, I haven't used arrays or a dictionary to keep it simple (hmm!?).
Sub CopyAccountBalances()
    
    ' Define constants.
    
    Const SRC_SHEET As String = "Todays Bals"
    Const SRC_DATE_CELL As String = "A2"
    Const SRC_FIRST_ACCOUNTS_CELL As String = "B5" ' ?
    Const SRC_BALANCES_COLUMN As String = "C"
    
    Const DST_SHEET As String = "Balances"
    Const DST_DATE_FIRST_CELL As String = "C1"
    Const DST_FIRST_ACCOUNTS_CELL As String = "A2"
    
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    
    ' Source
    
    Dim sws As Worksheet: Set sws = wb.Sheets(SRC_SHEET)
    
    Dim sDate: sDate = sws.Range(SRC_DATE_CELL).Value
    
    If Not IsDate(sDate) Then
        MsgBox "The source date cell contains the invalid """ _
            & CStr(sDate) & """.", vbCritical
        Exit Sub
    End If
    
    Dim sarg As Range, srCount As Long
    
    With sws.Range(SRC_FIRST_ACCOUNTS_CELL)
        srCount = sws.Cells(sws.Rows.Count, .Column).End(xlUp).Row - .Row + 1
        If srCount < 1 Then
            MsgBox "No accounts in worksheet """ & SRC_SHEET & """.", vbCritical
            Exit Sub
        End If
        Set sarg = .Resize(srCount)
    End With
    
    Dim sbrg As Range: Set sbrg = sarg.EntireRow.Columns(SRC_BALANCES_COLUMN)
    
    ' Destination
    
    Dim dws As Worksheet: Set dws = wb.Sheets(DST_SHEET)
    
    Dim ddrg As Range, dcCount As Long
    With dws.Range(DST_DATE_FIRST_CELL)
        dcCount = dws.Cells(.Row, sws.Columns.Count).End(xlToLeft).Column _
            - .Column + 1
        If dcCount < 1 Then
            MsgBox "No dates in worksheet """ & DST_SHEET & """.", vbCritical
            Exit Sub
        End If
        Set ddrg = .Resize(, dcCount)
    End With
    
    Dim dDateColumnIndex:
    dDateColumnIndex = Application.Match(CLng(sDate), ddrg, 0)
    
    If IsError(dDateColumnIndex) Then
        MsgBox "The date """ & CStr(sDate) _
            & """ was not found in worksheet """ & DST_SHEET & """.", _
            vbCritical
        Exit Sub
    End If
    
    Dim darg As Range, drCount As Long
    
    With dws.Range(DST_FIRST_ACCOUNTS_CELL)
        With .Offset(1)
            If IsEmpty(.Value) Then
                MsgBox "The second accounts cell """ & .Address(0, 0) _
                    & """ can't be empty.", vbCritical
                Exit Sub
            End If
        End With
        drCount = .End(xlDown).Row - .Row + 1
        Set darg = .Resize(drCount)
    End With
    
    Dim dbrg As Range: Set dbrg = darg.EntireRow _
        .Columns(ddrg.Cells(dDateColumnIndex).Column)
    
    ' The Lookup
    
    Dim dCell As Range, dValue, srIndex, dr As Long
    
    For Each dCell In darg.Cells
        dr = dr + 1
        dValue = dCell.Value
        If Len(CStr(dValue)) > 0 Then ' is not blank
            srIndex = Application.Match(dValue, sarg, 0)
            If IsNumeric(srIndex) Then ' match found in source range row
                dbrg.Cells(dr).Value = sbrg.Cells(srIndex).Value
            End If
        End If
    Next dCell
        
    ' Inform.
        
    MsgBox "Account balances copied.", vbInformation

End Sub
VBasic2008
  • 44,888
  • 5
  • 17
  • 28