vba stuck in a loop and not moving on to next command - vba

i have written the following code:
Public Sub SortMyData()
'approach: convert line to string and concatenate to that as it's a lot less picky than Excel's formats, then replace cell value with the new string.
' Excel will then define the string type as either Percentage or Scientific depending on the magnitude.
Dim i As Integer
Dim g As Integer
Dim N_Values As Integer
Dim IntermediateString As String
N_Values = Cells(1048576, 2).End(xlUp).Row 'retrieves the final filled row in column 2 (B)
For i = 6 To N_Values 'iteration loop from 6 (first row of value) to N_Values (last filled row)
If Cells(i, 2).NumberFormat <> "0.0%" Then
IntermediateString = Cells(i, 2).Value
Cells(i, 2).NumberFormat = "0.0%"
Cells(i, 2).Value = Cells(i, 2).Value / 100
Else
MsgBox ("The Range of Cells Has Already Been Formated as Percentage")
End If
Next i
For g = 6 To N_Values 'iteration loop from 6 (first row of value) to N_Values (last filled row)
If Len(Cells(g, 3) > 3) Then
Cells(g, 3).Value = Cells(g, 3).Value / 1000
Else
MsgBox ("Data is correct so no action will be taken")
End If
Next g
End Sub
the code runs fine but it does not move onto the secont if statement, it just keeps on running the first one and displaying the MsgBox ("The Range of Cells Has Already Been Formated as Percentage") so i dont know where i have made a mistake?
i am a rookie by the way so go easy on me!

You declare the string :
Dim IntermediateString As String
Then you affect a value to it (by the way, the .Value is optional, cells(x, y) and cells(x, y).Value are the same) :
IntermediateString = Cells(i, 2).Value
But then you don't do anything with this string, so I'm pretty sure that's not what you intended to do (you could comment both of those line, your program would run the same way).
Also, seeing as your program is coded, you should have at most as much messages "The Range of Cells Has Already Been Formated as Percentage" as the number of lines in the B column, but it should eventually keep going to reach second if statement.
I suggest you open the execution window (Ctrl + G), and replace the occurences of "MsgBox" in your code by Debug.Print. You will see the message in the execution window, but it won't pause the execution of the program (much better way to debug)

Related

VBA Code for Conditional Loop

I am trying to create a conditional loop macro in Excel. Column B contains a last name, Column C contains a first name, and Column D contains a first and last name. I am trying to get the macro to detect when Column D = Column C + Column B.
If D = C + B, then clear contents of D.
So, the following works for a single row:
Sub ClearContentsD ()
If Range("D1").Value = Range("C1").Value + Space(1) + Range("B1") Then Range("D1").ClearContents
End Sub
It does not work without the added Space(1), and I cannot get it to loop through the whole worksheet:
Sub ClearContentsLoop()
Application.ScreenUpdating = False
Dim i As Long
For i = 1 To Rows.Count
Next i
Do While Cells(i, 4).Value = Cells(i, 3).Value + Space(1) + Cells(i, 2).Value
Cells(i, 4).ClearContents
Loop
Application.ScreenUpdating = True
End Sub
VBA doesn't like my Do While. Any help would be greatly appreciated.
CJ
Some issues:
You must concatenate strings with &. The plus (+) is for addition;
Your For loop is not doing anything: its body is empty;
Your Do While Loop will at most run once, because i is not incremented;
It is a mystery why you would want two loops (For and Do While);
A sheet has many rows of which you only use a fraction, so don't loop through all of them (For) and use UsedRange.
Possible correction:
Sub ClearContentsLoop()
Dim i As Long
Application.ScreenUpdating = False
For i = 1 To ActiveSheet.UsedRange.Rows.Count
If Cells(i, 4).Value = Cells(i, 3).Value & " " & Cells(i, 2).Value Then
Cells(i, 4).ClearContents
End If
Next i
Application.ScreenUpdating = True
End Sub
There is a way to ignore the space in the values you are evaluating. Try this:
Application.ScreenUpdating = False
Dim i As Long
For i = 1 To Rows.Count
If InStr(1, Cells(i, 4).Value, Cells(i, 2).Value, vbTextCompare) > 0 And InStr(1, Cells(i, 4).Value, Cells(i, 3).Value, vbTextCompare) > 0 Then Cells(i, 4).ClearContents
Next i
Application.ScreenUpdating = True
Explanation:
By using the InStr function, you are testing for the presence of one text string inside of another, and if at least one match is found, then the function returns a non-zero value (the position where the match was found). In the above example, you are testing for the presence of the first name and last name at the same time, and if both are found, then the code clears out the contents of the cell.
And, as was pointed out in the comments section, you need to do this inside the loop so that all cells down the length of the worksheet are evaluated and updated as specified.
Be sure to test this on a COPY of your original data so that you don't lose the original values in case you want to roll back your changes! ;)

