Range versus Range Cells using Index Match in VBA - excel

I'm struggling to use the Range Cells method with Index Match in VBA. Using standard ranges works fine, but I'm having no luck with Range Cells. I must be failing to grasp something fundamental about Index Match. I have commented out the lines of code that fail. I appreciate any pointers the community can provide.
Sub IndexMatchTroubleShooting()
'dim worksheets
Dim Source As Worksheet
Dim Target As Worksheet
'set worksheets
Set Source = ThisWorkbook.Sheets("Source")
Set Target = ThisWorkbook.Sheets("Target")
'dim ranges
Dim ValuesToPull As Range
Dim TargetIDs As Range
Dim SourceIDs As Range
Dim MyRange As Range
'using range <-this works
Set ValuesToPull = Source.Range("B1:B5682")
Set TargetIDs = Target.Range("A1:A21")
Set SourceIDs = Source.Range("A1:A5682")
Set MyRange = Target.Range("B1:B21")
'using range cells <-this produces this error: "Run-time Error 1004 Method 'Range' of object '_Worksheet' failed"
'Set ValuesToPull = Source.Range(Cells(1, 2), Cells(5682, 2))
'Set TargetIDs = Target.Range(Cells(1, 1), Cells(21, 1))
'Set SourceIDs = Source.Range(Cells(1, 1), Cells(5682, 1))
'Set MyRange = Target.Range(Cells(1, 2), Cells(21, 2))
'apply formula
MyRange = Application.Index(ValuesToPull, Application.Match(TargetIDs, SourceIDs, 0))
End Sub

You need to fully qualify all Range/Cells references with a sheet as this will error if a different sheet is active when the macro is run, e.g.
Set ValuesToPull = Source.Range(Source.Cells(1, 2), Source.Cells(5682, 2))
or to save a bit of typing
With Source
Set ValuesToPull = .Range(.Cells(1, 2), .Cells(5682, 2))
Set SourceIDs = .Range(.Cells(1, 1), .Cells(5682, 1))
End With
With Target
Set TargetIDs = .Range(.Cells(1, 1), .Cells(21, 1))
Set MyRange = .Range(.Cells(1, 2), .Cells(21, 2))
End With
(Not sure you can use a multi-cell range in a match formula like that - does anyone know?)

Sub MatchMaster()
'this script helps simplify the use of Excel's Index Match function
'place this script in your personal macro workbook and assign it to a button
'use it to pull data between two worksheets that share unique identifiers
'dim ranges
Dim ValuesToPull As Range
Dim TargetIDs As Range
Dim SourceIDs As Range
Dim MyRange As Range
'dim worksheets
Dim Source1 As Worksheet
Dim Target1 As Worksheet
Dim Source2 As Worksheet
Dim Target2 As Worksheet
'input box dims
Dim Prompt1 As String
Dim Prompt2 As String
Dim Prompt3 As String
Dim Prompt4 As String
Dim Title1 As String
Dim Title2 As String
Dim Title3 As String
Dim Title4 As String
'set prompts
Prompt1 = "Select values to pull (1 column only)"
Prompt2 = "Select unique IDs on target sheet (1 column only)"
Prompt3 = "Select unique IDs on source sheet (1 column only)"
Prompt4 = "Where should we put these values? (1 column only)"
'set titles
Title1 = "Source Sheet"
Title2 = "Target Sheet"
Title3 = "Source Sheet"
Title4 = "Target Sheet"
'error handling
On Error GoTo OuttaHere
'input boxes
Set SourceIDs = Application.InputBox(Prompt3, Title3, Type:=8)
Set Source1 = SourceIDs.Worksheet
SourceIDcolumn = SourceIDs.Column
LastSourceID = Source1.Cells(Rows.Count, SourceIDcolumn).End(xlUp).Row
Source1.Activate
Set ValuesToPull = Application.InputBox(Prompt1, Title1, Type:=8)
Set Source2 = ValuesToPull.Worksheet
ValuesColumn = ValuesToPull.Column
LastValue = Source2.Cells(Rows.Count, ValuesColumn).End(xlUp).Row
Source2.Activate
Set TargetIDs = Application.InputBox(Prompt2, Title2, Type:=8)
Set Target1 = TargetIDs.Worksheet
TargetIDcolumn = TargetIDs.Column
LastTargetID = Target1.Cells(Rows.Count, TargetIDcolumn).End(xlUp).Row '<~~ also use this for MyRange
Target1.Activate
Set MyRange = Application.InputBox(Prompt4, Title4, Type:=8)
Set Target2 = MyRange.Worksheet
MyColumn = MyRange.Column
Target2.Activate
'convert input to Range Cells format
With Source1
Set SourceIDs = .Range(.Cells(1, SourceIDcolumn), .Cells(LastSourceID, SourceIDcolumn))
End With
With Source2
Set ValuesToPull = .Range(.Cells(1, ValuesColumn), .Cells(LastValue, ValuesColumn))
End With
With Target1
Set TargetIDs = .Range(.Cells(1, TargetIDcolumn), .Cells(LastTargetID, TargetIDcolumn))
End With
With Target2
Set MyRange = .Range(.Cells(1, MyColumn), .Cells(LastTargetID, MyColumn))
End With
'apply formula
MyRange = Application.Index(ValuesToPull, Application.Match(TargetIDs, SourceIDs, 0))
OuttaHere:
ActiveWorkbook.ActiveSheet.Columns.AutoFit
End Sub

