GoalSeek inside loop - Run time error 1004 : Reference is not valid - vba

I'm writing a code which goes into different sheets and performs GoalSeek on rows that have the word "Obj" and "Var". After completing my first sheet, the code moves on to the second sheet and prompted the error 1004. It says my reference for the Do ... Loop function is no longer valid. Why could that be?
Sub GoalSeek()
Dim FirstAddress As String
Dim SecondAddress As String
Dim Arr As Variant
Dim Rng As Range
Dim Rng2 As Range
Dim y As Long
Dim i As Long
Arr = Array("SheetA", "SheetB")
For i = LBound(Arr) To UBound(Arr)
With Worksheets(Arr(i)).Range("A1:BZ500")
Set Rng = .Find("Obj", LookIn:=xlValues)
If Not Rng Is Nothing Then
FirstAddress = Rng.Address
Set Rng2 = .Find("Var", LookIn:=xlValues)
If Not Rng2 Is Nothing Then
SecondAddress = Rng2.Address
'Error Occurred Here
Do
Rng.Offset(0, y + 1).GoalSeek Goal:=0, ChangingCell:=Rng2.Offset(0, y + 1)
y = y + 1
Loop Until y = 12
End If
End If
End With
Next i
End Sub

I think this might be your issue:
You initialise y at the beginning,
dim y as long
and by default it has the value 0. You make this assumption during your loop
Do
Rng.Offset(0, y + 1).GoalSeek Goal:=0, ChangingCell:=Rng2.Offset(0, y + 1)
y = y + 1
Loop Until y = 12
For the first sheet, y=0,1,2,3,...,12 then the loop stops. Then you leave y=12 and move onto your next sheet.
So for the second sheet you go into the Do loop with y=12 and get an error. You should amend your code to the following:
y = 0
Do
Rng.Offset(0, y + 1).GoalSeek Goal:=0, ChangingCell:=Rng2.Offset(0, y + 1)
y = y + 1
Loop Until y = 12
If you'd used a Do While ... Loop instead, you would probably have noticed this sooner because the loop would never even have been entered as the condition wasn't met.
y = 0
Do While y < 12
Rng.Offset(0, y + 1).GoalSeek Goal:=0, ChangingCell:=Rng2.Offset(0, y + 1)
y = y + 1
Loop
Really though, for a loop this simple, a For loop will always be easier to diagnose than a Do loop...
For y = 0 to 11
Rng.Offset(0, y + 1).GoalSeek Goal:=0, ChangingCell:=Rng2.Offset(0, y + 1)
Next y

Related

Cell selection by cell matrix

#TimWilliams if I define CellArray matrix as range then it crashes on the code to build the matrix, I followed the answer posted at the link that you have indicated https://stackoverflow.com/a/8320884/11835835
Dim CellsArray(3,3) As Range
For X = 0 To 2
For Y = 0 To 2
CellsArray(X, Y) = Cells(X+1,Y+1) _
.Address(RowAbsolute:=False, ColumnAbsolute:=False) 'it crashes here run-time error 91
Next Y
Next X
For K = 1 To 2
ActiveSheet.Union(Range(CellsArray(0, 0), CellsArray(0, K))).Select
Next K
Instead it works if I define CellsArray matrix as string
Dim CellsArray(3,3) As String
but then it crashes on
ActiveSheet.Union(Range(CellsArray(0, 0), CellsArray(0, K))).Select
with run time error 438
Try this:
Dim CellsArray(1 To 3, 1 To 3) As Range 'easier to use a 1-based array
For X = 1 To 3
For Y = 1 To 3
Set CellsArray(X, Y) = Cells(X, Y) 'Need Set here
Next Y
Next X
I'm not sure what you want to do here...
Dim rng As Range
For K = 1 To 3
If rng is nothing then
Set rng = CellsArray(1, 1)
Else
Set rng = Application.Union(rng, CellsArray(1, K))
End If
Next K
rng.Select

If and Do Until Loop EXCEL VBA

