VBA: matching cells from different workbooks - excel

I have a master sheet being updated by other workbooks. "Column A" in the Master has an ID number, the other spreadsheets will also have a column let's say "B" containing that ID number.
I want to match the ID number from the other workbook to the master and where it matches in column A pull over other columns into the master to fill in the blanks under the correct headings.
I was given this macro, but it's not matching any data.
Sub Macro1()
Dim mastersheet As Worksheet
Set mastersheet = ActiveSheet
For a = 2 To 1000
ValueToCheck = Cells(a, 1).Value
fname = "File location"
Dim Workbooktocheck As Workbook
Set Workbooktocheck = Workbooks.Open("filename")
For b = 2 To 1000
valueInNew = Workbooktocheck.Sheets("Sheet1").Cells(b, 12)
If ValueToCheck = valueInNew Then
mastersheet.Cells(a, 3).Value = Workbooktocheck.Sheets("sheet1").Cells(b, 7)
End If
Next b
Next a
End Sub
Update
This is the master:
This is the spreadsheet that updates:

Match() is usually faster than a nested loop as long as you're only expecting a single matched row.
Try this:
Sub Macro1()
Dim wsMaster As Worksheet, wbToCheck As Workbook, wsCheck As Worksheet
Dim ValueToCheck, a As Long, m
Set wsMaster = ActiveSheet
Set wbToCheck = Workbooks.Open("filepathgoeshere")
Set wsCheck = wbToCheck.Worksheets("Sheet1") '<<< was missing this
For a = 2 To wsMaster.Cells(Rows.Count, 1).End(xlUp).Row
ValueToCheck = wsMaster.Cells(a, 1).Value
If Len(ValueToCheck) > 0 Then
'match is faster than using a nested loop
m = Application.Match(ValueToCheck, wsCheck.Range("L:L"), 0)
If Not IsError(m) Then
'got a match
With wsMaster.Rows(a)
.Columns("C").Value = wsCheck.Cells(m, "G").Value
'etc for other cells...
End With
End If
End If
Next a
End Sub

Update Master Worksheet
Carefully adjust the values in the constants section.
s - Source (read from), d - Destination (written to)
Option Explicit
Sub UpdateMaster()
Const sPath As String = "C:\Test\Source.xlsx"
Const sName As String = "Sheet1"
Const sCol As String = "L"
Const sColsList As String = "A,B,C"
Const sfRow As Long = 1 ' header row
Const dName As String = "Master"
Const dCol As String = "A"
Const dfRow As Long = 1 ' header row
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
' Headers
Dim sCols() As String: sCols = Split(sColsList, ",")
Dim cUpper As Long: cUpper = UBound(sCols)
Dim dCols() As Long: ReDim dCols(0 To cUpper)
Dim cIndex As Variant
Dim n As Long
For n = 0 To cUpper
cIndex = Application.Match( _
sws.Rows(sfRow).Columns(sCols(n)), dws.Rows(dfRow), 0)
If IsNumeric(cIndex) Then
dCols(n) = cIndex
Else
MsgBox "A header was not found", vbCritical, "Update Master"
Exit Sub
End If
Next n
' Column Ranges
Dim sfCell As Range: Set sfCell = sws.Cells(sfRow + 1, sCol)
Dim slCell As Range: Set slCell = sws.Cells(sws.Rows.Count, sCol).End(xlUp)
Dim srg As Range: Set srg = sws.Range(sfCell, slCell)
Dim dfCell As Range: Set dfCell = dws.Cells(dfRow + 1, dCol)
Dim dlCell As Range: Set dlCell = dws.Cells(dws.Rows.Count, dCol).End(xlUp)
Dim drg As Range: Set drg = dws.Range(dfCell, dlCell)
' Write
Application.ScreenUpdating = False
Dim dCell As Range
Dim rIndex As Variant
For Each dCell In drg.Cells
rIndex = Application.Match(dCell.Value, srg, 0)
If IsNumeric(rIndex) Then
For n = 0 To cUpper
dCell.EntireRow.Columns(dCols(n)).Value _
= srg.Cells(rIndex).EntireRow.Columns(sCols(n)).Value
Next n
End If
Next dCell
Application.ScreenUpdating = True
' Inform
MsgBox "Data updated.", vbInformation, "Update Master"
End Sub

