Rules for escaping formulas and variables - excel

I know it's been asked several times, but I just don't get it.
I'd like to know the rules in order to correctly build VBA code which incorporates formulas and variables in a VBA Evaluate function.
This works ok:
stringa_per_mesi = "=DATEDIF(""" & d1 & """,""" & WorksheetFunction.EDate(d1, 12) & """,""ym"")"
mesi = Application.Evaluate(stringa_per_mesi)
I have to write a more complex formula with Evaluate but I get lost, so I have to solve the doubts I have.
In the above example, why couldn't I just write
stringa_per_mesi = "=DATEDIF(d1, & WorksheetFunction.EDate(d1, 12) & """,""ym"")"
and why this works
WorksheetFunction.EDate(d1, 12)
even without quotation marks here (d1, 12)?
Thank you!

Related

Runtime Error 1004 when replacing formula

I am using the following code to add something to a Formula in VBA (for debugging purposes I am using the variable currentFormula, instead of doing it directly):
currentFormula = Range("A" & row).Formula
currentFormula = currentFormula & "+" & CStr(difference)
Range("A" & row).Formula = currentFormula
When going through the code step by step, the variable currentFormula has the correct value before the final step, e.g. "=A1/A2+0.5". However, then the script Fails with runtime error 1004. When I am Setting currentFormula manually to something like "=10+10", the script works.
CStr formats the number according to the current system locale.
Formula accepts formulas in English.
The function that converts numbers to strings in an invariant way is Str. Note that it prepends a space to positive numbers which you might want to remove:
currentFormula = currentFormula & "+" & LTrim$(Str$(difference))

Comparing Textbox value to cell value

I programmed a communication tool for the production floor. This tool will register what they have done, who has done it and on what time.
The following should check whether the textbox value equals the value in the worksheet or if the textbox (textbox is TextTools1) is empty. If this is true, then nothing should happen and the thus the value of the textbox is gonna stay the same.
If the textbox is not empty or is not equal to what has been previously saved in the worksheet (thus the value has changed), then it should be registered which operator has done it and what date and what time.
It works when the textbox is empty, but when the value of the textbox has stayed the same (thus TextTools.value=ActiveCell.Offset(0,23).value (Correct)) it still adds the operators name, date and time.
Something is going wrong when trying to compare the textbox value and the cell value, but cant put my finger on it.
Sheets("Checklist & overdracht").Visible = True
Sheets("Checklist & overdracht").Select
If TextTools1.Value = Range("AZ1").Value Or TextTools1.Value = Empty Then
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value
Else
Sheets("Checklist & overdracht").Select
rowloc1.Value = ActiveCell.Row
ActiveCell.Offset(0, 23).Value = TextTools1.Value & " " & "(" & cboOperator.Value & " " & Format(DateValue(CStr(Now)), "short date") & " " & Format(TimeValue(CStr(Now)), "hh:mm") & ")"
End If
Edit; changed it to the code above. I tested this in another userform (and used f8) and it works brilliantly, but when I put in the userform that will actually run this code, than it doesnt have the same result...
Edit2; So apparently something goes wrong with Range(AZ1).Value reference. Because when I enter a random value instead of the range and then run the code, it does work. Is there a different way of referencing?
Ok based on your comments
Stop using active cell when code from a user form is communicating to the compiler what sheet is what. You need to fully qualify what sheet you are using. Im not entirely sure where in the code the active sheet is being set but I am fairly certain the answer is never. Another reason selecting and referencing .ActiveWhatever is bad is a cardinal sin of vba is interacting with the actual application object instead of doing everything in memory. It bogs everything done and performance suffers considerably. When you start writing pretty dense stuff then you will inevitably suffer from issues where the compiler gets confused as to what thing it should be looking at and you'll have a grand ol' time of troubleshooting that nonsense.
Also, it might be a good idea to check for more than just "=Empty". What if there is a null or empty string? I tend to check for:
.value = "" OR ISNULL(.Value)=True OR .Value = vbNullstring
this isnt real feedback though - tons of people have different ways of doing the same thing.
Try:
Thisworkbook.Sheets("YOURSHEETNAME").Range("YOURRANGE").Offset(0,23).Value = Someothervalue.
Let me know if youre still facing issues.

Unable to add if statement as exceeds level of nesting allowed?

