VBA. Replace a table cell content based on match from another table or delete entire row if match is not found - vba

I am trying to make the following to work:
There are two tables in a separate worksheets. I want it to check each cell in worksheet2 column B and find a match from worksheet1 column A. If a match is found then replace the data in worksheet2 column B with a data from a matching row of worksheet1 column B.
If a match is not found from a worksheet1 column A then delete entire row in a worksheet2 column B.
Sub match_repl_del()
Dim r1 As Long, rfound, vfound
Dim w1, w2, v As Long
Set w1 = Sheets(3) ' data sheet
Set w2 = Sheets(2) ' target sheet
r1 = 2 'data starting from row 2
Do While Not IsEmpty(w1.Cells(r1, 1))
v = w1.Cells(r1, 1)
rfound = Application.Match(v, w2.Columns(2), 0) ' look for value
If Not IsError(rfound) Then ' found it?
vfound = w2.Cells(rfound, 2)
If w1.Cells(r1, 2) <> vfound Then ' if value does not match sheet1 column b
w2.Cells(rfound, 2) = w1.Cells(r1, 2) ' update based on origin sheet
lastC = w2.Cells(rfound, 1).End(xlToRight).Column
w2.Range(w2.Cells(rfound, 1), w2.Cells(rfound, lastC)).Interior.ColorIndex = 5
Else ' delete entire row on sheet2 if match is not found
w2.Rows(r1).EntireRow.Delete
End If
End If
r1 = r1 + 1
Loop
End Sub

Try this wat, it's work for me :
Option Explicit
Sub test()
' Active workbook
Dim wb As Workbook
Set wb = ThisWorkbook
Dim i As Long
Dim j As Long
'*******************************************
'Adapt this vars
'define your sheets
Dim ws_1 As Worksheet
Dim ws_2 As Worksheet
Set ws_1 = wb.Sheets("Sheet1") 'find a match in worksheet1 column A
Set ws_2 = wb.Sheets("sheet2") 'cell in worksheet2 column B
'definie the last Rows
Dim lastRow_ws1 As Long
Dim lastRow_ws2 As Long
lastRow_ws1 = ws_1.Range("A" & Rows.Count).End(xlUp).Row 'if you need, adjust column to find last row
lastRow_ws2 = ws_2.Range("B" & Rows.Count).End(xlUp).Row 'if you need, adjust column to find last row
'*******************************************
For i = lastRow_ws2 To 2 Step -1
For j = 1 To lastRow_ws1
Dim keySearch As String
Dim keyFind As String
keySearch = ws_2.Cells(i, 2).Value
keyFind = ws_1.Cells(j, 1).Value
If keySearch = keyFind Then
'MsgBox keySearch & " " & keyFind & " yes"
ws_2.Cells(i, 2).Value = ws_1.Cells(j, 2).Value
GoTo next_i
End If
Next j
ws_2.Rows(i).EntireRow.Delete
next_i:
Next i
End Sub

Related

VBA: How can i select the cell in a row which matches a variable's value?