Related

How do I get it to select a single row based on the value?

I'm working on simplifying an excel worksheet and I want information in the rows to be transferred based on the value. If the value = "done", I want it transferred to Carc. If the value = "On-going", I want it transferred to Ccon (haven't typed this up yet). This have been written-up in VBA but I'm open to trying other things if it would make things easier.
Main thing is that I'm trying to find a way to make the code already made, simpler and more practical. Only thing I haven't figured out is how to have it select 1 individual row, instead of all rows.
Sub MoveBasedOnValue2()
Dim TakeCell As Range
Dim DestCell As Range
Dim Status As Range
Dim Cjob As Worksheet
Dim CArc As Worksheet
Dim Contact As Range, Subject As Range, JobNo As Range, QuoteNo As Range
Dim Dateofcommision As Range, Ddate As Range
Set Cjob = Sheet4
Set CArc = Sheet1
If Cjob.Range("G2") = "Done" Then
Set Contact = Cjob.Range("A2")
Set Subject = Cjob.Range("B2")
Set QuoteNo = Cjob.Range("C2")
Set JobNo = Cjob.Range("D2")
Set Dateofcommision = Cjob.Range("E2")
Set Ddate = Cjob.Range("F2")
Status.Select
Contact.Select
Subject.Select
QuoteNo.Select
JobNo.Select
Dateofcommision.Select
Ddate.Select
If CArc.Range("A2") = "" Then
Set DestCell = CArc.Range("A2")
Else
Set DestCell = CArc.Range("A1").End(xlDown).Offset(1, 0)
End If
Contact.Copy DestCell
Subject.Copy DestCell.Offset(0, 1)
QuoteNo.Copy DestCell.Offset(0, 2)
JobNo.Copy DestCell.Offset(0, 3)
Dateofcommision.Copy DestCell.Offset(0, 4)
Ddate.Copy DestCell.Offset(0, 5)
Status.ClearContents
Contact.ClearContents
Subject.ClearContents
QuoteNo.ClearContents
JobNo.ClearContents
Dateofcommision.ClearContents
Ddate.ClearContents
End If
You can do something like this:
Sub MoveBasedOnValue2()
Dim cStatus As Range, wsDest As Worksheet
Set cStatus = Sheet4.Range("G2") 'first cell to check status
Do While Len(cStatus.Value) > 0
Select Case LCase(cStatus.Value)
Case "done": Set wsDest = Sheet1
Case "on-going": Set wsDest = Sheet2 'for example
Case Else: Set wsDest = Nothing 'no move to make
End Select
If Not wsDest Is Nothing Then 'got a destination sheet?
'here Range("A1:F2") is *relative* to the whole row...
cStatus.EntireRow.Range("A1:F2").Cut _
Destination:=wsDest.Cells(Rows.Count, "A").End(xlUp).Offset(1)
End If
Set cStatus = cStatus.Offset(1, 0) 'next source row
Loop
End Sub