I have a list of 5 if statements in my formula, i am wanting to add a 6th, but it won't let me and says I have exceeded the level of nesting allowed.
Can someone please show me how I can add the following to my code?
IF(COUNT(SEARCH({"BTF","BTH","BTO","BTP"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_2.msg"),"")
Code:
=IF(COUNT(SEARCH({"XWS","XWW","XWO","XVV","XVS","XVO","XVH","XTO","XTA","XSW","XSV","XST","XSS","XSS","XSR","XSP","XSL","XSJ","XSH","XSG","XSF","XSE","XSD","XSC","XSB","XSA","XS5","XS2","XPO","XMO","XMF","XLS","XLP","XLO","XLL","XLB","XKT","XKR","XKO","XKH","XKE","XKD","XJS","XHO","XHL","XHF","XHA","XGO","XFT","XFO","XFC","XFA","XDO","XBS","XBO","XAO","WHO","PSO","PRO","PRM","PRE","PPT","PLO","PGW","PGV","PGT","PGS","PGR","PGP","PGH","PGF","PGE","PGB","PGA","PFP","PDC","PDB","PCP","PBO","OFD","MWW","MWC","MTT","MSP","MSO","MRM","MPP","MPO","MPF","MNO","MMW","MMS","MMP","MMI","MLO","MJO","MHH","MGO","MFO","MEE","MEB","MDO","MCO","MAT"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_PLANT2.msg"),
IF(COUNT(SEARCH({"XCT","XCO","XCA"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_CRANE2.msg"),
IF(COUNT(SEARCH({"XJO","XJS"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_OPERATOR2.msg"),
IF(COUNT(SEARCH({"LTV","LTH","LSW","LMC"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_3PL2.msg"),
IF(COUNT(SEARCH({"UUU","KKK","PPP","ACO","ARC","BCO","BCP","BFA","BFI","BFL","BFP","BHO","BPO","BSO","BTF","BTH","BTO","BTP","CMA","CME","CMF","CMH","CML","CMN","CMP","CMZ","DHA","EAA","EAP","ECC","ECC","ECE","EPM","EPO","FPA","FPB","FPC","FPD","FPE","FPF","FPH","FPI","FPJ","FPL","FPM","FPN","FPO","FPP","FPR","FPS","FPV","FPW","FSC","FUE","FUG","FUW","FWC","FWG","FWH","HPO","ICH","ICM","ICN","ICS","ITL","ITM","QMO","RSS","RTT","SFG","SLB","SLC","SLR","SLT","SMA","SMC","SMM","SMP","SMR","SSF","SSG","SSV","STA","STO","UEO","UGO","UWO","ZFO"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_2.msg"), IF(COUNT(SEARCH({"BRL","BRP","BRS"},G18)),HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\EMAIL_RECRUITMENT2.msg"),
""))))))
I agree with #Rowland Shaw regarding a separate table with lookups.
But if you are set on numerous IF() than just return a blank as the false result of each, and concatenate all the results.
=
HYPERLINK("\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\assets\"
&
IF(COUNT(SEARCH({"XWS","XWW","XWO","XVV","XVS","XVO","XVH","XTO","XTA","XSW","XSV","XST","XSS","XSS","XSR","XSP","XSL","XSJ","XSH","XSG","XSF","XSE","XSD","XSC","XSB","XSA","XS5","XS2","XPO","XMO","XMF","XLS","XLP","XLO","XLL","XLB","XKT","XKR","XKO","XKH","XKE","XKD","XJS","XHO","XHL","XHF","XHA","XGO","XFT","XFO","XFC","XFA","XDO","XBS","XBO","XAO","WHO","PSO","PRO","PRM","PRE","PPT","PLO","PGW","PGV","PGT","PGS","PGR","PGP","PGH","PGF","PGE","PGB","PGA","PFP","PDC","PDB","PCP","PBO","OFD","MWW","MWC","MTT","MSP","MSO","MRM","MPP","MPO","MPF","MNO","MMW","MMS","MMP","MMI","MLO","MJO","MHH","MGO","MFO","MEE","MEB","MDO","MCO","MAT"},G18)),"EMAIL_PLANT2.msg","")
&
IF(COUNT(SEARCH({"XCT","XCO","XCA"},G18)),"EMAIL_CRANE2.msg","")
&
IF(COUNT(SEARCH({"XJO","XJS"},G18)),"EMAIL_OPERATOR2.msg","")
&
IF(COUNT(SEARCH({"LTV","LTH","LSW","LMC"},G18)),"EMAIL_3PL2.msg","")
&
IF(COUNT(SEARCH({"UUU","KKK","PPP","ACO","ARC","BCO","BCP","BFA","BFI","BFL","BFP","BHO","BPO","BSO","BTF","BTH","BTO","BTP","CMA","CME","CMF","CMH","CML","CMN","CMP","CMZ","DHA","EAA","EAP","ECC","ECC","ECE","EPM","EPO","FPA","FPB","FPC","FPD","FPE","FPF","FPH","FPI","FPJ","FPL","FPM","FPN","FPO","FPP","FPR","FPS","FPV","FPW","FSC","FUE","FUG","FUW","FWC","FWG","FWH","HPO","ICH","ICM","ICN","ICS","ITL","ITM","QMO","RSS","RTT","SFG","SLB","SLC","SLR","SLT","SMA","SMC","SMM","SMP","SMR","SSF","SSG","SSV","STA","STO","UEO","UGO","UWO","ZFO"},G18)),"EMAIL_2.msg","")
&
IF(COUNT(SEARCH({"BRL","BRP","BRS"},G18)),"EMAIL_RECRUITMENT2.msg","")
)

Overwriting a formula in Excel using VBA

Here is the formula in question.
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I29>='Raw Data'!K2),--(I23:I29<='Raw Data'!K3))"
This works fine, but what I want is instead of I23:I29, I want it so that when I did a "lastrow" formula in excel VBA, it will replace the I29, with the I and whatever the response in the last row actually is.
I figured that to make this happen I'd have to break the parentheses, but I wasn't sure if it was the correct thing to do.
What I thought I'd have to do is this:
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I" & lastrow">='Raw Data'!K2),--(I23:I" & lastrow"<='Raw Data'!K3))"
But it doesn't look right. And Excel is giving me a redline for it as well, so I know I'm not doing it correctly. Can someone help me figure out this little nightmare?
Close - watch out, and make sure the & are between every part of the string build:
.Range("F5").Formula = "=SUMPRODUCT(--(I23:I" & lastrow & ">='Raw Data'!K2),--(I23:I" & lastrow & "<='Raw Data'!K3))"

vba Using Eval but maintaing internal string

So I am using Instr with Evaluation and facing some difficulties
The code is as follows
myIneq=">"
myString1="Hello"
myString2="el"
Evaluate( "Instr(" & myString1 & "," & myString2 & ")" & myIneq & cstr(0)
I am getting an Error 2029. Based off this msdn link I am assuming it is trying to evaluate "Hello" as a variable name. What is the work around for this, I know there must be one.
Thanks
I infer from the Error 2029 (#NAME?) and the link that you're using Excel. In this case the answer is simple. Application.Evaluate evaluates Excel expressions, not VBA code. That is, any functions you call in your expression have to be things you could call from an Excel formula. (And you're correct that Excel is trying to evaluate the value of a symbol it doesn't recognize, and is thus giving you back a #NAME? error.)
There is an Excel worksheet function, FIND, that does pretty much the same thing that the VBA function Instr does, so if your example is not too simplified, that might be all you need to do.
I just typed this into the Immediate window:
x="Hello"
y="el"
?Evaluate("FIND(""" & y & """, """ & x & """)")
2
ineq = ">"
?Evaluate("FIND(""" & y & """, """ & x & """)" & ineq & "0")
True
and it seems to work.
Note that Evaluate is a function, so it expects to receive a string argument, and then return what that string evaluates to if treated as an Excel formula-syntax expression. In your example, you don't seem to be doing anything with the return value, so I thought I'd mention it.
"Evaluate" doesn't understand all excel functions.
For example, trying to evaluate "instr" will give an Error 2029. But there is a nice workaround:
"evaluate" recognizes all added vba functions of your excel sheet
so just wrap a single-line function around the reluctant function.
Code will be similar to this:
Sub test()
MsgBox Evaluate(" Instring(""Hello"",""el"") ")
Msgbox "\o/ ! ... I owe a beer to someone out there"
End Sub
Function Instring(a, b)
'make instr visible to 'evaluate'
Instring = InStr(a, b)
End Function
You're evaluating the string InStr(Hello,el).
Obviously, that's not what you want.
You need to use a quoted string literal.

Resources