I have 2 sheets. Sheet1 has 2 rows: column names and values.
Sheet 2 is a master sheet with all the possible column names in. I need to copy the values from sheet 1 into their appropriate column.
I think i can do this via a match function, and so far i have this:
Sub dynamic_paste()
Dim Columnname As String
Dim inputvalue As String
Dim starter As Integer
Dim i As Integer
starter = 0
For i = 1 To 4
'replace 4 with rangeused.rows.count?
Sheets("sheet1").Select
Range("a1").Select
ActiveCell.Offset(0, starter).Select
Columnname = ActiveCell
'sets columnname variable
ActiveCell.Offset(1, 0).Select
inputvalue = ActiveCell
'sets inputname variable
Sheets("sheet2").Select
'**Cells(0, WorksheetFunction.Match(Columnname, Rows(1), 0)).Select**
Range("a1").Offset(1, starter).Value = inputvalue
'inputs variable in the next cell along
starter = starter + 1
Next
End Sub
I need to find out how to use my columnname variable as the matching value, and then offset down to the first row that is empty - then change the value of that cell to the variable called inputvalue.
For extra points: I need to make sure the code doesnt break if they dont find a matching value, and if possible put any values that dont match into the end of the row?
What about this:
Dim LR As Long, X As Long, LC As Long, COL As Long
Dim RNG As Range, CL As Range
Option Explicit
Sub Test()
LR = Sheets(2).Cells.SpecialCells(xlCellTypeLastCell).Row 'Get last used row in your sheet
LC = Sheets(2).Cells(1, Sheets(2).Columns.Count).End(xlToLeft).Column 'Get last used column in your sheet
Set RNG = Sheets(2).Range(Sheets(2).Cells(1, 1), Sheets(2).Cells(1, LC))
'Loop through all the columns on your sheet with values
For X = 1 To Sheets(1).Cells(1, Sheets(1).Columns.Count).End(xlToLeft).Column
Set CL = RNG.Find(Sheets(1).Cells(1, X).Value, lookat:=xlWhole)
If Not CL Is Nothing Then
COL = CL.Column
Sheets(2).Cells(LR + 1, COL).Value = Sheets(1).Cells(2, X).Value 'Get the value on LR offset by 1
Else
Sheets(2).Cells(1, Sheets(2).Cells(1, Sheets(2).Columns.Count).End(xlToLeft).Column).Value = Sheets(1).Cells(1, X).Value
Sheets(2).Cells(LR + 1, Sheets(2).Cells(1, Sheets(2).Columns.Count).End(xlToLeft).Column).Value = Sheets(1).Cells(2, X).Value
End If
Next X
End Sub
This way you will avoid using select. Which is very recommandable!
This is Sheet1:
This is Sheet2:
This is the code:
Option Explicit
Sub DynamicPaste()
Dim col As Long
Dim wks1 As Worksheet: Set wks1 = Worksheets(1)
Dim wks2 As Worksheet: Set wks2 = Worksheets(2)
For col = 1 To 3
Dim currentRow As Long
currentRow = WorksheetFunction.Match(wks2.Cells(1, col), wks1.Columns(1))
wks2.Cells(2, col) = wks1.Cells(currentRow, 2)
Next col
End Sub
This is Sheet2 after the code:
This is a must-read - How to avoid using Select in Excel VBA

Loop through worksheets and set values

I am writing the Sheet names and assigning progress in front of it (adjacent cell) from that sheet.
Suppose sheet name is sheet1, sheet2 ...
I am trying to write
Sheet1 B50 of sheet1
Sheet2 B50 ofsheet2
Sub LoadSummarySheet()
Dim row, i, col As Integer
row = 5
col = 3
Range("C5:C15").ClearContents
For i = 1 To Sheets.Count
If Application.Sheets(i).Name <> "TRACKER" And Application.Sheets(i).Name <> "Sheet1" And Application.Sheets(i).Name <> "PROGRESS" Then
Cells(row, col).Value = Application.Sheets(i).Name
row = row + 1
Range(Cells(row, col + 1)).Value = Application.Sheets(i).Range("B50").Value
End If
Next
maybe you're after something like this (explanations in comments)
Sub LoadSummarySheet()
Dim row As Long, col As Long
row = 5
col = 3
Range("C5:C15").ClearContents
Dim forbiddenNames As String
forbiddenNames = "TRACKER,Sheet1,Sheet2,PROGRESS" 'list sheet names you don't want to be processed
Dim sht As Worksheet
For Each sht In Worksheets 'loop through currently active workbook sheets
If InStr(forbiddenNames, sht.Name) = 0 Then 'if current sheet name is not "forbidden"
Cells(row, col).Value = sht.Name
row = row + 1
Cells(row, col + 1).Value = sht.Range("B50").Value
End If
Next
End Sub
all this assumes that the macro is being run when Summary Sheet is the active one
if this can be not the case then you can assure to write in the proper sheet as follows:
Sub LoadSummarySheet()
Dim row As Long, col As Long
row = 5
col = 3
Range("C5:C15").ClearContents
Dim forbiddenNames As String
forbiddenNames = "TRACKER,Sheet1,Sheet2,PROGRESS" 'list sheet names you don't want to be processed
Dim sht As Worksheet
With Worksheets("TRACKER") ' reference wanted "summary" sheet (change TRACKER" to your actually "summary" sheet name)
For Each sht In Worksheets 'loop through currently active workbook sheets
If InStr(forbiddenNames, sht.Name) = 0 Then 'if current sheet name is not "forbidden"
.Cells(row, col).Value = sht.Name ' preface a dot (.) to reference referenced object (i.e. 'Worksheets("TRACKER")' in this case)
row = row + 1
.Cells(row, col + 1).Value = sht.Range("B50").Value ' preface a dot (.)
End If
Next
End With
End Sub

