GoalSeek only within VBA, without depending on a WorkSheet Cell - vba

Very shortly: Instead of ActiveCell of ActiveCell.GoalSeek Goal:=0, ChangingCell:=Range("GM")formula, how can I use a variable? So I want to use something like GoalSickVariable.GoalSeek Goal:=0, ChangingCell:=Range("GM")
.
As a detail:
I am trying to shorten my current GoalSeek formulation and I'm stucked on the last line.
So far, I was running my codes within WorkSheet but as I can't assume which part of the Worksheet will be empty, I was going to a cell which is away from the reference cell by .Offset(0,25) but as user can also use that cell, I would like not to use any range within WorkSheet - if it's possible.
...
ActiveCell.Offset(0, 25).Select
ActiveCell.Formula = "=ROUNDUP(SellPrice,-3)"
RoundedCellAddress = ActiveCell.Address
ActiveCell.Offset(0, 1).Select
ActiveCell.Formula = "=(" & RoundedCellAddress & "-" & "SellPrice" & ")"
'SellPrice is a NamedRange from this current Worksheet
ActiveCell.GoalSeek Goal:=0, ChangingCell:=Range("GM")
'GM is also a NamedRange from this WS and it changes SellPrice's value.
...
While it's a very bad practice with many ActiveCell and a Assuming Cell Reference, this above code is working without any problem. Anyway as I explained above, I don't want to assume this .Offset(0,25) cell and don't want to use these ActiveCells.
So here below how I transformed my code into a good practice:
...
RoundedSellPrice = Application.WorksheetFunction.RoundUp(ws4.Range("SellPrice"), -3)
GoalSick = RoundedSellPrice - ws4.Range("SellPrice")
GoalSick.GoalSeek Goal:=0, ChangingCell:=ws4.Range("GM")
...
But now as you can easily guess, it gives me Invalid Qualifier error on GoalSick.GoalSeek line because GM and SellPrice are variables defined within WorkSheet so they are (I think) not able to run GoalSeek formula from VBA module without exactly referring to any cell(contains formula) within the WorkSheet.
If somehow I can not do this formulation without referring to a cell within the WorkSheet, how should I suppose to do without assuming a dummy cell like .Offset(50,150) or without creating a new empty WorkSheet?

Related

How to combine indirect and direct references in VBA?

Issue:
I need to call direct and indirect references. I have a column that shifts to the right every time the program is run. The column is being used to collect the sum of the preceding columns. (I'm aware I can combine the sheet1 within the with, however there are pieces of code between the with and sheet select and this particular question focuses on just the .value section.)
Code 1:
Sheets("Sheet1").Select
With Range("AL2")
.Value = "=SUM(B2:RC[-1])"
End With
B2 is being inserted as a string, instead of as a cell name.
I've also tried:
Sheets("Sheet1").Select
With Range("AL2")
.Value = "=SUM(range("B2") & ":RC[-1])"
End With
Sheets("Sheet1").Select
With Range("AL2")
.Value = "=SUM("& B2 & ":RC[-1])"
End With
This particular set of code does not run correctly and returns:
SYNTAX ERROR
So, the problem in this specific instance is that you are mixing R1C1 and A1 style notation.
Anyway, I'd change your code to set the .Formula property instead of the .Value property, and specifically change it to .FormulaR1C1 if you want to use that notation or leave it as .Formula for A1 notation.
Anyway, your original code:
Sheets("Sheet1").Select
With Range("AL2")
.Value = "=SUM(B2:RC[-1])"
End With
This is setting B2 as a string because Excel is recognizing the RC notation, correctly interpreting that "RC[-1]" is a cell reference, but then not understanding what "B2" means.
So, I'd use something like this:
With Sheets("Sheet1").Range("AL2")
.FormulaR1C1 = "=SUM(R2C2:RC[-1])"
End With
That however would leave $B$2 as an absolute cell reference, and AK2 as a relative reference, which is kind of gross. Depending on your needs you could do this:
With Sheets("Sheet1").Range("AL2")
.FormulaR1C1 = "=SUM(R2C2:R2C37)"
End With
Which would lead to both being absolute references.
If you want something more dynamic, you'll need to use string manipulation on the string you're inputting into the worksheet. For instance, if you have r1 as a range object (with address B2) and r2 as a range object (with address AK2), you could do this:
With Sheets("Sheet1").Range("AL2")
.Formula = "=SUM(" & r1.address ":" & r2.address & ")"
End With
If you have questions, let me know.

Excel use cell value as range in VBA

I have an excel file. There is a changable row quantity for column A for every time and that's why I need to make dynamic formula. For example;
I want to write "=LEN(B1)" formula on B1. And when make double click on right down corner of the cell, it's going to the end of until when column A values ends. That's why, before all this process, I wrote "=COUNT(A:A)" on cell C1.
In my VBA, I want to write;
Dim TEMP As String
TEMP = Range("C1").Value
Range("B1").Select
ActiveCell.FormulaR1C1="=+LEN(RC[-1])"
Selection.AutoFill Destination:=Range("B1:TEMP")
But there is something wrong in this process. As a result, I just want to use a cell value in my VBA as a range or string or number.
Thanks for your support.
Two notes:
It's best practice to always qualify your objects (workbooks, worksheets, ranges, etc.) beforehand
When you use R1C1 notation, you can just write the formula directly to the range (with no need for AutoFill or FillDown)
Try this:
Dim ws as Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1") 'edit for your sheet name
Dim lRow as Long
lRow = ws.Range("A" & ws.Rows.count).End(xlup).Row
ws.Range("B1:B" & lRow).FormulaR1C1 = "=Len(RC[-1])"
And just as a side note worth mentioning the way you wrote Range("B1:TEMP") is not proper syntax. Correct syntax would be Range("B1:B" & TEMP), which, of course, would only work if TEMP was indeed a numerical value :)