VBA runtime error 9

I am currently getting a error saying subscript out of range. on the line of code
If Sheets(Master).Cells(i, A).Value = AssetNum.Value Then
I'm trying to use a for loop to increment i so the row range starts at 12 and adds 1 to it each time. Then inside the for loop I want to use an If statement to check and see if the cell (i,A) is equal to the value in AssetNum. If the loop reaches the value of the EmptyRow it ends the loop. Im not exactly sure how to use a for loop IF-THen statement correctly.
Public i As Integer
Private Sub AssetNum_Change()
End Sub
Private Sub Enter_Click()
Dim EmptyRow As Long
'Audit will only search Master Sheet
Worksheets("Master").Activate
'Find empty row value so we can use that for limit of search
With Sheets("Master")
EmptyRow = .Range("A" & Rows.Count).End(xlUp).Row + 1
End With
'i needs to be set to minimum limit
'Begin loop of search
For i = 12 To EmptyRow + 1
If Cells(i, 1).Value = AssetNum.Value Then
'Go to compare userform to display
Compare.AssetDisplay.Value = AssetNum.Value
Compare.LocationDisply.Value = Cells(i, 2).Value
Compare.Show
End If
Next i
'If i gets to emptyrow num then go to non found asset userform
Unload Me
NonFoundAsset.Show
I assume your refer with your error to the line:
If Cells(i, A).Value = AssetNum.Value Then
Well, I see nowhere that A is declared. Then VBA declares it automatically (advice: always turn Tools, Options, Require variable declarations to ON). Neither do I see A being initialized, so its value will be 0 and that is not a valid reference for Cells. Hence, Subscript out of bounds.
If you want to reference the "A" column, then write:
If Cells(i, 1).Value = AssetNum.Value Then
as "A" is the first column.
Use as follow:
If Sheets(Master).Cells(i, "A").Value = AssetNum.Value Then
And also this line:
Compare.LocationDisply.Value = Cells(i, "B").Value

Data Manipulation In Excel