Comma Delimitting values in a new created column based on a matching condition

I have a value in column A on the transactions sheet which contains an Identifier for a Deal.
To be able to find out the customer information for this Deal I look in another sheet called Deal Information. Here there is a value in Column F which matches a value in Column A on the transactions sheet. Although on the Deal Information sheet it lists all the customers who are part of this deal as well as a unique identifier for each of the customers.
On the transactions sheet I have created a new column where by I want to display the list of ID's associated to a particular deal in comma delimited format if possible if not then a space will be good too.
transactions data:
Column A:ID Column: AA: BID Multiple
1 ?
2 ?
3 ?
4 ?
Roots data:
Column C: ID Column: D: BID
1 100
1 200
1 300
2 101
Expected Result in transaction table based on example.
Column A ID Column AA: BID Multiple
1 100,200,300
2 101
3 ?
4 ?
Sub test()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Worksheets("Roots")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim valuesArr()
valuesArr = ws.Range("F2:G" & lastRow) ' 1 TO 4, 1 TO 2
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim valuesString As String
Dim currValue As Long
Dim currRotation As Long
Dim index As String
For currRotation = LBound(valuesArr, 1) To UBound(valuesArr, 1)
index = valuesArr(currRotation, 1)
currValue = CStr(valuesArr(currRotation, 2))
If Not dict.Exists(index) Then
dict.Add index, currValue
Else
dict(index) = dict(index) & ";" & currValue
End If
Next currRotation
Dim wsTarget As Worksheet
Dim lastRowTarget As Long
Set wsTarget = ThisWorkbook.Worksheets("transactions")
lastRow = wsTarget.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim valuesArr2()
valuesArr2 = wsTarget.Range("A2:AA" & lastRow)
Dim testValue As String
For currRotation = LBound(valuesArr2, 1) To UBound(valuesArr2, 1)
testValue = dict(CStr(valuesArr2(currRotation, 1)))
If testValue = vbNullString Then testValue = "?"
valuesArr2(currRotation, 27) = testValue
Next currRotation
wsTarget.Range("A2").Resize(UBound(valuesArr2, 1), UBound(valuesArr2,
27)) = valuesArr2
End Sub
This does an unordered, for the original posting . Assumes data starts in row 2 and has layout as shown below.
Column D being where the concatenated string is output.
*Please note repeated edits to the original question may mean code will no longer fit the stated requirements.
Option Explicit
Sub test()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Worksheets("Roots")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim valuesArr()
valuesArr = ws.Range("A2:B" & lastRow) ' 1 TO 4, 1 TO 2
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim currValue As Long
Dim currRotation As Long
Dim index As String
For currRotation = LBound(valuesArr, 1) To UBound(valuesArr, 1)
index = valuesArr(currRotation, 1)
currValue = CStr(valuesArr(currRotation, 2))
If Not dict.exists(index) Then
dict.Add index, currValue
Else
dict(index) = dict(index) & ";" & currValue
End If
Next currRotation
Dim wsTarget As Worksheet
Dim lastRowTarget As Long
Set wsTarget = ThisWorkbook.Worksheets("transactions")
lastRow = wsTarget.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim valuesArr2()
valuesArr2 = wsTarget.Range("A2:D" & lastRow)
Dim testValue As String
For currRotation = LBound(valuesArr2, 1) To UBound(valuesArr2, 1)
testValue = dict(CStr(valuesArr2(currRotation, 1)))
If testValue = vbNullString Then testValue = "?"
valuesArr2(currRotation, 4) = testValue
Next currRotation
wsTarget.Range("A2").Resize(UBound(valuesArr2, 1), UBound(valuesArr2, 2)) = valuesArr2
End Sub
Edited as per OP's amended input and output columns
as per your examples, IDs are consecutive in Roots sheet
so you may go as follows
Sub main()
Dim cell As Range
With Worksheets("transactions") 'reference "transaction" sheet
For Each cell In .Range("A2", .Cells(.Rows.Count, "A").End(xlUp)) 'loop through referenced sheet column A cells from row 2 down to last not empty one
cell.Offset(, 26).value = GetIDDeals(cell.value) 'write in current cell offset 26 columns (i.e. column AA) the value of the BID
Next
End With
End Sub
Function GetIDDeals(ID As Variant) As String
With Worksheets("Roots")
With .Range("C1", .Cells(.Rows.Count, "C").End(xlUp)) 'reference its column C cells from row 1 (header) down to last not empty one
.AutoFilter Field:=1, Criteria1:=ID ' filter referenced cells on 1st column with passed ID content
Select Case Application.WorksheetFunction.Subtotal(103, .Columns(1)) 'let's see how many filtered cells
Case Is > 2 'if more than 2, then we have more than 1 filtered value, since header gets always filtered
GetIDDeals = Join(Application.Transpose(.Offset(1, 1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).value), ",")
Case 2 'if two filtered cells, then we have 1 filtered value, since header gets always filtered
GetIDDeals = .Offset(1, 1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).value
End Select
End With
.AutoFilterMode = False
End With
End Function

