VB Nested Loop w/ Conditionals Syntax - excel

I am new to VB and am having trouble getting a good grasp on the syntax of nested loops. For example:
For N = 8 To 22
For M = 4 To 19
If Cells(N, 3).Value >= 0 Then
Cells(M, 35).Value = 1
Else
Cells(M, 35).Value = 2
End If
Next M
Next N
I want this loop to check one column of cells and IF a cell contains a 0 or positive number it should return "1" in the other specified column. Otherwise, it should return a "2".
Unfortunately this loop currently is returning (ELSE) "2" in every cell of the new column. Any explanation of what I am doing wrong?

Nested loops like this operate by repeating the inner cycle from start to finish every time the outer cycle goes through one step. So for each N, every row M will have its cell in column 35 set to 1 or 2 (all the same) based on the value at row N and column 3. So in this case, the last row N must have a negative number or be missing, which sets every one of the output column cells to "2".
What I suspect you want is something more like this:
For N = 8 To 22
If Cells(N, 3) >= 0 Then
Cells(N - 4, 35) = 1
Else
Cells(N - 4, 35) = 2
End If
Next N
Note that there seems to be an off-by-one error in your original code as well, in that N goes over 15 rows, but M goes over 16 rows. Also, because .Value is the default property, you can leave it out.
Bonus: Generally speaking, you'll want something with fewer magic numbers, like this:
Option Explicit
Public Sub DoSomething()
Const ColTest As Integer = 3, ColResult As Integer = 35, DRowResult As Integer = -4
Const RowStart As Integer = 8, RowEnd As Integer = 22
Dim Row As Integer
For Row = RowStart To RowEnd
If Cells(Row, ColTest) >= 0 Then
Cells(Row + DRowResult, ColResult) = 1
Else
Cells(Row + DRowResult, ColResult) = 2
End If
Next Row
End Sub
Then, if you need to generalize it to work on different areas (by switching the constants to parameters), change where you've hardcoded it to work, or whatever else, it's simple to fix it at the top, once, and be sure you've got everything. It's also easier to understand in many cases. And, of course, Option Explicit is just good in general. (D in the constant names stands for delta/difference.)

Related

Mod Function Always Returning Zero

I have a data table that has values in column A consisting of whole integers and some decimal numbers. (e.g. 1; 2; 3; 3.1; 3.2; 4... etc). I am trying to loop thru column A, find any values that are not whole numbers and delete that entire row.
I am attempting to use the Mod function to do this, so I am taking the value of the cell in column A and when dividing that by 1, if the remainder is not zero delete the row.
For some reason, my remainder is always being set at zero with this code below, even when doing 10.1 Mod 1 for example. Can anyone tell me what I have wrong. Thanks.
Dim c As Range
Dim remainder As Variant
Dim rowNum As Integer
For Each c In Worksheets("BOM Dump").Range("A1:A1000").Cells
'Range("L1").Value = "Number"
'Range("M1").Value = c
remainder = c.Value Mod 1
Range("N2").Value = remainder
If remainder <> 0 Then
rowNum = c.Row
Rows(rowNum).EntireRow.Delete
End If
Next
Used fix instead of Mod and iterated backwards to get it working perfectly. Thanks everyone.
For i = 500 To 1 Step -1
Set c = Worksheets("BOM Dump").Range("A" & i)
remainder = c.Value - Fix(c.Value)
If remainder <> 0 Then
rowNum = c.Row
Rows(rowNum).EntireRow.Delete
End If
Next

Count how many cells exceed other cells' value

