Vlookup VBA Excel - excel

Range("B3").Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-1],'02.09'!C[-1]:C,2,0)"
Range("B3").Select
Selection.FillDown
First:
I'm using the above code to to a Vlookup. If I run this Macro there is no error, but also the column which i did the vlookup has no values.
Second:
In this code im referencing sheet "02.09". But i would like to reference always the second sheet. I haven't found a solution yet.
Thank you all!

VLookup R1C1 Formula in VBA
A Quick Fix
Sub VLookupR1C1()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(2)
Dim dws As Worksheet: Set dws = wb.Worksheets(1) ' adjust!
With dws.Range("B3") ' reference the first cell
Dim lRow As Long ' the last row in column 'A' (offset '-1')
lRow = .Offset(dws.Rows.Count - .Row, -1).End(xlUp).Row
With .Resize(lRow - .Row + 1) ' reference the (one-column) range
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1],'" & sws.Name _
& "'!C[-1]:C,2,0),"""")" ' write the formula to the range
End With
End With
End Sub

The reason that there is no data in your column is that Fill down requires a range; it fills a range with the first cell in the range. The following code will fill down to row 5, you will need to define the last row that you want the formula copying to.
Range("B3").Select
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-1],'02.09'!C[-1]:C,2,0)"
Range("B3:B5").FillDown

Related

VBA cannot AutoFilter a Range for a certain criteria

I am trying to make a Range object of all entrys and than apply a filter, which searches for a number in there.
I want the Range to hold only the matching entrys afterwards, but I always get the error 1004...
Here the code:
Dim rSearch As Range
Dim rResult As Range
Set rSearch = wbMe.Sheets(iCurSheet).Range("F2:F1000")
rSearch.AutoFilter Field:=iColKey, Criteria1:="=" & wbMe.Sheets(iCurSheet).Cells(iLine, iColKey).Value
The last line throws the exception. I found out that the AutoFilter has to be applied to the first line, so .Range("A1:K1"), but I still don't get why I am not able to Filter on a Range, maybe i get the Object wrong?
Thanks in advance!
Edit:
So I tried some stuff:
Set rSearch = wbMe.Sheets(iCurSheet).Range("A2:K1000")
rSearch.AutoFilter Field:=11, Criteria1:="=" & wbMe.Sheets(iCurSheet).Cells(iLine, iColKey).Value
MsgBox "Count Rows rSearch:" & rSearch.Rows.Count
I expected the MsgBox to say smth less, but I get 999, so it hasn't filtered anything.
My guess that I was filtering the wrong column, but I wanna filter on Col K (I need Col F afterwards to search once more, sry for mixing stuff up).
Now I don't get the AutoFilter exception anymore. But for some reason my rSearch range does not shrink.
How do I shrink my Range?
Count Visible Data Cells (Criteria Cells)
A quick fix could be something like
MsgBox "Count Rows rSearch:" & rSearch.Columns(11).SpecialCells(xlCellTypeVisible).Cells.Count - 1
Note that the headers need to be included in the range for AutoFilter to work correctly.
Using SpecialCells
Sub CountVisibleDataCells()
' Define constants.
Const CriteriaIndex As Long = 11
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
' Turn off AutoFilter.
If ws.AutoFilterMode Then ws.AutoFilterMode = False
' Reference the range ('rg').
Dim rg As Range: Set rg = ws.Range("A1:K21")
' Store the criteria value from the cell, converted to a string ('CStr'),
' in a string variable ('Criteria'). AutoFilter 'prefers' this.
Dim Criteria As String: Criteria = CStr(ws.Range("M1").Value)
' Filter the range.
rg.AutoFilter Field:=CriteriaIndex, Criteria1:=Criteria
' Reference the visible cells in the criteria column ('vrg').
Dim vrg As Range
Set vrg = rg.Columns(CriteriaIndex).SpecialCells(xlCellTypeVisible)
' Turn off the worksheet auto filter.
ws.AutoFilterMode = False
' Store the number of visible cells of the criteria column
' in a long variable (subtract 1 to not count the header).
Dim CriteriaCount As Long: CriteriaCount = vrg.Cells.Count - 1
' Inform.
MsgBox "Count of '" & Criteria & "': " & CriteriaCount
End Sub
Using Application Count
Sub CountCriteriaCells()
' Define constants.
Const CriteriaIndex As Long = 11
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet1")
' Turn off AutoFilter.
If ws.AutoFilterMode Then ws.AutoFilterMode = False
' Reference the range ('rg').
Dim rg As Range: Set rg = ws.Range("A1:K21")
' Store the criteria value from the cell, converted to a string ('CStr'),
' in a string variable ('Criteria').
Dim Criteria As String: Criteria = CStr(ws.Range("M1").Value)
' You may need to modify this because 'CountIf' works differently.
' Reference the criteria data range ('cdrg') (no headers).
Dim cdrg As Range
With rg.Columns(CriteriaIndex)
Set cdrg = .Resize(.Rows.Count - 1).Offset(1)
End With
' Store the number of cells containing the criteria ('CriteriaCount')
' in a long variable.
Dim CriteriaCount As Long
CriteriaCount = Application.CountIf(cdrg, Criteria)
' Inform.
MsgBox "Count of '" & Criteria & "': " & CriteriaCount
End Sub

Write a dynamic sum formula vba that takes range from another sheet

screenshot of code
I am trying to calculate sum in cell "I13" of sheet2 with inputs based on the dynamic range.
Formula
range("I13").formula= "=sum('sheet1'!A1:A3)"
works but the range can be dynamic. For this I have used lr to identify the last row in the range
lr=cells(rows.count,1).end(xlup).row
Now, I want to modify the above formula such that in place of A3, it takes last cell. i.e. A&lr
Have tried using range("I13").formula= "=sum('sheet1'!A1:A"&lr)", but it results in error
Sub MMM()
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
'this code works. But want dynamic range
'range("I13").formula = "= SUM('sheet1'!A1:A3)"
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
you can try to define the variable:
Option Explicit ' It should be used when you define variable
Sub MMM()
Dim lr as Range ' Define variable
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
You have to join the string for the formula like this:
"=SUM('Sheet1'!A1:A" & lastRow & ")"
Alternatively:
If you set the whole range to be summed then you can use the Address of this range. The External-parameter returns the sheet name as well.
Sub MMM()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsSource As Worksheet: Set wsSource = wb.Worksheets("Sheet1")
Dim wsTarget As Worksheet: Set wsTarget = wb.Worksheets("Sheet2")
Dim rgDataToSum As Range
With wsSource
Set rgDataToSum = .Range("A1", .Cells(.Rows.Count, 1).End(xlUp))
End With
wsTarget.Range("I13").Formula = "=SUM(" & rgDataToSum.Address(True, True, External:=True) & ")"
End Sub

Delete cells in column after last row in another

I would like to clear content of cells (not delete rows) in a column after the last row of another column. The code would act as follows to work properly
Go to last cell in column BA,
move to the right to column BB
delete all rows in BB below that last rows
When I try recording the macro the code includes the range of that last cell as a fixed place.
This is the code, I highlighted where I believe the issue is
Sub CopyPaste2()
'
' CopyPaste2 Macro
'
'
Columns("AS:AV").Select
Selection.Copy
Columns("AX:AX").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
**Range("BA7").Select
Selection.End(xlDown).Select
Range("BB47").Select
Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.ClearContents**
Range("BB46").Select
Selection.End(xlUp).Select
Range("BB7").Select
Selection.AutoFill Destination:=Range("BB7:BB46")
Range("BB7:BB46").Select
Range("BA6").Select
ActiveWorkbook.Worksheets("KPI - Efficiency - Case Level").Sort.SortFields. _
Clear
ActiveWorkbook.Worksheets("KPI - Efficiency - Case Level").Sort.SortFields.Add _
Key:=Range("BA7:BA46"), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("KPI - Efficiency - Case Level").Sort
.SetRange Range("AX6:BB46")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Im pretty new to VBA so really appreciate your help
Try this:
Add the following line near the top of your code - traditionally, we tend to declare our variables at the start of a procedure:
'declare 'lastrow' to store value of row number
Dim lastrow As Long
And then at the end of your code, after the sort etc., add this:
With ActiveWorkbook.Worksheets("KPI - Efficiency - Case Level")
' find last used row of column BA and add 1
lastrow = .Range("BA" & .Rows.Count).End(xlUp).Row + 1
' clear from 'lastrow' to bottom of sheet in column BB
.Range("BB" & lastrow & ":BB" & .Rows.Count).ClearContents
End With
I can see you've recorded this macro, so it's a little messy. If you're interested in learning how to craft better vba that is more portable and easier to read, you will want to read up on avoiding Select etc.:
How to avoid using Select in Excel VBA
Clear the Cells Below a Range
If rg is a range object, to clear all cells below it, you can use the following line:
rg.Resize(rg.Worksheet.Rows.Count - rg.Row - rg.Rows.Count + 1).Offset(rg.Rows.Count).Clear
In the code, some parts of it are replaced with variables:
drg.Resize(ws.Rows.Count - FirstRow - rCount + 1).Offset(rCount).Clear
If rg has only one row, you can simplify with:
rg.Resize(rg.Worksheet.Rows.Count - rg.Row).Offset(1).Clear
Clear Below
Sub ClearBelow()
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim lCell As Range
' ("Go to last cell in column BA")
' Reference the last non-empty cell in column 'BA' using 'End'
' (in the code the Find method is used instead of the End property).
Set lCell = ws.Cells(ws.Rows.Count, "BA").End(xlUp)
' ("Move to the right to column BB")
' Reference the cell adjacent to the right using offset.
Set lCell = lCell.Offset(, 1)
' Reference the cell in the same row but in column 'BB' using 'EntireRow'.
' (can be any column).
'Set lCell = lCell.EntireRow.Columns("BB")
' ("Delete all rows in BB below that last rows")
' Clear all cells below the cell using 'Resize' and 'Offset'.
lCell.Resize(ws.Rows.Count - lCell.Row).Offset(1).Clear
End Sub
The Code
Option Explicit
Sub CopyPaste2() ' be more creative e.g. 'CreateEfficiencyReport'!
' Define constants.
Const wsName As String = "KPI - Efficiency - Case Level"
Const sColumnsString As String = "AS:AV" ' Source Copy Columns
Const dFirstColumnString As String = "AX" ' Destination First Copy Column
Const FirstRow As Long = 7
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the worksheet ('ws').
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
' To make sure that the worksheet is not filtered, when the remaining
' code would fail, you could use the following:
'If ws.FilterMode Then ws.ShowAllData
' Reference the source columns range ('scrg') ('$AS$7:$AV$1048576').
Dim scrg As Range: Set scrg = ws.Rows(FirstRow).Columns(sColumnsString) _
.Resize(ws.Rows.Count - FirstRow + 1)
'Debug.Print scrg.Address(0, 0)
' Attempt to reference the last cell ('lCell'), the bottom-most
' non-empty cell in the source columns range (for the bottom-most
' non-blank cell, use 'xlValues' instead of 'xlFormulas').
Dim lCell As Range
Set lCell = scrg.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If lCell Is Nothing Then Exit Sub ' no data
'Debug.Print lCell.Address(0, 0)
' Reference the source range ('srg').
Dim srg As Range: Set srg = scrg.Resize(lCell.Row - FirstRow + 1)
'Debug.Print srg.Address(0, 0)
' Write the number of rows and columns of the source range
' to variables ('rCount', 'cCount').
Dim rCount As Long: rCount = srg.Rows.Count
Dim cCount As Long: cCount = srg.Columns.Count
Dim dcrg As Range ' Destination Copy Range
Dim dfcCell As Range ' Destination First Copy Cell
' Reference the destination first copy cell ('dfcCell').
Set dfcCell = ws.Cells(FirstRow, dFirstColumnString)
' Reference the destination copy range ('dcrg').
Set dcrg = dfcCell.Resize(rCount, cCount)
'Debug.Print dcrg.Address(0, 0)
' Copy the values from the source range to the destination copy range.
dcrg.Value = srg.Value
Dim dfrg As Range ' Destination Formula Range
Dim dffCell As Range ' Destination First Formula Cell
' Reference the destination first formula cell ('dffCell')
' in the column adjacent to the right of the copy range.
Set dffCell = dfcCell.Offset(, cCount)
' Reference the destination formula range ('dfrg').
Set dfrg = dffCell.Resize(rCount)
'Debug.Print dfrg.Address(0, 0)
Dim drg As Range ' (Whole) Destination Range
If rCount > 1 Then
' Write the formula from the first formula cell to the remaining cells
' of the destination formula range.
dfrg.Formula = dffCell.Formula
'
' Reference the destination range ('drg').
Set drg = dcrg.Resize(, cCount + 1) ' include the formula column
'Debug.Print drg.Address(0, 0)
' Sort the destination range ('drg') by the last column
' of the copy range.
drg.Sort drg.Columns(cCount), xlAscending, , , , , , xlNo
'Else ' there is only one row of data; do nothing
End If
' Clear the cells below the destination range.
drg.Resize(ws.Rows.Count - FirstRow - rCount + 1).Offset(rCount).Clear
End Sub

Index and Match Matrix formula to

I'm really stumped with converting Index + Match to VBA. I'm very new to VBA, this is proving to be beyond my abilities.
I have a table in Sheet2 With Columns, 'Case', 'Probability', 'Impact' & 'Severity'. Then a Matrix in Sheet1
My formula (filled down the column) is:
=IFNA(INDEX(Sheet1!$C$2:$G$6,MATCH([#Probability],Sheet1!$B$2:$B$6,0),MATCH([#Impact],Sheet1!$C$1:$G$1,0)),"")
I'm trying to auto-populate 'Severity' in the table based on the values in the Matrix
Table
Matrix
I tried using Application.WorksheetFunction but I don't get any results.
Any advice would be much appreciated.
VBA Using INDEX/MATCH Formula
These will populate the values instead of the formulas.
If you remove the line .Value = .Value, the formulas stay.
Adjust the worksheet and table names.
Option Explicit
Sub TestEdu()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets("Sheet2") ' adjust
Dim tbl As ListObject: Set tbl = ws.ListObjects("Table1") ' adjust
Dim lcl As ListColumn: Set lcl = tbl.ListColumns("Severity")
With lcl.DataBodyRange
.Formula = "=IFNA(INDEX(Sheet1!$C$2:$G$6,MATCH([#Probability]," _
& "Sheet1!$B$2:$B$6,0),MATCH([#Impact],Sheet1!$C$1:$G$1,0)),"""")"
.Value = .Value
End With
End Sub
Sub TestCompact()
With ThisWorkbook.Worksheets("Sheet2").ListObjects("Table1") _
.ListColumns("Severity").DataBodyRange
.Formula = "=IFNA(INDEX(Sheet1!$C$2:$G$6,MATCH([#Probability]," _
& "Sheet1!$B$2:$B$6,0),MATCH([#Impact],Sheet1!$C$1:$G$1,0)),"""")"
.Value = .Value
End With
End Sub

VBA to copy certain columns to all worksheets

Hi I'm looking to create code for copying certain columns (AH to AX) across all worksheets then skipping worksheets named "Aggregated" & "Collated Results"
I have this already
Sub FillSheets()
Dim ws As Worksheets
Dim worksheetsToSkip As Variant
Dim rng As Range
Dim sh As Sheet1
Set rng = sh.Range("AH1:AX7200")
worksheetsToSkip = Array("Aggregated", "Collated Results")
For Each ws In Worksheets
If IsError(Application.Match(ws.Name, worksheetsToSkip, 0)) Then
End Sub
This will
Loop through sheets
"Copy" data from AH1 - AX1 down to the last used row that is determined by Column AH (Update column if needed)
"Paste" data on a sheet named Sheet1 (Update if needed). The data will be pasted in Column AH on the first available blank row. It's not clear what column you want to paste the data in. You just need to change AH to Some Column to modify
"Copy" and "Paste" are in quotes because we are really just transferring values here since this is quicker. We are actually setting the values of two equal sized ranges equal to each other.
Option Explicit
Sub AH_AX()
'Update "Sheet1" to sheet where data is being pasted
Dim ms As Worksheet: Set ms = ThisWorkbook.Sheets("Sheet1")
Dim ws As Worksheet, wsLR As Long, msLR As Long
Dim CopyRange As Range, PasteRange As Range
For Each ws In Worksheets
If ws.Name <> "Aggregated" And ws.Name <> "Collated Results" Then
'Determine last rows
wsLR = ws.Range("AH" & ws.Rows.Count).End(xlUp).Row
msLR = ms.Range("AH" & ms.Rows.Count).End(xlUp).Offset(1).Row
'Set Ranges
Set CopyRange = ws.Range("AH1:AX" & LR)
Set PasteRange = ms.Range("AH" & msLR).Resize(CopyRange.Rows.Count, CopyRange.Columns.Count)
'Value Transfer (Quicker than copy/paste)
PasteRange.Value = CopyRange.Value
End If
Next ws
End Sub

Resources