How can i copy non matching numbers in vba

Im trying to compare two sheets which is sheet1 and sheet2 and print values in sheet3. When i am comparing between sheet1 and sheet2 and looking for non matching numbers, somehow my loop doesn't stop and lots of time its printing the samenumber. Here is my code but is there any other ways i can find non matching numbers between two sheets and paste it into sheet3.
lastrow1 = Sheets("Sheet1").UsedRange.Row - 1 + Sheets("Sheet1").UsedRange.Rows.Count
lastrow2 = Sheets("Sheet2").UsedRange.Row - 1 + Sheets("Sheet2").UsedRange.Rows.Count
a = 1
b = 1
c = 1
For i = a To lastrow1
For ii = b To lastrow2
If Worksheets("Sheet1").Cells(i, 1) <> Worksheets("Sheet2").Cells(ii, 1) Then
Worksheets("Sheet3").Range("A" & x) = Worksheets("Sheet1").Cells(i, 1)
x = x + 1
End If
Next ii
Next i
Note: the below code checks column A in Sheet1 against column A in Sheet2. Then, the Main() calls the same code with a reverse order so all the numbers in Sheet2 in column A are checked against Sheet1 column A. If you only want to see the values that are in Sheet1 but not in Sheet2 comment out the second call to PrintNonMatching in Main()
Sub Main()
PrintNonMatching "Sheet1", "Sheet2", "Sheet3"
PrintNonMatching "Sheet2", "Sheet1", "Sheet3"
End Sub
Sub PrintNonMatching(arg1 As String, arg2 As String, arg3 As String)
Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet
Set sh1 = Sheets(arg1): Set sh2 = Sheets(arg2): Set sh3 = Sheets(arg3)
Dim match As Boolean
For Each c1 In sh1.Range("A1:A" & sh1.Range("A" & Rows.Count).End(xlUp).Row)
For Each c2 In sh2.Range("A1:A" & sh2.Range("A" & Rows.Count).End(xlUp).Row)
If c1 = c2 Then match = True
Next
If Not match Then
sh3.Range("A" & sh3.Range("A" & Rows.Count).End(xlUp).Row + 1) = c1
End If
match = False
Next
End Sub