New to VBA if someone could help me what im doing wrong here.
Trying to run a loop such that it looks for a specific text, starts the loop then stops at a specific point.
The loops is such that I want it to copy some values below in my sheet hence a is 55.
Im facing the error Block IF without End If
Here is the code:
Private Sub CommandButton3_Click()
For y = 1 To 15 Step 5
Dim x As Double
Dim a As Double
x = 1
a = 55
If Cells(x, y).Value = "Text1" Then
Do Until Cells(x, y).Value = "Text2"
Cells(a, y) = Cells(x, y).Value
Cells(a, y + 1) = Cells(x, y + 1)
x = x + 1
a = a + 1
Loop
End Sub
Indenting is the way forward, you have a for statement with no next and an if with no End If:
Private Sub CommandButton3_Click()
For y = 1 To 15 Step 5
Dim x As Double
Dim a As Double
x = 1
a = 55
If Cells(x, y).Value = "Text1" Then
Do Until Cells(x, y).Value = "Text2"
Cells(a, y) = Cells(x, y).Value
Cells(a, y + 1) = Cells(x, y + 1)
x = x + 1
a = a + 1
Loop
End If
Next y
end sub
Besides the issues I mentioned in the comments to your post, if I understood you correctly, you want to loop on cells at Column A, find the first "Text1", then copy all the cells to row 55 and below, until you find "Text2". If that's the case, try the code below :
Private Sub CommandButton3_Click()
Dim x As Long, y As Long
Dim a As Long
Dim LastRow As Long
With Worksheets("Sheet1") '<-- modify "Sheet1" to your sheet's name
For y = 1 To 15 Step 5
x = 1 '<-- reset x and a (rows) inside the columns loop
a = 55 '<-- start pasting from row 55
LastRow = .Cells(.Rows.Count, y).End(xlUp).Row
While x <= LastRow '<-- loop until last row with data in Column y
If .Cells(x, y).Value Like "Text1" Then
Do Until .Cells(x, y).Value = "Text2"
.Cells(a, y).Value = .Cells(x, y).Value
.Cells(a, y + 1).Value = .Cells(x, y + 1).Value
x = x + 1
a = a + 1
Loop
End If
x = x + 1
Wend
Next y
End With
End Sub

Cut & Paste Overwriting Range Object definitions

I've found an interesting problem with Excel VBA's Cut and paste involving the use of a defined Range Object.
Here's the code that doesn't work:
Sub PasteToRangeDoesntWork()
Dim StRng As Range
Dim j, k, x, y As Integer
Set StRng = Range("A3")
x = 0
j = Range(StRng, StRng.End(xlToRight)).Columns.Count
k = WorksheetFunction.Max(Range(StRng, StRng.End(xlDown)))
For y = 1 To k
While StRng.Offset(x, 0) = y
x = x + 1
Wend
If y < k Then
Range(StRng.Offset(x, 0), StRng.End(xlDown).Offset(o, j - 1)).Select
Selection.Cut
Set StRng = StRng.Offset(0, j + 1)
ActiveSheet.Paste Destination:=StRng
x = 0
End If
Next y
End Sub
The problem is that when pasting to the defined StRng, the StRng object disappears and becomes and undefined object.
There's a simple fix, which I've done below.
Sub PasteToRangeWorks()
Dim StRng As Range
Dim j, k, x, y As Integer
Set StRng = Range("A3")
x = 0
j = Range(StRng, StRng.End(xlToRight)).Columns.Count
k = WorksheetFunction.Max(Range(StRng, StRng.End(xlDown)))
For y = 1 To k
While StRng.Offset(x, 0) = y
x = x + 1
Wend
If y < k Then
Range(StRng.Offset(x, 0), StRng.End(xlDown).Offset(o, j - 1)).Select
Selection.Cut
Set StRng = StRng.Offset(0, j)
ActiveSheet.Paste Destination:=StRng.Offset(0, 1)
Set StRng = StRng.Offset(0, 1)
x = 0
End If
Next y
End Sub
This works -- i.e. by not pasting the new cells directly to the StRng and instead to StRng.offset(0,1), the StRng object remains defined.
The Data in question are five columns across. The first column is an integer (with values going from 1 to 7), the next column is text followed by a column with dates and finally, two columns of general format data (2 decimal points).
The fix is not difficult but I'm perplexed as to why the first code doesn't work. Does anyone have ideas?
If you use the .Paste method, then all defined ranges that fall withing the paste boundaries will be reset. The exact "Why?" is something only Microsoft can explain I'm afraid.
A better alternative is to work with the Range.Value and Range.Clear members; these won't cause this issue, are faster, and also don't mess with the clipboard. Note however that this only copies the values and not the formatting nor any formulas.
The code for this can be something like this:
Dim SourceRng As Range
Set SourceRng = Range(StRng.Offset(x, 0), StRng.End(xlDown).Offset(0, j - 1))
Set StRng = StRng.Offset(0, j + 1)
Dim DestRng As Range
Set DestRng = StRng.Resize(SourceRng.Rows.Count, SourceRng.Columns.Count)
DestRng.Value = SourceRng.Value
Call SourceRng.Clear