(I'm a straight up beginner, first month of assignments of vba)
In my assignment, I was given an excel file with 4 sheets (of which, for my question, only the first three matter). Each of those first three's names end with the date (MM/YY) (0920, 1020 and 1120 respectively). In all those sheets I have two columns - one with a minimum value, and the other with the real value.
I need to create a procedure that, with a certain input of month and year, goes to the respective sheet and calculates how many cells with the real value have a value larger than their respective minimum value.
I tried this:
Sub ArtigosArmazem()
folhas = Array("Stock final 0920", "Stock final 1020", "Stock final 1120")
For i = LBound(folhas) To UBound(folhas)
Worksheets(folhas(i)).Activate
Next
Dim n As Integer
x = InputBox("Ano")
y = InputBox("Mês")
n = 0
If x = 2020 And y = setembro Then
i = "Stock final 0920"
For k = 3 To 510
If Cells(k, 8) > Cells(k, 7) Then
n = n + 1
End If
Next
MsgBox(n)
End If
End Sub
("Ano" means year, "Mês" means month and "setembro" means september in portuguese)
But it kept outputting "0" in the Message Box. Any help or tips?
If I understand the issue, then I think you need something like this using VBA.
Sub ArtigosArmazem()
Dim x as Integer
Dim y as String
Dim n as Integer
dim k as Integer
x = InputBox("Ano")
y = InputBox("Mês")
n = 0
If x = 2020 And y = "setembro" Then
Sheets("Stock final 0920").Activate
For k = 3 To 510
If Cells(k, 8) > Cells(k, 7) Then
n = n + 1
End If
Next
MsgBox(n)
End If
End Sub
With this method you have to watch out for the capitalization of "setembro". In VBA unlike Excel, "setembro" <> "Setembro".
It might be easier to use =SUMPRODUCT((H3:H510>G3:G510)*1) in each sheet instead of VBA.
This works in my version of Excel O365. I believe it will work in earlier versions as well.

Find first four cells in a row

I am trying to find the first four cells along a row that contain values and the type is Double. I want to add the values of the cells to an array and also locate the cells locations for future use. I need to work down 23 rows after as well. Some of the rows don't contain any values. The matrix starts with cell AB3
I've been trying to start with a For loop so I can work down the rows and then having a For loop inside that to create a new array every time I move to a new row.
The code I need looks something like this.
For i = 3 to 27
For j = 0 to 3
TIGA(j) = Range(Cells(i, j + 28), Cells(last cell)).Find(first
value and then the next three)
Again I need to work across from left to right in each row. First I need to add the first four values in a row to an array. Next I need to save the column number for each of the values because I need to know what column they're in later on in my code. After I get the information for one your I need to loop it down for the rest. The array with the values and any variable/array used for the cells location can be restarted every time the code loops through for the new row. Thank you!
Here's what's the data looks like.
I changed things up a bit, I think this should suffice:
Sub Test()
Dim TIGA As Variant, i As Long, j As Long, k As Long
ReDim TIGA(0 To 3)
For i = 3 To 27
k = 0
For j = 28 To 40
If Cells(i, j) <> "" Then
If IsNumeric(Cells(i, j)) = True And InStr(Cells(i, j), ".") > 0 Then 'make sure it's a double
TIGA(k) = Cells(i, j)
k = k + 1
If k = 3 Then
Exit For
End If
End If
End If
Next j
Next i
End Sub

Subtract Amount From Cell Until It Reaches 0 multiple reminding amount

My formula below subtracts a cell until it reaches zero, and moves to the next one. The subtraction is based on the value “B”. Each time the formula comes across the value “B”, this action is performed.
Question: I have been trying to advance this to formulae, in that each time “B” is found that cell is minuses until zero and those amount multiple by the adjacent price.
could you please provide me with a formula which does this ?
Example: when it comes across the first B the full value of 100 x 10 will be multiplied and the reminder 50 will be multiplied by 15 i.e. 50 x 15 price of the next A. These values will be summed.
=MAX(SUMIF($A$2:A2,"A",$B$2:B2)-SUMIF($A$2:$A$10,"B",$B$2:$B$10),0)
The reminder of the 50 is coming from the difference between the B 150 - A 100 , which leaves 50 to be still absorbed .
Further Calculation for explanation:
Apologies thats meant to say calculation of 6000
Your question is still very unclear. What does "My formula below subtracts a cell until it reaches zero" mean? Also, as OldUgly pointed out, it seems that you are ignoring the second A. Since we can't understand each other, take a look at the code below and try to rewrite it yourself to fit your needs. It assumes the data is in a sheet named "Data", and that there is a button (Button1) to run the code.
Dim lLastRow As Long
Dim i As Integer
Dim QtyNumberA, QtyNumberB, QtyNumberRem As Integer
Sub Button1_Click()
lLastRow = Worksheets("Data").Cells(2, 1).End(xlDown).Row 'Rows with data, starting 2nd row (titles in the first)
QtyNumberA = 0 'Variable for storing quantities of A
QtyNumberB = 0 'Variable for storing quantities of B
QtyNumberRem = 0 'Variable for storing quantities remaining
For i = 2 To lLastRow 'scan all rows with data
If (Worksheets("Data").Cells(i, 1).Value = "A") Then
QtyNumberA = QtyNumberA + Worksheets("Data").Cells(i, 2).Value
ElseIf (Worksheets("Data").Cells(i, 1).Value = "B") Then
QtyNumberB = QtyNumberB + Worksheets("Data").Cells(i, 2).Value
QtyNumberRem = QtyNumberA - QtyNumberB
Worksheets("Data").Cells(i, 6) = QtyNumberRem
End If
Next
End Sub

Filling Array once worked, does not anymore (subscript out of range)

The code I have once worked to add/delete groups of rows (requirements). I needed to modify the code so that if the 1st row of the group met certain criteria (i.e, the requirement was not one we wanted to consider), (1) we would not count it and (2), we would hide the group (current and subsequent 2 rows). This all works fine.
The problem is that now that I incorporated these changes, I get an error in another section of the code and for the life of me I cannot figure out why. I have stepped through this and am extremely frustrated. I am reaching out for help, and am hoping someone can see my error(!)
We calculate the start and finish row numbers within a grouping, and store these calculations in Arrays called "Start" and "Finish." I use the ReDim statement to initialize my arrays, because I thought that could be part of the problem, but no.
Any insight as to why my "subscripts are out of range" would be appreciated. I have traced through the logic, investigated this error, and read about the syntax/usage of VBA arrays. I don't know what else to do. Thanks in advance. Here are the relevant lines:
Sub Button1_Click()
Cells.Select
Selection.ClearOutline
If Cells.EntireRow.Hidden Then Cells.EntireRow.Hidden = False
Dim Start() As Integer
Dim Finish() As Integer
Dim p As Integer, q As Integer
ReDim Start(0, 50)
ReDim Finish(0, 50)
The following is embedded in logic that loops through all the rows in the spreadsheet:
i = 1
For Row = 4 To Cells(1, 6).Value - 1
If Begin Then
If Cells(Row, 3).Interior.ColorIndex = 44 Then
Start(i) = Row + 1
j = Cells(Row, 2).Value
Begin = False
End If
Else
If Cells(Row, 2).Value = j + 1 Or Cells(Row, 2).Interior.ColorIndex = 37 Then
Finish(i) = Row - 1
Begin = True
i = i + 1
Row = Row - 1
End If
End If
Next
The block I changed is as follows (code I added is last block where I attempt to hide rows). It precedes the previous. I am wondering how my change could have affect the above(?!)
If Cells(Row, 5).Value = "Requirement" Then
Range(Cells(Row, 4), Cells(Row, 4)).Interior.ColorIndex = 40
Rows(Row).Font.Bold = True
Rows(Row).Font.Italic = False
Rows(Row).Font.ColorIndex = 1 'Black
If Cells(Row - 3, 4).Value = "" Then 'this is requirement #1
Cells(Row, 4).Value = 1
Else
Cells(Row, 4).Value = Cells(Row - 3, 4).Value + 1
End If
p = Row
q = p + 2
Rows(p & ":" & q).Select
If Cells(p, 19).Value = "4" Then
Selection.EntireRow.Hidden = True
Else
Selection.EntireRow.Hidden = False
End If
Redim Start(0,50) makes the array dimensions 0 to 0, 0 to 50 i.e. a 2d array.
This means that when you call the array you need to provide parameters for both dimensions I.E: Start(0,i) or Finish(0,i). Calling Start(i) will result in the error you mentioned.
The easiest way to get rid of the error is to change your Redim lines to
ReDim Start(50)
ReDim Finish(50)
which is what I assume you meant to do in the first place.
Note: Based upon the format you used, you may have been meaning to do Start(0 to 50) and Finish(0 to 50) initially. The comma in the dimensioning indicates another dimension instead of a separation between lower and upper bounds.

Resources