VBA how to loop from the first cell/column (Force it)

Below are my codes, I am trying to force the checking to start from the first cell, but it doesn't work. Can anyone advise me on that. Thanks
I am trying to do checking on the names which is on the 3rd column of Workbook A and compare it with the other column in another workbook. Upon match of the string, it will copy certain cells to the desalinated column
Sub copyandpaste()
Set From_WS = Workbooks("copy_data2").Worksheets("Data")
Set To_WS = Workbooks("Book1").Worksheets("Sheet1")
Dim v1 As String
Dim v2 As String
Dim diffRow As Long
Dim dataWs As Worksheet
Dim copyWs As Worksheet
Dim rowData As Long
Dim totRows As Long
Dim lastRow As Long
Dim result As String
Dim row_no As Integer
Dim Name As Range
Dim Namelist As Range
diffRow = 1 'compare
Set dataWs = Worksheets("Data")
Set copyWs = Worksheets("Diff")
For Each c In Worksheets("Data").Range("C2:C10")
If c.Value <> "" Then
v1 = c
End If
For Each d In Workbooks("Book1").Worksheets("Sheet1").Range("B2:B10")
If d.Value <> "" Then
v2 = d
End If
With From_WS.Cells(1, 2).CurrentRegion
Total_Rows = .Rows.Count
Total_Columns = .Columns.Count
End With
Set mycellA = From_WS.Range("C:C")
Set mycellB = To_WS.Range("B:B")
Copy = False
' With Sheets("copy_data2")
' lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
'find first row
'column1 = Range("A2").End(xlToRight).Column
'For row_no = 1 To 10
'=========================================================================
Set Namelist = dataWs.Range("A1:A" & dataWs.Cells(Rows.Count, "A").End(xlUp).Row)
'Now loop through all the cells in the range
'For Each Name In Namelist.Cells
mynumber = 1
For Each Name In Namelist
'=======================================================================
If v1 = v2 Then
'select sheet
Sheets("Data").Select
'ActiveCell.Select 'select active cell
ActiveCell.Interior.ColorIndex = 36 'color the cell
'copy active cell same row
ActiveCell.Range("A1:F1").Copy
ActiveCell.Interior.ColorIndex = 50 'color the cell
'Paste file destination
Sheets("Diff").Select
Sheets("Diff").Range("A2").Select
'Paste Active
ActiveSheet.Paste
ActiveCell.Interior.ColorIndex = 37 '<< Colored Blue
'==================================================================
'select sheet
Sheets("Data").Select
'ActiveCell.Select 'select active cell
ActiveCell.Interior.ColorIndex = 36 'color cell Yellow
'result = ActiveCell.EntireRow.copy
'copy active cell same row
ActiveCell.Range("H1:J1").Copy
'Paste file destination
Sheets("Diff").Select
'Paste cell destination
Sheets("Diff").Range("G2").Select
'Paste Active
ActiveSheet.Paste
mynumber = mynumber + 1
End If
Next Name
Next d
Next c
End Sub
This is the second function, to count and go through the rows.
Sub RoundToZero1()
For Counter = 1 To 20
Set curCell = Worksheets("Data").Cells(Counter, 3)
If Abs(curCell.Value) < 0.01 Then curCell.Value = 0
Next Counter
End Sub
Update Question:
I have the code below, I need to make the column A to be incremental. Anyone have suggestion how to achieve that?
Sheets("Diff").Range("A").Select
The line Set selectedCell = selectedCell + 1 throws an error when I run it and doesn't appear to do anything in the code, if that is the case you should comment it out or delete it.
Also I think you need to change
Else
If IsEmpty(Cells(i, 1)) = True Then 'if cells in column "A" is empty then stop
to
ElseIf IsEmpty(Cells(i, 1)) = True Then 'if cells in column "A" is empty then stop
As it stands you have an extra open If statement.