Fairly easy one I hope.
If I have a column of values in a sheet, How can I set those values to equal a variable I can work with in VBA.
For instance column A has 100 weight values and column b has 100 height values. In a VBA script I want to set "weight" as all values in column A and height as b. and say BMI = weight * height and then write BMI to column C.
I know I can do this example with formulas but for the actual task I'll be looping this a few hundred times and will not know the column index value.
Thanks!
Edit: To specify further, the columns are randomly arranged. I won't be able to use relative cell references. Ultimately I'll be finding the column, naming it working with the data in reference to another column and then finding the next column and doing the same.
Edit 2: I think answers are focusing on achieving the result I specified in the example rather than implementing the process I was trying to describe.
This should be enough for you to see how this simple task can be done :
Sub user3033634()
Dim LastRow As Integer
With Sheets("Sheet1")
LastRow = .Cells(Rows.Count).End(xlUp).row
For i = 1 To LastRow
.Cells(i, "C") = .Cells(i, "A") * .Cells(i, "B")
'.Cells(i, 3) = .Cells(i, 1) * .Cells(i, 2)
Next i
End With
End Sub
First determine the limits and then Select that part of column C you wish to fill and then:
Sub BMII()
Dim r As Range
For Each r In Selection
r.Value = r.Offset(0, -2).Value * r.Offset(0, -1).Value
Next r
End Sub
EDIT#1
Once you have determined which columns and which rows to process, update the parameter section of the following macro and run it:
Sub BMIII()
Dim wcol As String, hcol As String, bcol As String
Dim start_row As Long, end_row As Long, i As Long
''''''''''' PARAMETER SECTION ''''''
start_row = 5
end_row = 200
wcol = "A"
hcol = "B"
bcol = "C"
''''''''''''''''''''''''''''''''''''
For i = start_row To end_row
Cells(i, bcol).Value = Cells(i, wcol).Value * Cells(i, hcol).Value
Next i
End Sub

Double For Loop for finding if a cell value is in a range

Even more VBA Goodness, i've tried writing a for loop with a for loop to go through get the cells text assign it a a variable and then run through a range seeing if the cells value is in range and if found then change another cells value to yes or no if not found but i keep getting all NO's despite being able seeing the values inside the range myself
The whole point is to avoid using vlookup function =if(vlookup("value","Table","col","false"),"Yes","No") which seems to skip some values despite being present.
my code is
Dim xell As Range
For Each xell In Range("C6:C36")
lookFor = xell.Value
For i = 6 To 36
If Cells(i, 10).Value = lookFor Then
Cells(i, 7).Value = "Yes"
Else
Cells(i, 7).Value = "No"
End If
Next i
Next xell
The idea being loop in the first range get the cells text assign it to a variable and start a new loop during this to look through a range to see if the cell value is inside this range.
It executes but comes back with All no.
Turns out i had n exited my loop when finding a yes :)
Exit For was needed
Dim xell As Range
For Each xell In Range("C6:C36")
lookFor = xell.Value
For i = 6 To 36
If Cells(i, 10).Value = lookFor Then
Cells(i, 7).Value = "Yes"
Exit For <-------- was missing
Else
Cells(i, 7).Value = "No"
End If
Next i
Next xell
Didnt solve my current issue of data not being found unless edited

How to match strings in cells on Excel, with if/or operators, and delete the rows

Disclaimer: I've never used Visual Basic and I've never made a macro.
I am trying to create a macro in Microsoft Excel 2010 that will delete all rows where neither column G nor column I contain the string "Ohio", "Indiana", or "Kentucky". To clarify, the row should be deleted if the cell does not contain either of those three state names. I want the macro to start at row 6, as rows 1-5 contain vital information. The whole sheet contains over 14000 rows and only ~1.5% of those are actually helpful.
Also, I am looking to be able to reuse this macro, but for other terms (besides Ohio, Indiana, and Kentucky) in other columns (besides G and I).
It may also help me if you can, besides correcting this, explain what exactly I am saying in these lines. Perhaps in Java terms, or Python is okay too. Not necessary, but may help.
Sub DeleteIfNotKYINOH()
Dim i, LastRow
LastRow = Range("G" & Rows.Count).End(xlUp).Row
For i = LastRow To 6 Step -1
I get a type mismatch error on the next line.
If Cells(i, "G").Value = "Ohio" Or "Indiana" Or "Kentucky" Then
Cells(i, "G").Value = True
End If
If Cells(i, "I").Value = "Ohio" Or "Indiana" Or "Kentucky" Then
Cells(i, "I").Value = True
End If
If Cells(i, "G").Value Or Cells(i, "I").Value = False Then
Cells(i, "G").EntireRow.Delete
End If
Next
' DeleteIfNotKYINOH Macro
' Delete all rows that do not contain Ohio, Indiana, or Kentucky, as a state.
'
'
End Sub
There are a few things to consider, it looks like you are on the right track, though, you even got the backwards iteration over the collection (this stumps a lot of people!).
Make sure to declare your variables properly (i and LastRow should probably be Long integer, not unspecified Variant type).
If statements can include Or joins, but have to be like this:
If Cells(i, "G").Value = "Ohio" Or Cells(i, "G").Value = "Indiana" Or Cells(i, "G").Value = "Kentucky"
Since you want to be able to re-use the macro for other strings, of course you could go in and edit each instance of "Ohio" or "Indiana", etc., but that can be tedious and error-prone.
You could do something like this instead to re-use it for a list of any number of states, just change the assignment to the states variable.
Const states as String = "Ohio,Indiana,Kentucky"
Sub TestDeleteIfNot()
Dim i as Long, LastRow as Long
Dim cl as Range
LastRow = Range("G" & Rows.Count).End(xlUp).Row
For i = LastRow To 6 Step -1
With Cells(i, "G")
If Not(InList(.Value, states)) And Not(InList(.Offset(0,2).Value, states))
.EntireRow.Delete
End If
End With
Next
End Sub
This routine calls on a function InList which accepts as its arguments two strings. The first string should be the value being compared, and the second is a comma-delimited "list" of allowable values.
Function InList(strVal as String, list as String) As Boolean
Dim a as Variant
For each a in Split(list, ",")
If strVal = a Then
InList = True
Exit For
End If
Next
End Function
The function converts the list to an array and iterates that against the compare value. It should return False if the value is not found. So then the logic in the calling sub runs this on cells in COlumn G and also Column I, only deleting the row if BOTH tests return False.