Related

Loop Filter data based on 2 criterial and copy it with header to new sheets

So Reference to My old question here that was solved by #VBasic2008, it worked quite well.
Loop Filter data and copy it with header to a new sheet
Now I wonder if I can tweak this code to filter two criteria instead of 1, as I need to filter column A also which contains my company codes (it's not unique values but repetitive like UK1, UK2, and so on. I want to filter for UK1 in column A first then Filter the unique values in column D in a loop and copy data to a new sheet.
with the code mentioned below or in the link shared, it filters only the unique values in column D and copies it to a new sheet.
I need to filter columns A and Column D as per the below screenshot. My columns that contain the data go from A to Z
Code:
Sub CreateSummary()
' Define constants.
' Source
Const SOURCE_NAME As String = "Sheet1"
Const SOURCE_FIRST_CELL_ADDRESS As String = "A1"
Const SOURCE_FILTER_COLUMN_INDEX As Long = 4
' Destination
Const DESTINATION_NAME As String = "Sheet2"
Const DESTINATION_FIRST_CELL_ADDRESS As String = "A1"
Const DESTINATION_GAP As Long = 1 ' empty rows in-between
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(SOURCE_NAME)
If sws.FilterMode Then sws.ShowAllData
Dim srg As Range
Set srg = sws.Range(SOURCE_FIRST_CELL_ADDRESS).CurrentRegion
Dim srCount As Long: srCount = srg.Rows.Count
If srCount = 1 Then Exit Sub ' only headers or empty worksheet
Dim scCount As Long: scCount = srg.Columns.Count
If scCount < SOURCE_FILTER_COLUMN_INDEX Then Exit Sub ' too few columns
' Write the values from the filter column ('srfg') to an array ('sData').
Dim sfrg As Range: Set sfrg = srg.Columns(SOURCE_FILTER_COLUMN_INDEX)
Dim sData() As Variant: sData = sfrg.Value
' Return the unique values and their number of occurrences
' in a dictionary ('dict').
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim sString As String
Dim sr As Long
For sr = 2 To srCount
sString = CStr(sData(sr, 1))
If Len(sString) > 0 Then dict(sString) = dict(sString) + 1 ' count
Next sr
If dict.Count = 0 Then Exit Sub ' only error values or blanks
Erase sData
' Reference the first destination cell ('dCell').
Application.ScreenUpdating = False
Dim dsh As Object
On Error Resume Next
Set dsh = wb.Sheets(DESTINATION_NAME)
On Error GoTo 0
If Not dsh Is Nothing Then
Application.DisplayAlerts = False
dsh.Delete
Application.DisplayAlerts = True
End If
Dim dws As Worksheet: Set dws = wb.Worksheets.Add(After:=sws)
dws.Name = DESTINATION_NAME
Dim dCell As Range: Set dCell = dws.Range(DESTINATION_FIRST_CELL_ADDRESS)
' Copy column widths.
srg.Rows(1).Copy
dCell.Resize(, scCount).PasteSpecial xlPasteColumnWidths
dCell.Select
' Copy the filtered ranges one below the other.
Dim sKey As Variant
For Each sKey In dict.Keys
srg.AutoFilter SOURCE_FILTER_COLUMN_INDEX, sKey
srg.Copy dCell
sws.ShowAllData
Set dCell = dCell.Offset(DESTINATION_GAP + dict(sKey) + 1)
Next sKey
sws.AutoFilterMode = False
'wb.Save
Application.ScreenUpdating = True
' Inform.
MsgBox "Summary created.", vbInformation
End Sub
Please, test the next updated code. It uses other two dictionaries (one for unique company codes and another one to keep the occurrences for each combination Company code - Filter criteria:
Sub CreateSummaryTwoFilters()
Const SOURCE_NAME As String = "Sheet1"
Const SOURCE_FIRST_CELL_ADDRESS As String = "A1"
Const FILTER_COLUMN1_INDEX As Long = 1
Const FILTER_COLUMN2_INDEX As Long = 4
' Destination
Const DESTINATION_NAME As String = "Sheet2"
Const DESTINATION_FIRST_CELL_ADDRESS As String = "A1"
Const DESTINATION_GAP As Long = 1 ' empty rows in-between
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(SOURCE_NAME)
If sws.FilterMode Then sws.ShowAllData
Dim srg As Range
Set srg = sws.Range(SOURCE_FIRST_CELL_ADDRESS).CurrentRegion
Dim srCount As Long: srCount = srg.rows.count
If srCount = 1 Then Exit Sub ' only headers or empty worksheet
Dim scCount As Long: scCount = srg.Columns.count
If scCount < FILTER_COLUMN2_INDEX Then Exit Sub ' too few columns
'place all the range in an array for faster iteration:
Dim sData() As Variant: sData = srg.Value
' Return the unique values of cells in A:A and D:D and the number of occurrences for each concatenated pair:
Dim dictA As Object: Set dictA = CreateObject("Scripting.Dictionary")
dictA.CompareMode = vbTextCompare
Dim dictD As Object: Set dictD = CreateObject("Scripting.Dictionary")
dictD.CompareMode = vbTextCompare
Dim dictAD As Object: Set dictAD = CreateObject("Scripting.Dictionary")
dictAD.CompareMode = vbTextCompare
Dim sString As String, sr As Long
For sr = 2 To srCount
sString = CStr(sData(sr, FILTER_COLUMN2_INDEX))
If Len(sData(sr, 1)) > 0 Then dictA(sData(sr, 1)) = vbNullString
If Len(sString) > 0 Then dictD(sString) = vbNullString
dictAD(sData(sr, 1) & "_" & sData(sr, 4)) = dictAD(sData(sr, 1) & "_" & sData(sr, 4)) + 1 'count rows of both occurrence on the same row
Next sr
Application.ScreenUpdating = False
Dim dws As Worksheet
On Error Resume Next
Set dws = wb.Sheets(DESTINATION_NAME)
On Error GoTo 0
If Not dws Is Nothing Then
dws.cells.ClearContents
Else
Set dws = wb.Worksheets.Add(After:=sws)
dws.name = DESTINATION_NAME
End If
Dim dCell As Range: Set dCell = dws.Range(DESTINATION_FIRST_CELL_ADDRESS)
' Copy column widths.
srg.rows(1).Copy ' copy the headers columns width
dCell.Resize(, scCount).PasteSpecial xlPasteColumnWidths
' Copy the filtered ranges one after the other.
Dim sKeyA As Variant, sKeyD As Variant
For Each sKeyA In dictA.Keys 'iterate between each key of company codes dictionary
For Each sKeyD In dictD.Keys 'Iterate between each key of D:D criteria dictionary
srg.AutoFilter FILTER_COLUMN1_INDEX, sKeyA 'place the filters:
srg.AutoFilter FILTER_COLUMN2_INDEX, sKeyD
srg.Copy dCell 'copy the filtered range
'if no any filter row resulted, writhe the keys combination on the headers row (after the last column):
If dictAD(sKeyA & "_" & sKeyD) = "" Then dCell.Offset(, scCount).Value = sKeyA & "_" & sKeyD
sws.ShowAllData:
Set dCell = dCell.Offset(DESTINATION_GAP + dictAD(sKeyA & "_" & sKeyD) + 1) 'reinitialize the cell where to paste next time
Next sKeyD
Next sKeyA
sws.AutoFilterMode = False
'wb.Save
Application.ScreenUpdating = True
' Inform.
dws.Activate
MsgBox "Summary created.", vbInformation
End Sub
Please, send some feedback after testing it.
Edited:
Please, test the next version, which should do what (I understood) you need. I had some problems with the fact that the code used to stop after inserting a worksheet... I added code lines to stop events, calculation etc.:
Sub CreateSummaryTwoFiltersPerCompCode()
Const SOURCE_NAME As String = "Sheet1"
Const SOURCE_FIRST_CELL_ADDRESS As String = "A1"
Const FILTER_COLUMN1_INDEX As Long = 1
Const FILTER_COLUMN2_INDEX As Long = 4
' Destination
Const DESTINATION_FIRST_CELL_ADDRESS As String = "A1"
Const DESTINATION_GAP As Long = 1 ' empty rows in-between
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(SOURCE_NAME)
If sws.FilterMode Then sws.ShowAllData
Dim srg As Range
Set srg = sws.Range(SOURCE_FIRST_CELL_ADDRESS).CurrentRegion
Dim srCount As Long: srCount = srg.rows.count
If srCount = 1 Then Exit Sub ' only headers or empty worksheet
Dim scCount As Long: scCount = srg.Columns.count
If scCount < FILTER_COLUMN2_INDEX Then Exit Sub ' too few columns
'place all the range in an array for faster iteration:
Dim sData() As Variant: sData = srg.Value
' Return the unique values of cells in A:A and D:D and the number of occurrences for each concatenated pair:
Dim dictA As Object: Set dictA = CreateObject("Scripting.Dictionary")
dictA.CompareMode = vbTextCompare
Dim dictD As Object: Set dictD = CreateObject("Scripting.Dictionary")
dictD.CompareMode = vbTextCompare
Dim dictAD As Object: Set dictAD = CreateObject("Scripting.Dictionary")
dictAD.CompareMode = vbTextCompare
Dim sString As String, sr As Long
For sr = 2 To srCount
sString = CStr(sData(sr, FILTER_COLUMN2_INDEX))
If Len(sData(sr, 1)) > 0 Then dictA(sData(sr, 1)) = vbNullString
If Len(sString) > 0 Then dictD(sString) = vbNullString
dictAD(sData(sr, 1) & "_" & sData(sr, 4)) = dictAD(sData(sr, 1) & "_" & sData(sr, 4)) + 1 'count rows of both occurrence on the same row
Next sr
Application.ScreenUpdating = False
' Copy the filtered ranges one after the other.
Dim sKeyA As Variant, sKeyD As Variant, dws As Object, dCell As Range
For Each sKeyA In dictA.Keys 'iterate between each key of company codes dictionary
'insert a new sheet per company code:
Set dws = Nothing
On Error Resume Next
Set dws = wb.Sheets(sKeyA)
On Error GoTo 0
If Not dws Is Nothing Then
Application.DisplayAlerts = False
dws.Delete
Application.DisplayAlerts = True
End If
'a lot of measures to avoid stopping the code after the sheet insertion...
Application.EnableEvents = False: Application.Calculation = xlCalculationManual
Application.AutomationSecurity = msoAutomationSecurityForceDisable
Set dws = wb.Worksheets.Add(After:=sws)
dws.name = sKeyA
DoEvents
Application.AutomationSecurity = msoAutomationSecurityByUI
Application.EnableEvents = True: Application.Calculation = xlCalculationAutomatic
Set dCell = dws.Range(DESTINATION_FIRST_CELL_ADDRESS)
' Copy column widths.
srg.rows(1).Copy ' copy the headers columns width
dCell.Resize(, scCount).PasteSpecial xlPasteColumnWidths
For Each sKeyD In dictD.Keys 'Iterate between each key of D:D criteria dictionary
srg.AutoFilter FILTER_COLUMN1_INDEX, sKeyA 'place the filters:
srg.AutoFilter FILTER_COLUMN2_INDEX, sKeyD
If dictAD(sKeyA & "_" & sKeyD) <> "" Then
srg.Copy dCell 'copy the filtered range
sws.ShowAllData
Set dCell = dCell.Offset(DESTINATION_GAP + dictAD(sKeyA & "_" & sKeyD) + 1) 'reinitialize the cell where to paste next time
End If
Next sKeyD
Next sKeyA
sws.AutoFilterMode = False
'wb.Save
Application.ScreenUpdating = True
' Inform.
dws.Activate
MsgBox "Summary created.", vbInformation
End Sub

Find Matches in Column and Replace from External File

I use this VBA code which works very well. It searches in column A of an external Excel file for all the terms in column D, and replaces the matches, with the content of column B of the external file in the found row. So for instance:
if D5 matches A11 of the external file, then B11 from external file is written to D5.
I am now trying to modify it so that it still searches in column 4 for matches in column A of external file, but for any matches found, replaces the column E with column B of the external file. So:
If D5 matches A11, then B11 from external file is written to E5.
Well, I've tried many changes in the replace loop but it throws errors every time. I suppose I don't use the correct command!
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook, thisWb As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet
Dim i As Long, lRow As Long
'This is the workbook from where code runs
Set thisWb = ThisWorkbook
Set thisWs = thisWb.Sheets("Sheet1")
'External file
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
Set NameListWS = NameListWB.Worksheets("Sheet1")
With NameListWS
'Detect end row in Col A of Data.xlsx
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'Loop though Column A
For i = 1 To lRow
'... and perform replace action
thisWs.Columns(4).Replace What:=.Range("A" & i).Value, _
Replacement:=.Range("B" & i).Value, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next i
End With
End Sub ```
Untested:
Private Sub CommandButton1_Click()
Dim NameListWB As Workbook
Dim NameListWS As Worksheet, thisWs As Worksheet, n As Long
Dim i As Long, arrList, arrD, rngD As Range
Set thisWs = ThisWorkbook.Sheets("Sheet1") 'This is the workbook from where code runs
'get an array from the column to be searched
Set rngD = thisWs.Range("D1:D" & thisWs.Cells(Rows.Count, "D").End(xlUp).Row)
arrD = rngD.Value
'Open external file and get the terms and replacements as an array
Set NameListWB = Workbooks.Open("E:\Data.xlsx")
With NameListWB.Worksheets("Sheet1")
arrList = .Range("A1:B" & .Cells(Rows.Count, "A").End(xlUp).Row).Value
End With
For n = 1 To UBound(arrD, 1) 'check each value from ColD
For i = 1 To UBound(arrList, 1) 'loop over the array of terms to search for
If arrD(n, 1) = arrList(i, 1) Then 'exact match ?
'If InStr(1, arrD(n, 1), arr(i, 1)) > 0 Then 'partial match ?
rngD.Cells(n).Offset(0, 1).Value = arrList(i, 2) 'populate value from ColB into ColE
Exit For 'got a match so stop searching
End If
Next i
Next n
End Sub
A VBA Lookup (Application.Match)
Adjust (play with) the values in the constants section.
Compact
Sub VBALookup()
' Source
Const sPath As String = "E:\Data.xlsx"
Const sName As String = "Sheet1"
Const slCol As String = "A" ' lookup
Const svCol As String = "B" ' value
Const sfRow As Long = 2
' Destination
Const dName As String = "Sheet1"
Const dlCol As String = "D" ' lookup
Const dvCol As String = "E" ' value
Const dfRow As Long = 2
Application.ScreenUpdating = False
' Source
Dim swb As Workbook: Set swb = Workbooks.Open(sPath)
Dim sws As Worksheet: Set sws = swb.Worksheets(sName)
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, slCol).End(xlUp).Row
If slRow < sfRow Then Exit Sub ' no data in lookup column range
Dim srCount As Long: srCount = slRow - sfRow + 1
Dim slrg As Range: Set slrg = sws.Cells(sfRow, slCol).Resize(srCount)
Dim svData As Variant
With slrg.EntireRow.Columns(svCol)
If srCount = 1 Then ' one cell
ReDim svData(1 To 1, 1 To 1): svData(1, 1) = .Value
Else ' multiple cells
svData = .Value
End If
End With
' Destination
Dim dwb As Workbook: Set dwb = ThisWorkbook ' workbook containing this code
Dim dws As Worksheet: Set dws = dwb.Worksheets(dName)
Dim dlRow As Long: dlRow = dws.Cells(dws.Rows.Count, dlCol).End(xlUp).Row
If dlRow < dfRow Then Exit Sub ' no data in lookup column range
Dim drCount As Long: drCount = dlRow - dfRow + 1
Dim dlrg As Range: Set dlrg = dws.Cells(dfRow, dlCol).Resize(drCount)
Dim dData As Variant
If drCount = 1 Then ' one cell
ReDim dData(1 To 1, 1 To 1): dData(1, 1) = dlrg.Value
Else ' multiple cells
dData = dlrg.Value
End If
' Loop.
Dim srIndex As Variant
Dim dValue As Variant
Dim dr As Long
Dim MatchFound As Boolean
For dr = 1 To drCount
dValue = dData(dr, 1)
If Not IsError(dValue) Then
If Len(dValue) > 0 Then
srIndex = Application.Match(dValue, slrg, 0)
If IsNumeric(srIndex) Then MatchFound = True
End If
End If
If MatchFound Then
dData(dr, 1) = svData(srIndex, 1)
MatchFound = False
Else
dData(dr, 1) = Empty
End If
Next dr
' Close the source workbook.
swb.Close SaveChanges:=False
' Write result.
dlrg.EntireRow.Columns(dvCol).Value = dData
' Inform.
Application.ScreenUpdating = True
MsgBox "VBA lookup has finished.", vbInformation
End Sub

if condition only few steps true VBA/Excel

enter image description hereFor a larger project I need to change the source of values for a column all n*k steps, with n being a rational and k a natural number.
Edit for better understanding:
I have a column with multiple entries (filled by a loop in a makro) and need to find all entries with a common divisor called "testwer" in my makro. This "testwer" should later be editable in an excel sheet via a cellinput (in this case G2)
I've tried by writing a macro , a simplified example looks like the following:
Sub testmam()
Dim testwer, i, j
i = 1
j = 1
testwer = Range("g2").Value 'gets the rational number n
Do Until i = 18 'until end of entries in column is reached
If Cells(i, 1).Value = testwer * j Then 'if cellvalue = n*1,2,...,infty
Cells(i, 2).Value = j 'some output in another cell to check wether the detection was sucessfull
j = j + 1 'check coming cells for next value of n*k
End If
i = i + 1
Loop
End Sub
However, when I run this, it only detects the first few (3-5) solutions. For example for n being 1.5 it found only 1.5, 3 and 4.5 to be true. Starting from values 6 to all following multipliers of 1.5 the if condition seems to turn out false.
Does someone know how this could happen? As the if condition is true for multiple steps, I assume the syntax isn't completely wrong.
Greets
Detect Multipliers
Compact
Sub TestMamCompact()
Const wsName As String = "Sheet1"
Const SourceFirstCellAddress As String = "A1"
Const TestCellAddress As String = "G2"
Const DestinationColumn As String = "B"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim sfCell As Range: Set sfCell = ws.Range(SourceFirstCellAddress)
Dim slCell As Range
Set slCell = ws.Cells(ws.Rows.Count, sfCell.Column).End(xlUp)
If slCell.Row < sfCell.Row Then Exit Sub ' no data
Dim srg As Range: Set srg = ws.Range(sfCell, slCell)
Dim TestWert As Double: TestWert = ws.Range(TestCellAddress).Value
Dim k As Long: k = 1
Dim sCell As Range
For Each sCell In srg.Cells
If IsNumeric(sCell) Then
If sCell.Value = TestWert * k Then
ws.Cells(sCell.Row, DestinationColumn).Value = k
k = k + 1
End If
End If
Next sCell
MsgBox "Results written.", vbInformation
End Sub
Argumented
Sub TestMamTEST()
Const wsName As String = "Sheet1"
Const SourceFirstCellAddress As String = "A1"
Const TestCellAddress As String = "G2"
Const DestinationColumn As String = "B"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet: Set ws = wb.Worksheets(wsName)
Dim sfCell As Range: Set sfCell = ws.Range(SourceFirstCellAddress)
TestMam sfCell, TestCellAddress, DestinationColumn
' or just:
'TestMam sfCell, "G2", "B"
End Sub
Sub TestMamOneLinerTEST()
TestMam ThisWorkbook.Worksheets("Sheet1").Range("A1"), "G2", "B"
End Sub
Sub TestMam( _
ByVal SourceFirstCell As Range, _
ByVal TestCellAddress As String, _
ByVal DestinationColumn As String)
Dim ws As Worksheet: Set ws = SourceFirstCell.Worksheet
Dim slCell As Range
Set slCell = ws.Cells(ws.Rows.Count, SourceFirstCell.Column).End(xlUp)
If slCell.Row < SourceFirstCell.Row Then Exit Sub ' no data
Dim srg As Range: Set srg = ws.Range(SourceFirstCell, slCell)
Dim TestWert As Double: TestWert = ws.Range(TestCellAddress).Value
Dim k As Long: k = 1
Dim sCell As Range
For Each sCell In srg.Cells
If IsNumeric(sCell) Then
If sCell.Value = TestWert * k Then
ws.Cells(sCell.Row, DestinationColumn).Value = k
k = k + 1
End If
End If
Next sCell
MsgBox "Results written.", vbInformation
End Sub

Find value in another sheet and return value to the right

I want to take the active cell in the For Each, "vlookup" it in another sheet, and bring back the value from the cell to the right of it.
The problem is in .find(cell.value).
Option Explicit
Sub EmailRep()
Dim range1, range2, cell As Range
Dim ult_email As String
Dim ult_linha As Integer
Dim linha_atual As Integer
Dim Email_atual As String
Set range2 = Sheets("Planilha1").Range("B2:B21")
Set range1 = Range("D4:D19")
linha_atual = range1.Cells(1, 1).Row
ult_linha = 19
ult_email = Email_atual
Email_atual = ult_email
For Each cell In range1
If cell.Value <> ult_email Then
Email_atual = cell.Value
ult_email = cell.Value
Else
cell.Value = range2.Find(cell.Value).Offset(1, 1)
MsgBox (cell)
End If
linha_atual = linha_atual + 1
Next
End Sub
A VBA Lookup (Loop, Dictionary)
This may not be what you need but check it out. It will return the unique column pairs of one two-column range in another worksheet's two-column range.
Adjust (play with) the values in the constants section (a second worksheet name was never mentioned).
Option Explicit
Sub EmailRep()
' Source (Read)
Const sName As String = "Planilha1"
Const sfCol As String = "A"
Const sfRow As Long = 2
' Destination (Write)
Const dName As String = "Planilha2"
Const dfCol As String = "D"
Const dfRow As Long = 4
Const DoClearBelow As Boolean = True
Const DoSort As Boolean = True
' Both
Const Delimiter As String = "|" ' something that doesn't appear in the data
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the source range.
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim slRow As Long: slRow = sws.Cells(sws.Rows.Count, sfCol).End(xlUp).Row
Dim srg As Range: Set srg = sws.Range( _
sws.Cells(sfRow, sfCol), sws.Cells(slRow, sfCol)).Resize(, 2)
' Write from the source range to the dictionary.
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim srrg As Range
Dim sString As String
For Each srrg In srg.Rows ' loop through rows
sString = srrg.Cells(1) & Delimiter & srrg.Cells(2)
dict(sString) = Empty
Next srrg
Dim rCount As Long: rCount = dict.Count
Application.ScreenUpdating = False
' Write from the dictionary to the destination range.
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim drg As Range: Set drg = dws.Cells(dfRow, dfCol).Resize(rCount, 2)
Dim Key As Variant
Dim r As Long
For Each Key In dict.Keys
r = r + 1
drg.Rows(r).Value = Split(Key, Delimiter)
Next Key
' Clear below.
If DoClearBelow Then
drg.Resize(dws.Rows.Count - drg.Row - rCount + 1).Offset(rCount).Clear
End If
' Sort.
If DoSort Then drg.Sort drg.Columns(1), xlAscending
Application.ScreenUpdating = True
MsgBox "Data created.", vbInformation
End Sub

For loop on unique ID

Sheet1 is a continuous list of everything being recorded and kept.
Sheet2 is an updated list that is retrieved, with updated lines and new lines. Within the lists in column A is a unique ID for every entry in numeric value.
I am trying to go through every unique ID in sheet2, look for a match in sheet1
if there is a match, replace that entire row values with the new values from sheet2
if there is no match it needs to be placed in the last blank row (+1 from xlUp).
I have tried other ways that are not below like using scripting.dictionary.
The way I am trying to do this results in every cell that the “for” is looking at to be true for the if not equal. Every item is posted multiple times below xlUp.
Sub test()
Dim enter As Worksheet
Dim take As Worksheet
Set enter = Worksheets("Sheet1")
Set take = Worksheets("Sheet2")
Dim a1 As Long
Dim b1 As Long
Dim c1 As Long
a1 = take.Cells(Rows.Count, 1).End(xlUp).Row
b1 = enter.Cells(Rows.Count, 1).End(xlUp).Row
c1 = enter.Cells(Rows.Count, 1).End(xlUp).Row + 1
For i = 1 To a1 'this statement works fine to find the matching value to replace.
For K = 1 To b1
If take.Cells(i, 1) = enter.Rows(K, 1) Then
enter.Rows(i).EntireRow = take.Rows(K).EntireRow.Value
End If
Next
Next
'below is other things i have tried
'For I = 1 To a1
' For J = 1 To b1
' If enter.Cells(J, 1) <> take.Cells(I, 1) Then
' enter.Rows(c1).EntireRow = take.Rows(I).EntireRow.Value
' c1 = c1 + 1
' End If
' Next
'Next
'For i = 1 To a1
' For j = 1 To b1
' If take.Cells(i, 1) = enter.Cells(j, 1) Then
' enter.Rows(j).EntireRow = take.Rows(i).EntireRow.Value
' GoTo Skip
' ElseIf j = b1 Then
' enter.Rows(c1).EntireRow = take.Rows(i).EntireRow.Value
' c1 = c1 + 1
' End If
' Next
'Skip:
'Next
End Sub
hy
Public Sub MyCopy()
Dim wsSource As Worksheet, wsTarget As Worksheet
Set wsSource = ThisWorkbook.Worksheets("ws1")
Set wsTarget = ThisWorkbook.Worksheets("ws2")
Dim col As String
col = "A"
Dim i As Long, targetRow As Long, q As Long
Dim sourceRange As Range
With wsSource
For i = 1 To .Cells(.Rows.Count, col).End(xlUp).Row
Set sourceRange = .Range(col & i)
targetRow = GetDataRow(wsTarget, col, sourceRange.value)
For q = 0 To 30
wsTarget.Range(col & targetRow).Offset(0, q).value = sourceRange.Offset(0, q).value
Next q
Next i
End With
End Sub
Private Function GetDataRow(ws As Worksheet, col As String, value As String) As Long
With ws
Dim lastRow As Long, i As Long
lastRow = .Cells(.Rows.Count, col).End(xlUp).Row
For i = 1 To lastRow
If .Range(col & i).value = value Then
GetDataRow = i
GoTo exitFunc
End If
Next i
GetDataRow = lastRow + 1
End With
exitFunc:
End Function
Update Worksheet (For Each ... Next, Application.Match)
Option Explicit
Sub UpdateWorksheet()
Const sName As String = "Sheet2"
Const sFirst As String = "A1"
Const dName As String = "Sheet1"
Const dFirst As String = "A1"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim slCell As Range
Set slCell = sws.Cells(sws.Rows.Count, sws.Range(sFirst).Column).End(xlUp)
Dim srg As Range: Set srg = sws.Range(sFirst, slCell)
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlCell As Range:
Set dlCell = dws.Cells(dws.Rows.Count, dws.Range(dFirst).Column).End(xlUp)
Dim drg As Range: Set drg = dws.Range(dFirst, dlCell)
Application.ScreenUpdating = False
Dim sCell As Range
Dim cIndex As Variant
For Each sCell In srg.Cells
cIndex = Application.Match(sCell.Value, drg, 0)
If IsNumeric(cIndex) Then
drg.Cells(cIndex).EntireRow.Value = sCell.EntireRow.Value
Else
Set dlCell = dlCell.Offset(1)
dlCell.EntireRow.Value = sCell.EntireRow.Value
End If
Next sCell
Application.ScreenUpdating = True
End Sub

Resources