Match in two different sheet and offset - vba

I am writing the following code that finds a match from one worksheet (Sheet2) and pastes values into (sheet2).
So far the code targets those names that have "accepted" as offset values. it loops through looking for a match and displaying it. However i would like to also select the offset values and paste them in sheet1 if possible. THis is where I am getting confused please help, where to take my code from here?
Sheet1
Column a , b
5 Jim Accepted
6 Bob Rejected
7 Tim Accepted
Sheet 2
Column d e f g
Jim 40 0.4
Bob 78 58
Tim 36 45
Sub check()
Dim i As Long, lastrow As Long, myval As Long
Dim agentname As String
Dim sh2 As Worksheet
Dim val As String
Dim findstr As String
Dim rng As Range
Set sh2 = Sheets(2)
lastrow = Cells(Rows.Count, "A").End(xlUp).Row
For i = 1 To lastrow
agentname = Cells(i, 1).Offset(, 1).Value
If Cells(i, 1) = "Accepted" And Not IsEmpty(Cells(i, 1)) Then
'For i = 1 To sh2.Range("b2:b9")
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("b1:b9"), 0)
findstr = agentname
MsgBox agentname
End If
Next i
End Sub

Few problems -
agentname = Cells(i, 1).Offset(, 1).Value
This appears to be looking in the wrong column. It's returning "Accepted" or "Rejected" instead of the name. So remove the offset - you can specify what column you want directly, no need to offset. Keep it simple. (You don't even need the .Value, it's assumed)
agentname = Cells(i,1)
Now this is doubly confusing--
If Cells(i, 1) = "Accepted" And Not IsEmpty(Cells(i, 1)) Then
Again referring to the wrong column, we want column 2 here. And beyond that, if it is 'accepted', how could it also be empy? So we want:
If Cells(i, 2) = "Accepted" then
Ok, so next -
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("b1:b9"), 0)
What is myval? Not a descriptive name, that can confuse you when you come back to your code. You're trying to match the agent name you saved, and specifying the range and sheet is on, that's great. Are the names really in column B? Without knowing the exact layout i'll assume they're on sheet 2 column A instead, that's easier for me. So now it's working when it finds a name, but a weird function of Worksheetfunction means it'll break if it can't find anything. So we'll wrap it in some error handling.
On Error Resume Next
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
If Err = 0 Then
findstr = agentname
MsgBox agentname
End If
On Error GoTo 0
I'm a little short on time, so a few more comments-
1.) You named your worksheet2 , that's fantastic. You should do it for worksheet1 too. In fact, go further and specify the workbook too. It'll save a lot of headache.
2.) You need to indent properly, maybe it just messed up when you posted here but those For loops and If statements need to be indented or you'll get a headache the next time you try to figure out what you were doing
3.) Use descriptive names, especially if you're writing a longer script that does a lot of things like this one.
4.) This is an opinion, but I think you should wait to declare your variables until you're about to use them. Again increased readibility. (And look into camel-Case for naming your variables, it's cosmetic, but...anyway I think it looks better)
Setup I was using - Sheet1:
A B
Tim Accepted
Tom Rejected
Sheet2:
A B C
Tim 40 30.1
Tom 21 15.5
Jeff 18 31.3
Code:
Sub check()
Dim sh1 As Worksheet: Dim sh2 As Worksheet
Set sh1 = Sheets(1)
Set sh2 = Sheets(2)
Dim val As String
Dim findstr As String
Dim lastrow As Long
lastrow = sh1.Cells(Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To lastrow
Dim agentname As String
agentname = sh1.Cells(i, 1)
If sh1.Cells(i, 2) = "Accepted" Then
On Error Resume Next
Dim myval As String
myval = Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
If Err = 0 Then
findstr = agentname
MsgBox agentname
End If
On Error GoTo 0
End If
Next i
End Sub

Instead of matching i have used the vlookup function this return the value in sheet2 matching the name on sheet1. This provides the basics of what I was trying to achieve. The code Acantud provided laid the foundation
Sub check()
Dim sh1 As Worksheet: Dim sh2 As Worksheet
Set sh1 = Sheets(1)
Set sh2 = Sheets(2)
Dim val As String
Dim findstr As String
Dim lastrow As Long
lastrow = sh1.Cells(Rows.Count, "A").End(xlUp).Row
Dim i As Long
For i = 1 To lastrow
Dim agentname As String
agentname = sh1.Cells(i, 1)
If sh1.Cells(i, 2) = "Accepted" Then
On Error Resume Next
Dim myval As String
Dim myval1 As String
myval = Application.WorksheetFunction.VLookup(agentname, sh2.Range("A1:E13"), 3, False)
myval1 = Application.WorksheetFunction.VLookup(agentname, sh2.Range("A1:E13"), 5, False)
'Application.WorksheetFunction.Match(agentname, sh2.Range("A1:A9"), 0)
sh1.Cells(i, 3) = myval
' sh1.Cells(i, 4) = myval1
If Err = 0 Then
findstr = myval
End If
On Error GoTo 0
End If
Next i
End Sub

Related

Find and replace multiple values in Excel using VBA

I'm looking for VBA code to run in Excel to find and replace lots of words.
Basically, it will be a simple Excel file where Sheet1 contains phrases in 1 column which contains names to be replaced (not the whole phrase but one name which might consist of few words). Second sheet2 contains in 1 column values which I need to find in Sheet1 (there might be more than one time when value appears to be found in 1st column) and column which contains translation. I don't need Google API for this because names are very custom.
I came across to the following script but it does nothing basically.
Sub ReplaceValues()
Dim dataSht As Worksheet
Dim editSht As Worksheet
Dim dataRange As Range
Dim dataColumn As Long
Dim editColumn As Long
Dim dataEndRow As Long
Dim editEndRow As Long
'sheet that holds all the values we want to find
Set dataSht = Sheet2
'sheet we want to edit
Set editSht = Sheet1
Dim replaceValue As String
'replace value is empty string
replaceValue = ""
'set the column of the data sheet to A
dataColumn = 1
'set the colmun of the sheet to edit to A
editColumn = 5
dataEndRow = dataSht.Cells(dataSht.Rows.count, dataColumn).End(xlUp).Row
editEndRow = editSht.Cells(editSht.Rows.count, editColumn).End(xlUp).Row
'this is the range of the data that we're looking for
Set dataRange = dataSht.Range(dataSht.Cells(1, dataColumn),
dataSht.Cells(dataEndRow, dataColumn))
Dim count As Long
Dim val As String
For i = 1 To editEndRow
val = editSht.Cells(i, editColumn).Value
count = Application.WorksheetFunction.CountIf(dataRange, val)
If count > 0 And Trim(val) <> "" Then
editSht.Cells(i, editColumn).Value = replaceValue
End If
Next i
End Sub
Finally, I was able to do what I need with a very simple piece of code. Get trained folks!
Sub Test()
Dim Sh1 As Worksheet
Dim Sh2 As Worksheet
Dim FndList, x&
Set Sh1 = Sheets(1)
Set Sh2 = Sheets(2)
FndList = Sh2.Cells(1, 1).CurrentRegion
For x = 1 To UBound(FndList)
Sh1.Cells.Replace What:=FndList(x, 1), Replacement:=FndList(x, 2), LookAt:=xlPart
Next
End Sub
So as I understand correctly you want a list of phrases translated by a dictionary - word by word. The following script should do it - assuming Sheet1 contains the phrases (in column 1 from row 2) and Sheet2 contains the dictionary(column1 for original values, column2 for translations and also from row2 on). The replaced/translated phrases will appear in column2 of Sheet1.
Firstly, in your original code, vba will take Sheet1 and Sheet2 as two undefined variable automatically, hence there's no alert about this. You should use Worksheets() collection to specify the worksheet.
Secondly, you forgot to change the value of replaceValue. Actually, you can put the cell.value into the replace function as a parameter directly. Therefore there is no need to set a variable for this unless you want to make it more readable.
Lastly, if you want to check whether a word is contained or not. Use InStr function. However in your case, using a replace function is good enough. It will replace the word into the translation you wanted, and will do nothing if there is no match to be found.
Sub btn_Click()
Dim cntPhrases As Integer
Dim cntDict As Integer
Worksheets("Sheet1").Activate
cntPhrases = Worksheets("Sheet1").Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count - 1
cntDict = Worksheets("Sheet2").Range("A:A").Cells.SpecialCells(xlCellTypeConstants).Count - 1
MsgBox (cntPhrases)
Dim i As Integer
Dim j As Integer
Dim phrase As String
Dim org As String
Dim rep As String
For i = 2 To cntPhrases + 1
phrase = Cells(i, 1)
For j = 2 To cntDict + 1
org = Worksheets("Sheet2").Cells(j, 1)
rep = Worksheets("Sheet2").Cells(j, 2)
phrase = replace(phrase, org, rep)
Next j
Cells(i, 2) = phrase
Next i
End Sub
You could also do it like this.
Sub main()
Dim Find_text() As String
Dim Replace_text() As String
Dim str As String
str = "test 150 test 160 test 170 test 200 test 220"
Find_text = Split("150 160 170 180 190 200 210 220")
Replace_text = Split("15 16 17 18 19 20 21 22")
For i = 0 To UBound(Find_text)
For j = 0 To UBound(Replace_text)
If InStr(str, Find_text(j)) > 0 Then
str = Replace(str, Find_text(j), Replace_text(j))
End If
Next
Next
MsgBox str
End Sub

Find the texts in Dynamic Range in another sheet

I am creating a VBA application that will find the text that I have entered in a certain range (Should be dynamic, in order for me to input more in the future). With that the entered texts in the range will look for the words in another sheet column:
Example:
And it will look for the words inputted in another sheet.
Dim Main as Worksheet
Set Main = Sheets("Sheet1")
Dim Raw2 as Worksheet
Set Raw2 = Sheets("Sheet2")
LookFor = Main.Range(D8:100)
Fruits = Raw2.Range("G" & Raw2.Rows.Count).End(xlUp).row
For e = lastRow To 2 Step -1
value = Raw2.Cells(e, 7).value
If Instr(value, LookFor) = 0 _
Then
Raw2.Rows(e).Delete
Honestly I am not sure how to proceed. And the mentioned code is just experiment. Desired output is to delete anything in sheet2 except for the rows that contain the words that I have inputted in the "Look for the words". Hope you can help me. Thank you.
This should do the trick :
Sub Sevpoint()
Dim Main As Worksheet
Set Main = Sheets("Sheet1")
Dim Raw2 As Worksheet
Set Raw2 = Sheets("Sheet2")
Dim LooKFoR() As Variant
Dim LastRow As Double
Dim i As Double
Dim j As Double
Dim ValRow As String
Dim DelRow As Boolean
LooKFoR = Main.Range(Main.Range("G8"), Main.Range("G" & Main.Rows.Count).End(xlUp)).Value
LastRow = Raw2.Range("G" & Raw2.Rows.Count).End(xlUp).Row
For i = LastRow To 2 Step -1
ValRow = Raw2.Cells(i, 7).Value
DelRow = True
'MsgBox UBound(LooKFoR, 1)
For j = LBound(LooKFoR, 1) To UBound(LooKFoR, 1)
If LCase(ValRow)<>LCase(LooKFoR(j, 1)) Then
Else
DelRow = False
Exit For
End If
Next j
If DelRow Then Raw2.Rows(i).Delete
Next i
End Sub

Select cells that fit in the range of the counter and concatenate what is selected from the range

I've been working on a Macro that i need to copy, concatenate what has been selected through the counter. e.g. is below
excel snapshot example
so what i want to do is set a count in column c from 1 to "infinite" because each worksheet varies to go up to 10 or hundreds and when the counter hits a value of 1 again to stop concatenate column D what is in the range from 1 to "the last digit it stopped before hitting 1 again" and paste it on a different sheet. I know little to nothing on VBA but I understand the copy and paste to different sheet part. I'm just stuck on the counter and the concatenate part. Here is the code i have so far(i edited it to resemble the example for better reference)
'select counter/concatenate
Sheets(1).Select
Columns("C").EntireColumn
Do
Columns("C").Count
For i = 1 To 9999
Loop While (i <= 1)
If i = 1 Then
select.columns("D")
after the count is where i am stuck. this count is what I've come up with looking at different variations of counters.
I suggest you Forget about column and use just one cell for easier understanding. A cell is a reference that allows you to refer to any other cells on the sheet by using Offsets. You may use two Loops, the outer one crawling the columns, the inner one working downward until it finds 1
Dim i As Long ' note that in VBA integer Overflows at 65535 rows
Dim s As String
Set aCell = Worksheet("Sheet1").Range("D1")
While aCell.Column < 255
i = 0
s = ""
While Not aCell.Offset(i, 0).Value = 1
s = s & aCell.Offset(1, 0).Value
Wend
' paste s somewhere by using range.value = s
Set aCell = aCell.Offset(0, 1)
Wend
By specifying the workbook and worksheet before the range, you may refer to the proper cell without being dependent on the active worksheet or range.
Hope this works for you.
You can try this (not tested):
Dim s As String, firstAddr as String
Dim f as range, iniCell As Range
With Worksheet("MySheet") '<--| change "MySheet" to your actual sheet name
With .Range("C1", .Cells(.Rows.Count, 3).End(xlUp))
Set f = .Find(What:=1, LookAt:=xlWhole, LookIn:=xlValues, After:=.Cells(.Rows.Count, 1))
If Not f Is Nothing Then
firstAddr = f.Address
Set iniCell = f
Set f = FindNext(f)
Do While f.Address <> firstAddr
s = s & Join(Range(iniCell, f.Offset(-1)).Offset(, 1), "")
' here code to paste s somewhere
Set iniCell = f
Set f = FindNext(f)
Loop
End If
End With
End With
Here's one I actually tested, using some random data in columns C and D.
You'll have to modify a little to get exactly where you want the data to go, but should get you in the right direction.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim i As Long
Dim s As String
Dim lastRow As Long
Dim c As Integer
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
lastRow = ws1.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
'This will get an accurate last row
c = 1
For i = 1 To lastRow
s = s & ws1.Cells(i, 4).Value 'Build the string
If ws1.Cells(i + 1, 3).Value = 1 Or ws1.Cells(i + 1, 3).Value = "" Then
ws2.Cells(c, 1).Value = s
s = ""
c = c + 1
'If the next cell to check is 1 or blank, then copy the values to the next cell in order on sheet2
End If
Next
End Sub
Walking through it, lastRow is set using the last row in the sheet with a value in it. Then, c is set to one, although you could set this to the last available row in ws2 using the same process. After that it just steps through the rows from 1 To LastRow building strings and transferring the value to ws2 when it's about to hit a 1.

What is wrong with my VBA IsNumeric function?

I cannot find what is wrong with this segment of code, every time I try to change it to something that I think will work better it shows up as an error. Many thanks in advance for your help!
This is the code, its specifically to do with the use of the isnumeric function and I am using Excel 2016 on a Mac.
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
Set i = 1
Set n = 1
Do While ws1.Cell(i, "F") <> "End"
Num1 = ws1.Cell(i, "F")
If IsNumeric(Num1.value) <> False And Num1 <> ""
Set ws2.Cell(n, "B") = ws1.Cell(i, "F")
n = n + 1
End If
Next i
Perhaps you don't need VBA at all. For a non-vba solution enter this formula in Sheet2 cell B1 and drag down for as many rows as needed (in Sheet1 column F).
=IF(AND(NOT(ISNUMBER(Sheet1!F1)),Sheet1!F1=""),Sheet1!F1,"")
For a VBA solution, I cleaned up your code a bit for many syntax errors that were off. Also, heed the following:
Always use Option Explicit in your modules and declare all variable types
Always qualify objects with variables
(1 and 2 are best practices, but not required. Leaving things out can produce unexpected results).
Option Explicit
'... Sub Name ...
Dim wb as Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim Num1 as Variant
Set wb = ThisWorkbook 'or Workbooks("myBook")
Set ws1 = wb.Sheets("Sheet1")
Set ws2 = wb.Sheets("Sheet2")
Dim i as Long, n as Long
i = 1 'no need to "Set" numerical integers
n = 1
Do While ws1.Cells(i, "F") <> "End"
Num1 = ws1.Cells(i, "F").Value2 'set this to the value2 property of the cell
If Not IsNumeric(Num1) And Num1 <> "" 'remove .Value from variable
ws2.Cells(n, "B").Value = ws1.Cells(i, "F").Value 'set the cells Value property equal to each ... again, Set will not work here
n = n + 1
i = i + 1 'need to increment i as well
End If
Loop 'not Next I, since you are using a Do While Loop

Using cell value to specify the paste location in Excel VBA

I have a table with two rows : the first row contains the locations where the value of the second row should be pasted.
For example :
row 1 : sheet8!D2 sheet6!D2 sheet2!C5
row 2 : apple lemon pEER
So apple should be pasted in sheet 8 cell D8. Lemon should be pasted in sheet6 cell D2. The problem is that the value apple is pasted everywhere (in sheet8!D2, sheet6!D2 and sheet2!C5). How can I correct this?
Sub Sample()
Dim rng As Range
Dim Sh As String, Cl As String
Dim ws As Worksheet
Dim i As Integer
Dim Row1 As String
ncol = Range("A1:F1").Columns.Count
For i = 1 To ncol
Row1 = Range("A1:F1").Cells(1, i).Value
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
Sh = Split(Row1, "!")(0)
Cl = Split(Row1, "!")(1)
Set rng = ThisWorkbook.Sheets(Sh).Range(Cl)
rng.Value = .Range("A2").Value
End With
Next i
End Sub
There are a few issues with your code. First up its good practice to put Option Explicit at the top of each module, this will ensure variables are defined (ncol is not defined).
The following code will fix the problem although it could be tweaked in various ways. The main problem is you don't quite set the referencing ranges correctly, you move through the columns with your loop but always refer back to cell A2. Assuming your input data is on rows 1 and 2 and run from the sheet with that data this will work.
Sub SampleFixed()
Dim rng As Range
Dim Sh As String, Cl As String
Dim ws As Worksheet
Dim i As Integer, ncol As Integer
Dim Row1 As String
ncol = Range("A1:F1").Columns.Count
For i = 1 To ncol
Set ws = ActiveSheet
With ws
Row1 = .Cells(1, i).Value
If Len(Row1) > 0 Then
Sh = Split(Row1, "!")(0)
Cl = Split(Row1, "!")(1)
Set rng = ThisWorkbook.Sheets(Sh).Range(Cl)
'Here you were always refering to cell A2 not moving through the values which was the main problem.
rng.Value = .Cells(2, i).Value
End If
End With
Next i
End Sub