Populating multiple cells in row from a reference table, depending on single cell value

I am attempting to populate columns D-J of table1, with the values in table2, columns B-H. The values should be based upon the value of column C in table1.
I have the code below, but I believe that is copying the tables as is and not doing a check of the value in column C.
Images:
Sub wps()
Dim rng As Range
Dim strTable As String
Dim strAddress As String
Dim i As Long
With Worksheets("Procedures")
For i = 1 To .ListObjects.Count
strTable = .ListObjects(i).Name
Set rng = .ListObjects(strTable).Range
strAddress = rng.Cells(2, 3).Address
rng.Copy Destination:=Worksheets("Base Data").Range(strAddress)
With Worksheets("Base Data")
.ListObjects(i).Name = "quals"
End With
Next i
End With
End Sub
It looks like a destination.value=source.value situation, using a single Match(). You could wrap this in a loop on your destWS.
Maybe something like (mock-up, untested):
For i = 2 to lastRowDest
dim sourceWS as worksheet
set sourceWS = sheets(1)
dim destWS as worksheet
set destWS = sheets(2)
destinationSearchTerm = destWS.Cells(i,"C").Value
dim sourceRow as long
sourceRow = Application.Match(destinationSearchTerm, sourceWS.Columns("A"), 0)
destWS.Range(destWS.Cells(i,"D"), destWS.Cells(i,"J") = sourceWS.Range(sourceWS.Cells(sourceRow,"B"),sourceWS.Cells(sourceRow,"H")
Next i

Excel Row paste with VBA

Hi guys i need some help on VBA.
I have range of numbers in sheet 1 from cells A6:O29. Next I have specific numbers selected in Sheet 3 in Column "B".
[![enter image description here][1]][1]
[![enter image description here][2]][2]
I want to loop throw each value in Sheet 3 Column B and find that specific value in Sheet 1 range A6:O29
Next it should paste Entire Row from Sheet 1 starting From Column (Q:CF) in Sheet 3 Starting from Column C onwards
I have coded it but its not working.
Private Sub CommandButton1_Click()
Dim main As Worksheet
Dim outcome As Worksheet
'main sheet contains Range to search number in
Set main = ThisWorkbook.Sheets("Sheet1")
'outcome sheet has specific values in Column B
Set outcome = ThisWorkbook.Sheets("Sheet3")
'column B values are considrered as doubles
Dim valuesfind As Double
'range where values are to be found
Dim myrange As Range
Set myrange = Worksheets("Sheet1").Range("A6:O29")
'no of times to loop code based on values in outcomesheet
locations = Worksheets("Sheet3").Cells(Rows.Count, 2).End(xlUp).Row
For i = 6 To locations
degrees = outcome.Range("B" & i).Value
For b = 6 To Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
If main.Range("A6:O29" & b).Value = degrees Then
outecome.Range("C:BR" & i).Value = main.Range("Q:CF" & b).Value
Exit For
End If
Next b
Next i
End Sub
[1]: https://i.stack.imgur.com/uBo66m.png
[2]: https://i.stack.imgur.com/D0bRUm.png
Please remember to declare all variables, add Option Explicit at the top of your module to help you enforce it.
Try the code below:
Option Explicit
Private Sub CommandButton1_Click()
'main sheet contains Range to search number in
Dim main As Worksheet
Set main = ThisWorkbook.Sheets("Sheet1")
Const mainCopyRng As String = "Q?:CF?"
'outcome sheet has specific values in Column B
Dim outcome As Worksheet
Set outcome = ThisWorkbook.Sheets("Sheet3")
Const outcomePasteRng As String = "C?:BR?"
'range where values are to be found
Dim myrange As Range
Set myrange = main.Range("A6:O29")
'no of times to loop code based on values in outcomesheet
Dim outcomeLastRow As Long
outcomeLastRow = outcome.Cells(Rows.Count, 2).End(xlUp).Row
Dim i As Long
For i = 6 To outcomeLastRow
Dim Degrees As Double
Degrees = outcome.Cells(i, 2).Value
Dim searchRng As Range
Set searchRng = myrange.Find(Degrees, LookIn:=xlValues, LookAt:=xlWhole)
If Not searchRng Is Nothing Then
Dim searchRow As Long
searchRow = searchRng.Row
outcome.Range(Replace(outcomePasteRng, "?", i)).Value = main.Range(Replace(mainCopyRng, "?", searchRow)).Value
End If
Next i
End Sub
This should work.
Sub Test()
Dim main As Worksheet
Set main = ThisWorkbook.Sheets("Sheet1")
Dim myrange As Range
Set myrange = main.Range("A6:O29")
Dim outcome As Worksheet
Set outcome = ThisWorkbook.Sheets("Sheet3")
'Set reference to locations in sheet3.
Dim locations As Range
With outcome
Set locations = .Range(.Cells(1, 2), .Cells(Rows.Count, 2).End(xlUp))
End With
'Search for each location in Sheet1 and if found copy to Sheet3.
Dim location As Range
Dim FoundLocation As Range
For Each location In locations
Set FoundLocation = myrange.Find( _
What:=location, _
After:=myrange.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext)
If Not FoundLocation Is Nothing Then
main.Cells(FoundLocation.Row, 1).Resize(, 15).Copy _
Destination:=location.Offset(, 1)
End If
Next location
End Sub

Table lookup on a different workbook on fulfilling a criteria - Most efficient way

I have a table with 66 columns (representing the Wind turbines) and about 5000 rows of timestamps. I have to check if the value of each cell, in this case velocity, meets a certain criteria, if it does, i extract name of the Wind turbine from the topmost row. Using the name, i need to "lookup" the Wind turbine closest to it from a Matrix in a different sheet and return this.
Option Explicit
Public Sub ErsetzenNachbar()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Arr As Variant
Dim Rng As Range
Dim SheetName As String
Dim i As Long
Dim j As Long
Dim WeaMat As Workbook
Dim Mat As Range
Dim Arr2 As Variant
Dim target As Long
Dim MOfound As String
SheetName = "INPUT_WIND"
'Range in the first Workbook
Set Rng = wb.Worksheets(SheetName).Range("C2:AG5000")
'Open the second Workbook
Set WeaMat = Workbooks.Open("C:\Users\Nikhil.srivatsa\Desktop\WeaMat")
'Set range for second workbook with the Matrix
Set Mat = WeaMat.Worksheets(1).Range("A2:AP68")
'Range into array
Arr = Rng.Value
'loop through array
For i = LBound(Arr, 1) To UBound(Arr, 1)
For j = LBound(Arr, 2) To UBound(Arr, 2)
If Arr(i, j) = 0.047 Then
'wind turbine Name from the topmost row
Arr(LBound(Arr, 1), j) = target
'look for target in the Matrix and fetch the neighboring turbine here is where i need help!
End If
Next j
Next i
End Sub
For example I look for the cells containing 0,047 (may vary) and get "MO30" the turbine name. Now i lookup MO30 in the Matrix of a second workbook and ask it to fetch MO42 from the Matrix since it is the first closest wind turbine.
would using Collections or Dictionary help in this case? or should I create an array out the Matrix? or use the Find function ?
Here is a simple example using two sheets rather than two workbooks, but see if you can adapt it for your set up.
Sub x()
Dim rFind1 As Range, s As String, rFind2 As Range
With Sheet1.Range("A1").CurrentRegion
Set rFind1 = .Find(what:=0.047, Lookat:=xlWhole, MatchCase:=False, SearchFormat:=False) 'look for value on sheet1
If Not rFind1 Is Nothing Then
s = .Rows(1).Cells(rFind1.Column) 'if found, find corresponding row 1 value
Set rFind2 = Sheet2.columns(1).Find(what:=s) 'look for this in sheet2
If Not rFind2 Is Nothing Then MsgBox rFind2.Offset(, 1) 'report contents of cell to the right
End If
End With
End Sub
Sheet1
Sheet2
Try this code, please:
Sub findTurb()
Dim sh As Worksheet, sh2 As Worksheet, rng As Range, strTurb As String
Const timeSt As Double = 0.047
Set sh = ActiveSheet 'use here your sheet
Set sh2 = Worksheets("second") 'use here your sheet
Set rng = sh.UsedRange.Find(timeSt)
If Not rng Is Nothing Then
strTurb = sh.Cells(1, rng.Column).value
Set rng = sh2.Range("A1:A" & sh2.Range("A" & Cells.Rows.Count).End(xlUp).Row).Find(strTurb)
If Not rng Is Nothing Then
MsgBox rng.Offset(, 1).value
End If
End If
End Sub
It can be transformed in a function, receiving time stamp as parameter and returning a string...

Use Index Match to pull multiple columns of data

The following script allows users to perform an Index Match function through a series of Input Boxes. This version only allows users to pull one column of data per use. I'm wondering if its possible to change this code to allow users to pull multiple columns of data. I appreciate any feedback the community can provide.
Sub MatchMaster()
'this script helps simplify the use of Excel's Index Match function
'place this script in your personal macro workbook and assign it to a button
'use it to pull data between two worksheets that share unique identifiers
'dim ranges
Dim ValuesToPull As Range
Dim TargetIDs As Range
Dim SourceIDs As Range
Dim MyRange As Range
'dim worksheets
Dim Source1 As Worksheet
Dim Target1 As Worksheet
Dim Source2 As Worksheet
Dim Target2 As Worksheet
'input box dims
Dim Prompt1 As String
Dim Prompt2 As String
Dim Prompt3 As String
Dim Prompt4 As String
Dim Title1 As String
Dim Title2 As String
Dim Title3 As String
Dim Title4 As String
'set prompts
Prompt1 = "Select values to pull (1 column only)"
Prompt2 = "Select unique IDs on target sheet (1 column only)"
Prompt3 = "Select unique IDs on source sheet (1 column only)"
Prompt4 = "Where should we put these values? (1 column only)"
'set titles
Title1 = "Source Sheet"
Title2 = "Target Sheet"
Title3 = "Source Sheet"
Title4 = "Target Sheet"
'error handling
On Error GoTo OuttaHere
'input boxes
Set SourceIDs = Application.InputBox(Prompt3, Title3, Type:=8)
Set Source1 = SourceIDs.Worksheet
SourceIDcolumn = SourceIDs.Column
LastSourceID = Source1.Cells(Rows.Count, SourceIDcolumn).End(xlUp).Row
Source1.Activate
Set ValuesToPull = Application.InputBox(Prompt1, Title1, Type:=8)
Set Source2 = ValuesToPull.Worksheet
ValuesColumn = ValuesToPull.Column
LastValue = Source2.Cells(Rows.Count, ValuesColumn).End(xlUp).Row
Source2.Activate
Set TargetIDs = Application.InputBox(Prompt2, Title2, Type:=8)
Set Target1 = TargetIDs.Worksheet
TargetIDcolumn = TargetIDs.Column
LastTargetID = Target1.Cells(Rows.Count, TargetIDcolumn).End(xlUp).Row '<~~ also use this for MyRange
Target1.Activate
Set MyRange = Application.InputBox(Prompt4, Title4, Type:=8)
Set Target2 = MyRange.Worksheet
MyColumn = MyRange.Column
Target2.Activate
'convert input to Range Cells format
With Source1
Set SourceIDs = .Range(.Cells(1, SourceIDcolumn), .Cells(LastSourceID, SourceIDcolumn))
End With
With Source2
Set ValuesToPull = .Range(.Cells(1, ValuesColumn), .Cells(LastValue, ValuesColumn))
End With
With Target1
Set TargetIDs = .Range(.Cells(1, TargetIDcolumn), .Cells(LastTargetID, TargetIDcolumn))
End With
With Target2
Set MyRange = .Range(.Cells(1, MyColumn), .Cells(LastTargetID, MyColumn))
End With
'apply formula
MyRange = Application.Index(ValuesToPull, Application.Match(TargetIDs, SourceIDs, 0))
OuttaHere:
ActiveWorkbook.ActiveSheet.Columns.AutoFit
End Sub

Resources