Declaring last row references in Excel formulas through VBA

In an attempt to take one of my rudimentary programs, and develop it more I am in need of help referencing last row references in Excel formulas as well as dragging formulas down consistently to the last row of a document.
To elaborate I am attempting to reference the last row in an ever expanding mapping table in my vlookup formula. The reason I need this is because as this mapping table expands when I am no longer coding this program, I need my vlookup formula which will be generated every time I run the program to adapt to the ever changing size.
Also my more pressing issue is in regard to taking that vlookup formula and being able to drag it down to the last row of a worksheet. The worksheet will be static and the last row will range anywhere from 70,000 rows to 90,000 rows. I am trying to avoid loops in this scenario as this will already be a very demanding formula and I would hate to loop through each row.
Currently my rudimentary code looks like this (this was built as a proof of concept, I understand the current method isn't the most ingenious but it served its initial purpose).
Ath.Cells(1, x) = "Business"
Ath.Cells(2, x).Select
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R264C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R264C5,3,0))"
Ath.Range("d2").Copy
Range("d2:d90000").Select
ActiveSheet.Paste
Calculate
I namely want to change this
Ath.Range("d2").Copy
Range("d2:d90000").Select
ActiveSheet.Paste
and
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R264C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R264C5,3,0))"
Perhaps these?
Ath.Range("d2").Copy
Range("d2:d" & Range("D" & Rows.Count).End(xlUp).Row).Paste
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R2C4:R" & Sheets("Mapping").Range(ActiveCell.Offset(Rows.Count, -1)).End(xlUp).Row & "C5,2,0),VLOOKUP(LEFT(RC[1],2),Mapping!R1C3:R" & Sheets("Mapping").Range(ActiveCell.Offset(Rows.Count, -1)).End(xlUp).Row & "C5,3,0))"
Combining Dans answer with work of my own I have developed a solution.
Sub Formulas()
Dim Map As Worksheet
Dim Ath As Worksheet
Dim last As Long
Set Ath = Sheets("Athena IBT TEST")
Set Map = Sheets("Mapping")
last = Map.Cells(Rows.Count, "D").End(xlUp).Row
ActiveCell.FormulaR1C1 = "=IFERROR(VLOOKUP(RC[1],Mapping!R1C1:R" & last & "C4,4,0),IFERROR(VLOOKUP(LEFT(RC[1],3),Mapping!R1C2:R" & last & "C4,3,0),VLOOKUP(LEFT(RC[1],3),Mapping!R1C3:R" & last & "C4,2,0)))"
End Sub

Using a variable in a range statement in VBA excell macro

Ok, I'm sure this question is really basic but all my searchers turn up complicated answers and I've been messing with VBA for about a day. I have two worksheets in an excel doc, I've created a button that I can click that invokes my macro that is just moving cells from one work sheet to another. But I need my macro to determine what row I am on. I'm using this:
r = ActiveCell.Row
to determine my row, but what would be the easiest way to use that variable in a range statement like this:
Range("A2").Select
You could use the Range method with the & operator to join the variable into a string:
Range("A" & r)
Alternately you can use the Cells method which takes arguments (Row, Column):
Cells(r, "A")

VBA Excel error when code is moved from worksheet to module

I have a Excel file with multiple tabs. I have a worksheet with some code which is working fine. This code also refers to data on some "master" tabs. I need to duplicate this sheet so I moved the common functions from there to a module. Now I get a VBA 1004 error when trying to access a range on the same worksheet.
Dim selectedRange As Range
Set selectedRange = Worksheets(name).Range("A1", _
Range("A" & Rows.count).End(xlUp)) 'Error Line
This code worked fine till I moved it to a module. It works if I put a
Worksheets(name).Select
before it, but I will have to do it too many times. Based on this query: VBA error 1004 - select method of range class failed
the code should work fine without a .Select. And it does as long as the code is within the worksheet. Why does moving code to a module create a problem?
U use Range and Rows properties without an object qualifier. When used without an object qualifier, this properties are a shortcut for ActiveSheet.Range / ActiveSheet.Rows.
So the code does this:
Worksheets(Name).Range("A1", ActiveSheet.Range("A" & ActiveSheet.Rows.Count).End(xlUp))
But Worksheets(name) could be different from active sheet so better is:
Worksheets(Name).Range("A1", Worksheets(Name).Range("A" & Worksheets(Name).Rows.Count).End(xlUp))
In With-End With block:
With Worksheets(name)
Set selectedRange = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With
So it is ensured that the Range/Rows properties are applied on Worksheets(name) worksheet object.
When you do things on a sheet, you do not really need explicit declarations to that sheet.
However when working on a module and interacting with other sheets, you need to specify which Sheet you want to work with. So select the sheet before you can select the range. To say, SELECT PARENT BEFORE YOU SELECT THE CHILDREN :) Please note, following is just the logic explanantion. Not the exact code syntax.
So I suggest you create the following worksheet variable and set your worksheet object that you need into that.
e.g.
Dim WS as Worksheet
Dim selectedRange As Range
Set WS = Sheets("Shee1")
Set selectedRange = WS.Range("A1", _
Range("A" & Rows.count).End(xlUp)) 'Error Line
Or else if you want to refer to all sheets, you may use each sheet's index
E.g. ThisWorkBook.Sheets(i) 'i is an integer
Then loop or whatever as it deems to your programme structure.
Further you do not have to use Select on the worksheet to point to a range in that worksheet. As per above code you could set the worksheet and set the range you need to process. When optimizing VBA execution, select is usually a taboo. Also Excel 2007 does not retain the active sheet the way older versions used to.