Error 1004 when multiplying cell values based on criteria

I have a macro which looks at a range of cells. Every other cell is either a 1 or a 0 (sign bit). Depending on the sign bit, the next cell (a normal number) is multiplied either by 1 or 0. I keep getting a run time error 1004 Application-defined or object-defined error on the body of the ElseIf of the If statement (indicated below). Not sure what I'm doing wrong. My code is in a "proof-of-concept" stage so it's still pretty hackish.
Dim N As Long
------------------------------------------
Private Sub CommandButton1_Click()
Dim x As Integer
Dim y As Integer
x = 0
y = 1
N = Application.InputBox(Prompt:="Enter value", Type:=1)
If N > Columns.Count Then
N = Columns.Count
Else
For i = 4 To 9999
Cells(1, i).ClearContents
Cells(3, i).ClearContents
Next i
End If
For i = 4 To N + 3
x = x + y
Cells(1, i) = x
Next i
For i = 4 To N + 3
If Cells(2, i) = 1 Then
Cells(2, i).Offset(0, 1).Select = Cells(2, i).Offset(0, 1).Select * -1
ElseIf Cells(2, i) = 0 Then
'This is the line with errors vvvvvvvvvvvvvvvvv
Cells(2, i).Offset(0, 1).Select = Cells(2, i).Offset(0, 1).Select * 1
End If
Next i
End Sub
That's because you're using Select. Obviously, Select and Activate don't give you values. They select or activate the cell, not different from manually clicking on them using the mouse or moving/activating to them using the keyboard or what else. Multiplying them by a value is a major no-no.
The Range property you should be looking for is Value. In any case, I think you're making it difficult because of having two loops. You really should reconsider your design pattern. In any case, here's my approach (mine's vertical, but it seems like yours is horizontal, so be clear exactly what is on your end so this can be adjusted).
Private Sub CommandButton1_Click()
Dim WS As Worksheet
Dim LastRow As Long
Dim Iter As Long
Dim CurrCell As Range
Const Col = 1
With ThisWorkbook
Set WS = .Sheets("Sheet3") 'Change as necessary.
End With
With WS
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
For Iter = 1 To LastRow 'Change as necessary.
Set CurrCell = .Cells(Iter, Col)
Select Case CurrCell.Value
Case 1
CurrCell.Offset(0, 1).Value = (CurrCell.Offset(0, 1).Value * (-1))
Case 0
CurrCell.Offset(0, 1).Value = (CurrCell.Offset(0, 1).Value * 1) 'Is this even necessary? It's an identity.
End Select
Next
End With
End Sub
Screenshot:
Let us know if this helps.

Appending rows from other sheets to a master sheet

Literally first time in two decades I've done this and that was even super basic (no pun intended). I have Sheet1 ("Main Page") that I am copying data from ("Control Sequences") based on data entered in Column B. I have it sort of working. The issue I will run into is when I copy over the first set of data, then want to bring in another set, the code runs for the whole sheet again and overwrites any tweaks I did previously. I want to be able to bring in a set of data to Sheet1, manually skip a couple of rows, type in another value in column B below that, re-run the code and append new data in. I'll try to come up with a simpler explanation if this doesn't make sense. Brain is fried right now after 5 hours of VBA absorption :P Here is the code I have so far in its entirety (It's sort of brute force so beware):
Sub test()
Dim i As Integer 'Main Page Sheet Row Number
Dim n As Integer 'Control Sequences Sheet Row Number
Dim x As Integer 'Main Page Current Row Number
Dim y As Integer 'Column Number
Dim CSrow As Integer 'Current Row
Dim NextCS As Integer 'Next Control Sequence
Dim NextCSrow As Integer 'Row To Stop At
Dim ws1 As Worksheet 'Var
Dim ws2 As Worksheet 'Var
Set ws1 = Worksheets("Main Page")
Set ws2 = Worksheets("Control Sequences")
y = 2
'Cycles through the codes in sheet 1
For i = 2 To ws1.Cells(ws1.Rows.Count, y).End(xlUp).row Step 1
For n = 2 To ws2.Cells(ws2.Rows.Count, y).End(xlUp).row Step 1
If ws1.Cells(i, y).Value = ws2.Cells(n, y).Value Then
x = i
CSrow = ws2.Cells(n, y).row
NextCS = ws1.Cells(i, y).Value + 1
NextCSrow = Application.WorksheetFunction.Match(NextCS, ws2.Range("B1:B200"), 0)
NextCSrow = NextCSrow - 1
For CSrow = CSrow To NextCSrow
y = y + 1
For y = 3 To 7
ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
Next y
' ws1.Cells(x, 8).Formula = ws2.Cells(CSrow, 8).Formula
y = y + 1
ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
y = y + 2
ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
x = x + 1
y = 2
Next CSrow
End If
Next n
Next i
End Sub
Thanks to anyone for your help and input.
EDIT 13 FEB 2014
As mentioned in the comment to the Answer below, I took out the .End(xlUp) piece and it worked. I've also changed the body of the writing loop to this:
For CSrow = CSrow To NextCSrow
' y = y + 1
' For y = 3 To 7
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' Next y
' ws1.Cells(x, 8).Formula = ws2.Cells(CSrow, 8).Formula
' y = y + 1
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' y = y + 2
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' x = x + 1
' y = 2
ws2.Rows(CSrow).Copy Destination:=ws1.Cells(x, 1)
x = x + 1
Next CSrow`
I've got the formatting and the formula to copy over without keeping the original reference :D On to part IV... Testing ALL of the Variables and not just 1 ;) I will continue to update this thread with ... well ... updates.
EDIT 20 FEB 2014
Here's the complete code as it stands now:
Sub test()
Dim i As Long 'Main Page Sheet Row Number
Dim j As Long 'Placeholder
Dim n As Long 'Control Sequences Sheet Row Number
Dim x As Long 'Main Page Current Row Number
Dim y As Long 'Column Number
Dim z As Long
Dim a As Long
Dim CSrow As Long 'Current Row
Dim NextCS As Long 'Next Control Sequence
Dim NextCSrow As Long 'Row To Stop At
Dim ws1 As Worksheet 'Var
Dim ws2 As Worksheet 'Var
Dim ws3 As Worksheet 'Var
Dim ws4 As Worksheet 'Var
' Set ws1 = Worksheets("Main Page")
Set ws1 = ActiveSheet
Set ws2 = Worksheets("Control Sequences")
Set ws3 = Worksheets("Cost 1")
Set ws4 = Worksheets("Cost 2")
If ws1.Name = ws2.Name Or ws1.Name = ws3.Name Or ws1.Name = ws4.Name Then
End
End If
y = 2
z = 10
a = ws1.Cells(ws1.Rows.Count, z).End(xlUp).row + 2
If IsEmpty(ws1.Cells(a, y).Value) Then End
'Cycles through the codes in sheet 1
j = ws1.Cells(ws1.Rows.Count, y).End(xlUp).row
i = ws1.Cells(j, y).row
For i = i To j Step 1
For n = 2 To ws2.Cells(ws2.Rows.Count, y).End(xlUp).row Step 1
If ws1.Cells(i, y).Value = ws2.Cells(n, y).Value Then
x = i
CSrow = ws2.Cells(n, y).row
NextCS = ws1.Cells(i, y).Value + 1
NextCSrow = Application.WorksheetFunction.Match(NextCS, ws2.Range("B1:B100"), 0)
NextCSrow = NextCSrow - 1
For CSrow = CSrow To NextCSrow
' y = y + 1
' For y = 3 To 7
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' Next y
' ws1.Cells(x, 8).Formula = ws2.Cells(CSrow, 8).Formula
' y = y + 1
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' y = y + 2
' ws1.Cells(x, y).Value = ws2.Cells(CSrow, y).Value
' x = x + 1
' y = 2
ws2.Rows(CSrow).Copy Destination:=ws1.Cells(x, 1)
x = x + 1
Next CSrow
End If
Next n
Next i
End Sub
I added a check that if the user was on any of the "Template" sheets, the code would just stop. It's a bit brute force, but it gets the job done and it's the only code I have. Maybe if I continue to do this, I'll try to get more "streamlined". :D Thanks to everyone for their input and help.
I think I have it. Your problem is in the first line of your loop:
For i = 2 To ws1.Cells(ws1.Rows.Count, y).End(xlUp).row Step 1
Try setting i dynamically before the loop begins. DIM another variable j for this, then replace the above line with the following:
j = ws1.Cells(ws1.Rows.Count, y).End(xlUp).row
i = ws1.Cells(j, y).End(xlUp).row
For i = i to j Step 1
While you're at it, change your row integers to long since there are more rows in a worksheet than integers can handle.