Get to know whether a cell is inside a range - vba

I'm trying to make a code which does something if a cell is in a range, i've tried this:
For i = 1 To lastrow
If Not IsEmpty(wsdata.Cells(i, 3)) And Not IsEmpty(wsdata.Cells(i, 4)) Then
If Not Application.WorksheetFunction.Match(range("ISINS").Value, Cell(i,3) Then
MsgBox ("Not in the list")
Else
MsgBox ("In the list")
End If
End If
Next i
But obviously did not work! I've also tried with the Interest function like this:
If Intersect(range("ISINS"),Cells(i,3)) Is Nothing Then
it runs but it doesn't find any value that isn't in the range however there are!
I created a range so that i don't use Cells, but the error remains.
ISINS is juste the name of my range in excel, it could also be A:A.
Thank you for your help!

Related

Setting variables VBA

complete novice here
I started some VBA a few days ago, I have simple question but cant seem to find what I am doing wrong.
I am trying to make a button which will take the coordinates of the active cell and compare them to another worksheet to retrieve a specific value from another table.
I set variables to the active cell column and row, I want to do this so I can later compare these locations to another worksheet and get the value at a specified position on another worksheet.
So far I have written simply what I could find on the internet as I have no formal training.
The msgbox at the end is just to test whether or not it actually picks up the reference.
Sub CommandButton1_Click()
Dim Arow As Range
Dim Acol As Range
Set Arow = Worksheets("Sheet1").Range(ActiveCell.Row)
Set Acol = Worksheets("Sheet1").Range(ActiveCell.Column)
MsgBox (Arow)
End Sub
So far I have error run-time error '1004' Application defined or object defined error highlighting the 4th Row. If anyone could help me solve this or redirect me to some help it would be much appreciated.
I think this won't work, you should put there
Set arow = Worksheets("Sheet1").Range(ActiveCell.Row & ":" & ActiveCell.Row)
Putting there simply number won't work. For the column, you should put there somethong like C:C. For getting letter of column, see this qestion: Function to convert column number to letter?
For more information about Range property, please see official documentation https://msdn.microsoft.com/en-us/library/office/ff836512.aspx.
The thing is, that you have to supply either the address in so called A1 reference, which is "A1", or "$A$1" or name of cell, etc, or you have to supply two Range objects, such as two cells Worksheets("Sheet1").Range(Worksheets("Sheet1").Cells(1,1), Worksheets("Sheet1").Cells(2,2)), which defines area starting with upper-left corner in first parameter and lower right in second parameter.
ActiveCell.Row and ActiveCell.Column returns you some Integer value representing number of row and column, i.e. if you point cell B4, ActiveCell.Row would return 4, and ActiveCell.Column gonna return 2. An Range() property need as an argument whole adress for some range, i.e. Range("C6") or Range("G3:J8").
When you have your column as a number, you can use Cells() property for pointing first and last cell in your range, i.e. Range(Cells(2, 4), Cells(6, 8) would be the same range as Range("D2:H6").
Following this, one of the ways that you can do what you have described is:
Sub CommandButton1_Click()
Dim Rng As Range
Set Rng = Worksheets("Sheet1").Cells(ActiveCell.Row, ActiveCell.Column)
End Sub
Now you have under variable Rng an Range of the same coordinates as ActiveCell, but in Sheet1. You can pass some value into i.e Rng.Value = "Hello World", paste something with Rng.PasteSpecial xlPasteAll etc.
if you want the value from other sheet at the same location as activeCell, use this code,
Private Sub CommandButton1_Click()
valueFromOtherSheet = Sheets("Sheet2").Range(ActiveCell.Address)
MsgBox (valueFromOtherSheet)
End Sub
Like the others have said, it's just about knowing your variable types. This is another way you could achieve what you want
Sub CommandButton1_Click()
Dim Acell As Range
Set Acell = Worksheets("Sheet2").Range(ActiveCell.Address)
MsgBox "Value on ActiveSheet: " & ActiveCell.Value & vbNewLine & _
"Value on Sheet2: " & Acell.Value
End Sub
Thank you everyone for the help and clarification, In the end I was able to come up with some code that seems to do what I need it to.
Private Sub CommandButton1_Click()
Dim cabDate As Range
Dim searchCol As Integer
Dim newindex As Range
Set cabDate = WorksheetFunction.Index(Range("A1:O9999"), ActiveCell.Row, 2)
searchCol = ActiveCell.Column
Set newindex = WorksheetFunction.Index(Worksheets("Deadlines").Range("A1:O9999"), cabDate.Row, searchCol)
MsgBox (newindex)
End Sub
I wasn't aware about conflicting data types so thank you all for the assistance.

"Runtime Error '1004'" Command cannot be used on multiple selections

I put together a VBA code to take the values off a form on one worksheet and insert them into another worksheet without the blank cells inbetween, then clear the original form.
However, I run into the error "Runtime Error 1004: Command cannot be used on multiple selections" and cannot figure out what is causing it. After a little research, it seems that saving and reopening the workbook makes this error go away, but not always.
Any ideas?
Sub DataEntry()
'--- Find rows that contain any value in column G or H and copy them
Dim cell As Range
Dim selectRange As Range
For Each cell In ActiveSheet.Range("G3:H90")
If (cell.Value <> "") Then
If selectRange Is Nothing Then
Set selectRange = cell
Else
Set selectRange = Union(cell, selectRange)
End If
End If
Next cell
selectRange.EntireRow.Select
selectRange.EntireRow.Copy
'Paste copied selection to the worksheet 'Data' on the next blank row
Sheets("Data").Range("A65536").End(xlUp).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues
'Delete content of rows after copy and paste
Union(Range("G3:G150"), Range("H3:H150")).ClearContents
The problem seems to be that the EntireRow property is becoming a variant and not a range. I initially tried to fix this by just declaring a variable as a Range, but this didn't work either. However, by doing the original Union on rows instead of cells, I was able to get this to work.
Sub DataEntry()
'Find rows that contain any value in column G or H and copy them
Dim cell As Range
Dim selectRange As Range
Dim rowRange As Range
For Each cell In ActiveSheet.Range("G3:H90")
If (cell.Value <> "") Then
If selectRange Is Nothing Then
Set selectRange = cell.EntireRow
Else
Set selectRange = Union(cell.EntireRow, selectRange)
End If
End If
Next cell
'No need to select anything here, just copy.
selectRange.Copy
.....
I'm not entirely sure why this is happening, but this fixed it for me.
EDITED because the original fix did not work.

Excel VBA iterate over all used cells and substitute their values

This is my first time ever working with VBA and Excel and my problem is probably caused by a big lack of knowledge on my part.
I have a one column list of city names (containing 800 items, hence I'm looking to automatically replace them) and some chunks of text in which the term "cityname" occurs multiple times and needs to be replaced by the correct city name, which in my setup would be the value of the first column cell in the same row.
So I found this: How to iterate through all the cells in Excel VBA or VSTO 2005
and found the InStr and Substitute functions by looking through the Excel VBA reference.
Using the iteration like this works fine:
Sub MySubstitute()
Dim cell As Range
For Each cell In ActiveSheet.UsedRange.Cells
If InStr(cell.Value, "cityname") > 0 Then
MsgBox "Hello World!"
End If
Next cell
End Sub
I get a message box for every "cityname" in my sheet (a test sheet with only 2 rows).
However when I add what I really want to achieve I get a Runtime Error (1004):
Sub MySubstitute()
Dim cell As Range
For Each cell In ActiveSheet.UsedRange.Cells
If InStr(cell.Value, "cityname") > 0 Then
cell.Value = WorksheetFunction.Substitute(cell.Value, "cityname", Cells(cell.Row, A))
End If
Next cell
End Sub
So I guess something in that line is wrong but I can't figure out what. Any hints to what my mistake is are appreciated, thanks :)
You can use the Range.Replace Method and replace all at once no need to iterate.
Sub MySubstitute()
Dim rng As Range
Set rng = ActiveSheet.UsedRange.Cells
rng.Replace "cityname", "correctcityname", xlPart
End Sub
You should change:
cell.Value = WorksheetFunction.Substitute(cell.Value, "cityname", Cells(cell.Row, A))
by
cell.Value = WorksheetFunction.Substitute(cell.Value, "cityname", Cells(cell.Row, 1))

Type Mismatch Run Time error 13 for excel VBA

I have requirement to write some function which will accept Range as input and I need to return value of first non empty cell. I have tried in one excel sheet and finding non empty cell was working fine. When I try with my project excel file it was not working. Basically for Find method of Range I am getting runtime error 13. Check below code and let me know what is the issue. I have noticed even in when I put Range.Row property it make "Row" as row in code ( in below code see Target.row).
Sub Btn_GenerateChartClicked()
If Range("E9") = "Scatter" Then
MsgBox "Scatter is selected"
Dim str As String
Dim rng As Range
Set rng = Range("B12:I12")
str = FindNonEmptyCellFromRange(rng)
' MsgBox str
Else
MsgBox "Bar is selected"
End If
End Sub
Function FindNonEmptyCellFromRange(Target As Range) As String
Dim ws As Worksheet
Set ws = Sheets("Benchmarking_Project")
Dim foundRange As Range
Set foundRange = Target.Find("*", Cells(Target.row, 1), xlFormulas, , xlByColumns, xlPrevious)
'Dim cellValue As String
'cellValue = foundRange.Value
FindNonEmptyCellFromRange = "Test"
'cellValue
End Function
You can't find a target.
use Cell.Find and then once you have the cell selected use Target.Address to get the address of the cell
So your CellValue would become:
CellValue = FoundRange.Address
Although, your question is a little vague as your not doing anything practicle with this UDF anyway
Your question does not provide enough details and the function call does not return the non empty cell. Whatever happens your function will return only Test.
Anyway when going through the code, your range has a single row in it.
Issue seems to be with the following code
Set foundRange = Target.Find("*", Cells(Target.row, 1), xlFormulas, , xlByColumns, xlPrevious)
There is no need to specify the After Parameter Cells(Target.row, 1)
After parameters corresponds to the position of the active cell when a search is done from the user interface. Notice that After must be a single cell in the range. Remember that the search begins after this cell; the specified cell isn’t searched until the method wraps back around to this cell. If you do no specify this argument, the search starts after the cell in the upper-left corner of the range.
Try to change that code to
Set foundRange = Target.Find("*", , xlFormulas, , xlByColumns, xlPrevious)
The following code may work for you
Sub Btn_GenerateChartClicked()
If Range("E9") = "Scatter" Then
MsgBox "Scatter is selected"
Dim str As String
Dim rng As Range
Set rng = Range("B12:I12")
str = GetFirstNonEmptyCell(rng)
' MsgBox str
Else
MsgBox "Bar is selected"
End If
End Sub
Public Function GetFirstNonEmptyCell(Target As Range)
Dim startCell As Range, firstNonEmptyCell As Range
For Each c In Target.Cells
If Trim(c.Value) <> "" Then
Found_Address = c.Address
Exit For
End If
Next
GetFirstNonEmptyCell = Found_Address
End Function
Ian your suggestion about not to use Cells(Target.Row,1) in Find method is right. I got my mistake. In that I have put column index as 1 but it should be 2 because my selected range is from Column B which means column index 2. So I got actually error because there is no column index 1 in that range. So if I put 2 instead of 1 in above mentioned call then it is working fine. Yes your right that I was not returning actually value of last non empty cell as that was my R&D code I kept changing it. So while posting it I forgot to change it. Thank you all for your reply

Locating Cell Values in Excel VBA

Using: Excel 2007/Win 7
First, I created a subroutine to find the dynamic range of a worksheet called 'WIP':
Sub GetWIPRange()
Dim WIPrng1 As Range
Dim WIPrng2 As Range
Sheets("WIP").Activate
Set WIPrng1 = Cells.find("*", [a1], , , xlByRows, xlPrevious)
Set WIPrng2 = Cells.find("*", [a1], , , xlByColumns, xlPrevious)
If Not WIPrng1 Is Nothing Then
Set WIPrng3 = Range([a1], Cells(WIPrng1.Row, WIPrng2.Column))
Application.Goto WIPrng3
Else
MsgBox "sheet is blank", vbCritical
End If
End Sub
Now I want to find a given contract number within the range defined above:
Sub find()
Dim find As Long
find = Application.WorksheetFunction.Match("545499", Range(WIPrng3.Parent.Name & "!" & WIPrng3.Address), 0)
MsgBox "Found at row : " & find
End Sub
But the error I get from the code above is:
Run-time error '91':
Object variable With block variable not set.
How can I fix this code so that it returns the row number of the value I'm seeking?
Is there a more efficient way of finding cell values using VBA? For example, if I have many worksheets and I want to search all worksheets and return a value's specific row number and worksheet location.
Many thanks!
Where is WIPrng3 defined? Is it defined as Public? The problem is that WIPrng3 has gone out of scope by the time you run "find" and is therefore Nothing. You can check for Nothing in your "find" code and run the Get procedure if needed. Like this
Sub find()
Dim find As Long
If WIPrng3 Is Nothing Then GetWIPRange
find = Application.WorksheetFunction.Match("545499", Range(WIPrng3.Parent.Name & "!" & WIPrng3.Columns(1).Address), 0)
MsgBox "Found at row : " & find
End Sub
Two things to note: If WIPrng3 returns a multicolumn range, MATCH will fail with a 1004 error. MATCH only works on a single column or row. In the example above, I restricted WIPrng3 to the first column in the MATCH function to avoid this. You didn't have this in your code.
Another thing is that you're looking for the text string "545499", not the number 545499. If your range contains the number and not the string, you'll get an error. You can trap that error with an On Error statement and handle appropriately.
Finally, I don't see the advantage to defining WIPrng3 (but I can't see the whole of what you're doing). You could easily use
Sub Find2()
Dim lRow As Long
On Error Resume Next
lRow = Application.WorksheetFunction.Match("545499", Sheets("WIP").UsedRange.Columns(1), 0)
If lRow > 0 Then
'add where the used range starts in case it's not row 1
MsgBox "Found at row : " & lRow + Sheets("WIP").UsedRange.Cells(1).Row - 1
Else
MsgBox "Not found"
End If
End Sub
You might end up looking through a larger range, but it won't appreciably affect performance.
I added the On Error in this example so you could see how it works. Don't put the On Error in there until you've tested it because it will mask all the other errors.
Charles Williams did some nice analysis on finding efficiency here http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/