LOOP and nested if statements not working - vba

the code is intended to seek out the "Yes" in "OverExtensions" and will create a new range and determine the maximum value of the new range. For some reason the logic of the code seems alright but I'm getting an empty result and would love the community's input as to where I've went wrong.
Private Sub CommandButton1_Click()
Dim maximum As Double, OverExtension As Range, x As Range
Cells.Interior.ColorIndex = 0
Set OverExtension = Range("D2:D12")
maximum = WorksheetFunction.Max(Range("c2:c12"))
For Each x In OverExtension
If x.Value = Yes Then
If x.Offset(0, -1).Value = maximum Then
x.Cells.Interior.ColorIndex = 22
End If
End If
Next x
End Sub

You nested the if and for blocks in a wrong way.
You have to put the second End If between Next PriceNo and Next OEResult.
Update:
You need just one End If. The first one is wrong because If and Then are in one line.
Besides you have problem with your OEYes and OEResult variables as they are defined but not initialized but as I don't know your intention I also don't know how to solve it.

Related

Checking if data exists and adding it if not

I have two rows containing dates which I am trying to compare and see if they are the same. If not, I want to add the extra data (i.e. row 1 can change and so I want those changes added to row 2). Ive tried looking around and also writing my own loop but I`m getting an error.
UPDATE following the comment, i am still getting an error; "Unable to get the CountIf propety of the worksheetfunction class"
I am wondering if there are any alternatives to check if the data is present somewhere in the second row add add it if not.
I am new to vba and programming in general and any help would be appreciated.
Dim Dates As Range
Set Dates = Range("C23:O23")
Dim hisdate As Range
Set hisdate = Range("C35:O35")
For Each cell In Dates 'this is gonna first add new dates
If WorksheetFunction.CountIf(hisdate, cell) > 0 Then 'do nothing
Else
Set hisdate = Union(hisdate, cell)
End If
Next
As mentioned in the comments, WorksheetFunction.CountIf doesn't work with multi-area ranges. You could write your own countIf-function that loops over all areas (works even if the range is not a multi-area range)
Dim cell As Range
For Each cell In Dates 'this is gonna first add new dates
If MyCountIf(hisdate, cell) <= 0 Then
Set hisdate = Union(hisdate, cell)
End If
Next
Debug.Print hisdate.Address
Function MyCountIf(fullRange As Range, val As Variant)
MyCountIf = 0
Dim r As Range
For Each r In fullRange.Areas
MyCountIf = MyCountIf + WorksheetFunction.CountIf(r, val)
Next
End Function

Count Rows Until Finding Specific String

I am trying to use Excel VBA to count the number of rows until I hit a specific string and set a variable equal to it.
Something like:
Dim i as Integer
i = Worksheets("Scope Phase Document").Range("A1", Range("A1").End(xlDown)).Find("FACTS - What are we measuring?").Count
I know this isn't the correct syntax and I'm probably missing other stuff, but just using the different functions I currently know, this is what I would hope would do the trick. I get
Run-time error '91' saying "Object variable or With block variable not
set
I have tried a few different ways of doing it, but can't figure out a way that doesn't result in an error.
So I want to start at A1 and count all the rows down until I reach the specific string "FACTS - What are we measuring?".
Any help would be greatly appreciated!
I prefer MATCH, but if the match is not found it throws an error. So we need to test for that:
Dim i As Long
i = 0
On Error Resume Next
i = Application.WorksheetFunction.Match("FACTS - What are we measuring?", ActiveSheet.Range("A:A"), 0)
On Error GoTo 0
If i > 0 Then
' do you stuff with i
End If
So you basically want MATCH():
=MATCH("FACTS - What are we measuring?",A:A,0)
It returns the row number of matched string.
Your code is fine except you should use the Row property. The Count property as you have used it will return 1 because the Find method returns one cell (the first cell where a match is found).
Dim i as Integer
i = Worksheets("Scope Phase Document").Range("A1", Range("A1").End(xlDown)).Find("FACTS - What are we measuring?").Row
Like Scott mentioned, if your text is not found, Excel will throw an error.
I'd do this:
Sub rowcounter()
Dim i As Integer
Range("A1").Select
i = 0
Do
Selection.Offset(1, 0).Select
i = i + 1
Loop Until Selection.Value = "FACTS - What are we measuring?"
MsgBox "rows count is " & i
End Sub

Excel VBA - why is my output value placed one cell down than expected?

I have a weird fluke that can be fixed easily, but I'd like to know why it's happening in the first place. I have a subroutine that is spitting out its value one cell down than expected. Here's the code:
Sub Reference()
On Error Resume Next
Dim Output_Row As Long
Output_Row = Range("Table1[Output]").Row
For Each cl In Range("Table1[ID1]")
Range("Table1[Output]").Cells(Output_Row, 1) = Application.WorksheetFunction.Index(Range("Table2[ID2]"), Application.WorksheetFunction.Match(cl, Range("Table2[ID2]"), 0))
Output_Row = Output_Row + 1
Next cl
End Sub
Now this should perform like a VLOOKUP and regurgitate the same ID from Table2 if it matches Table1, otherwise be blank. But this happens whenever I run it:
See how all the outputs are one cell down from where they should be? Now I can redefine Output_Row to say:
Output_Row = Range("Table1[Output]").Row - 1
That realigns the output values in the right spots. But I would like to know how it got wrong in the first place. Any thoughts?
Range.Row always returns the row number relative to the ENTIRE sheet.
On the other hand Range.Cells takes relative values.
So here you are passing an absolute value from Range("Table1[Output]").Row into a function expecting a relative value. The relative value is offset by the position of the table on the sheet AND the table header row Range("Table1[Output]").Cells(Output_Row, 1).
You could also change the location of Output_Row increment
Sub Reference()
On Error Resume Next
Dim Output_Row As Long
For Each cl In Range("Table1[ID1]")
Output_Row = Output_Row + 1
Range("Table1[Output]").Cells(Output_Row, 1) = Application.WorksheetFunction.Index(Range("Table2[ID2]"), Application.WorksheetFunction.Match(cl, Range("Table2[ID2]"), 0))
Next cl
End Sub

If/Else statement for chart

So, I've been stuck in this problem for so many days now. I'm trying to loop the system.array from the data in Excel. I use the if statement that read if the data value from the excel is numeric or not. After that I put elseif statement that change the chart marker style to none if the value is equal to zero. However, no matter what kind of methods that I try, the markers still show on the chart. Here's my code:
Dim A_GTRng As Excel.Range
Dim A_GTArry As System.Array
'Set the range
A_GTRng = excelWS.Range("I2", excelWS.Range("I2").End(Excel.XlDirection.xlDown))
'Read in the values of a range of cells
A_GTArry = CType(A_GTRng.Value, System.Array)
'Looping through the A_GTArry
For x As Integer = 1 To A_GTArry.GetUpperBound(0)
For y As Integer = 1 To A_GTArry.GetUpperBound(1)
Dim A_GT As Object = A_GTArry(x, y)
If IsNumeric(y).Equals(0) Then
'Chart1.Series("A_GT").MarkerSize = 0
'Chart1.Series("A_GT").MarkerColor = Color.Transparent
Chart1.Series("A_GT").MarkerStyle = MarkerStyle.None
ElseIf IsNumeric(y) Then
'Chart1.Series("A_GT").Points.Dispose()
Chart1.Series("A_GT").Points.AddY(A_GT)
Chart1.Series("A_GT").MarkerStyle = MarkerStyle.Diamond
Chart1.Series("A_GT").MarkerColor = Color.Red
Chart1.Series("A_GT").MarkerSize = 7
End If
Next y
Next x
Result from the program above:
Can anyone check if I make some mistake somewhere? I try to solve this problem since the past few days, but did got the result that I want. My brain pretty much fried now. I really need help to solve this. Thank you!
Since y is an Integer by definition in your For loop it will always be numeric.
Therefore this statement will never succeed:
If IsNumeric(y).Equals(0) Then
What exactly are you trying to do? Seems like you've gotten a little bit off course.
Z

Excel VBA Length-1 In a Range

I recently got into Excel macro development after a long time of not having the need to.
I have one column with two-hundred rows where each row has a value. I wrote a loop to iterate to each row value, read the current value and then write the value back minus the last character.
Here is some actual (and pseudo) code of what I wrote.
Dim theRow as Long
Dim totRow as Long
Dim fooStr as String
theRow = 2 'we begin on the second row of the colummn
totRow = 201 'there are 200 values
For theRow = 2 to totRow
fooStr = WorkSheets(DestSheet).Cells(theRow,"A").Formula 'read the cell value
fooStr = Left(fooStr,Len(fooStr)-1 'subtract the last character from the value
Cells(theRow,1).Value = fooStr 'write the value back
Next theRow
After I did some reading I learned that it is best practice to read and write values using a Range. Is it possible to rewrite what I am doing using a Range so it willl go faster.
Here is what I came up with so far.
Range("A2:A201").Value = Len(Range.Left("A2:A201").Value)-1
However, this doesn't work.
Any clues on how to do this if this is indeed possible?
Thanks for any tips.
If you want maximum performance (you don't need it for 200 rows, but...) you have to minimize the number of reads and writes (mostly writes) to ranges. That means reading the whole range into an array, manipulating the array, then writing it back to the range. That's one read and one write compared to 200 in a loop. Here's an example.
Sub RemoveLastChar()
Dim vaValues As Variant
Dim i As Long
vaValues = Sheet1.Range("A2").Resize(200).Value
For i = LBound(vaValues, 1) To UBound(vaValues, 1)
vaValues(i, 1) = Left$(vaValues(i, 1), Len(vaValues(i, 1)) - 1)
Next i
Sheet1.Range("A2").Resize(UBound(vaValues, 1), UBound(vaValues, 2)).Value = vaValues
End Sub
You could do something like
Sub StringTrim()
Dim xCell as Range
Range("A1:A201").Select
For Each xCell in Selection
xCell.Value = Left(xCell.Value, Len(xCell.Value) - 1)
Next
End Sub
I don't know what kind of speed improvements you are seeking, but that would also do the job.
You might know this already but putting Application.ScreenUpdating = False at the top of your code can speed it up significantly (unless you like to watch everything flash by as the script works). You should reset the value to True at the end of your code.