I would like to put the below coding into a vba like a function. There is a bunch of data created already by VBA, and when the VBA does its work, then the following function should be run, but i dont know how to add to my vba so that the function always runs as long as data contains. The macro i created already puts the datasheet together, now instead of creating the below with lenthy codings, i just want my macro to run the below, like a man who clicks on the below right hand corner of the cell which contains the below function.
It should be something: Activesheet.ForulaR1C1 = "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))" something. Can someone help me? Thanks
ORIGINAL FUNCTION TO BE RUN "=RIGHT(AY4,LEN(AY4)-FIND(".",AY4))"
This is where I am at now:
Sub Project_numbers()
Dim j As Integer
Zorro = Range("AY" & Rows.Count).End(xlUp).Row
o = 4
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(AE4,LEN(AE4)-FIND(".",AE4))"
o = o + 1
End Sub
You have a couple of problems here. The biggest is that you've got quotation marks in your formula. VBA reads these as the end of the string, so it's interpreting your formula as two separate text strings: =Right(AE4,LEN(AE4)-FIND( and ,AE4)), separated by a .. This isn't a structure VBA can do anything with, so it's going to fail at that point.
When you're inserting a formula with VBA that contains quotation marks, you need to use two quotes together to indicate that it's a literal quote mark that's part of the string, rather than the end of the string:
"=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The second problem is that you're using the FormulaR1C1 method, which expects cell references to be given in R1C1 (row#column#) notation, rather than A1 notation, but then passing it a formula that uses A1 notation. Again, this is going to confuse the issue and produce errors.
I'm guessing you used the macro recorder to get the syntax, then inserted your own formula? The macro recorder, for some weird reason, loves to use the R1C1 reference style, but we can use a different method for written code.
The full line you need is:
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
EDITED TO ADD:
With further information, specifically that you need the range referenced to change as you loop, you have some options on how to do it.
1. Use the R1C1 reference style
This allows you to include relative references in formulae easily. You'll use R to designate the formula's row, and C to designate its column; so a cell that referred to itself would simply be =RC. You can follow the R and C with numbers to designate specific rows and columns, so cell B2 would be =R2C2 - row 2, column 2. More usefully, you can use =R[#]C[#] to offset your formula by a certain amount.
In your formula, assuming it's always going to be looking at column AE but whichever row the formula is entered into, your line would be:
Worksheets("MJE").Range("AF" & o).FormulaR1C1 = "=RIGHT(RC31,LEN(RC31)-Find(""."",RC31))"
2. Build your formula from variables.
You already have a variable you can use, o, so we can combine that with the rest of the string to get the appropriate references. It's harder to read, though...
Worksheets("MJE").Range("AF" & o).Formula = "=RIGHT(AE" & o & ",LEN(AE" & o & ") - FIND(""."",AE" & o & "))"
Personally, I find this method rather cumbersome to work with, but it's an option.
3. Assign the formula to your entire range as a single operation
Personally, I prefer this option; I find it to be the neatest one. I'm assuming, from your formula, that your data starts on row 4, and you want the formula to go into every cell between AE4 and the end of your data, which is stored in Zorro. You can use this line to add the formula in one go:
Worksheets("MJE").Range("AF4","AF" & Zorro).Formula = "=RIGHT(AE4,LEN(AE4)-FIND(""."",AE4))"
The cell references will update automatically for each row. There's no need for a loop with this method - of course, if you're looping anyway, that may be no great saving.
Related
I have a macro button in worksheet 2 and want it to put a formula into a column of worksheet 1.
For example I can do a simple sum formula such as:
Sheets("worksheet1").Range("I:I") = "=SUM(M:M)"
This works but when I try and do it with the actual more complicated formula I want it will not work.
Why is this?
Sheets("worksheet1").Range("I:I") = "=IF(ISNUMBER(SEARCH("*567*",B:B)),"INSTOCK","")"
Writing a double quote like you did makes VBA think you ended your string after just writing "=IF(ISNUMBER(SEARCH(". In fact, this code will error out. You'll need to double-up your quotes. A great way to understand what you are writing would be to use Debug.Print first:
Debug.Print "=IF(ISNUMBER(SEARCH(""*567*"",B:B)),""INSTOCK"","""")"
So this will work:
Sheets("worksheet1").Range("I:I") = "=IF(ISNUMBER(SEARCH(""*567*"",B:B)),""INSTOCK"","""")"
Note: since you are using whole column references, this is going to be heavy on your calculation!
I need to write a macro.
I've got a workbook with ~ 30000 rows (changes daily).
I need to search for expression "TRADE" within the strings in cells from column (A)
If string inside the cell contain expression TRADE I need to change string in relevant cell in column (B) (the same row) to expression "TRADEIN"
If condition is not met relevant cells from column (B) need to stay unchanged
What have I learned so far:
Formula =IF(ISNUMBER(FIND("TRADE", A1 )), 1, 2) changes adjacent cell value accordingly ONLY if placed directly inside cell and copied down in Excel.
Problems starts when I try to have string as an outcome
Formula: =IF(ISNUMBER(FIND("TRADE", A1 )), "TRADEIN", "") won't work ->error
Formula: =IF(ISNUMBER(FIND("TRADE", A1 )), ""TRADEIN"", "") won't work ->error
Then any attempts to make my macro insert more complex formulas into cells from VBA failed i.e.:
Below works fine:
For i=1 to i=NumberOfRows
ActiveSheet.Cells(i, 2).Formula = "= 2+2"
next i
Below won't work (again, formula works if placed in the cell directly):
For i=1 to i=NumberOfRows
ActiveSheet.Cells(i, 2).Formula = "=IF(ISNUMBER(FIND("TRADE", (i, 1)), 1, 2)"
next i
I think there's no point in listing all my failed attempts to make it work so far (loads of useless lines to read I presume) but by all means - correct me if I'm wrong.
I can't find solution as specific as my task and have got problems altering some found online whilst other won't work for me at all. Perhaps don't exactly know how to ask for what I need in the most effective way. Be very basic and try not to miss out any declarations from proposed modules/subs if you can - I'm not yet confident when it comes to using and creating objects and methods outside of a few examples I followed, or choosing/using the right type of variables with compatible methods/functions etc.
Using VBA this is how would accomplish the goal. This will find the last row used in column A to set the range to work through.
Sub test()
Dim w As Range
lrow = Range("A1", Range("A" & Rows.Count).End(xlUp)).SpecialCells(xlCellTypeVisible).Count
For Each w In Range("A1:A" & lrow).Cells
If w.Value = "trade" Then
w.Offset(0, 1).Value = "tradein"
End If
Next w
End Sub
Practice using the auto filter, once you have that worked out use the macro recorder to get a code to work on.
Select column A and the goto Data=>Filter=>text Filter=>Contains....type the word in the box to filter for.
I'd like to use something like the EVALUATE-Function in Excel for if-statements.
I've got the following issue: I'd like to use Excel to validate my data. I've got three sheets:
the real data I'd like to check. Each row represents a customer and each column some data. The columns have specific names like “age”, “name”, …
the description of the checks I’d like to perform. Each row represents one check and I’ve got 3 columns: 1 check_id – an identifier of each check; 2 check_desc – a description of the check that every normal person can understand like “Age below 18”; 3 rule – the Excel Formula as a string like If(age<18, “error”, “no error”)
the place where sheet 1 and 2 should come together. Each row should represent one customer and each column one check.
Now, if I’ve got for example check_1 “If(age<18, “error”, “no error”)” and the customer data 10 and 20, then the check for the first customer should fire and the check for the second shouldn’t.
If the data is changed, and the age is set from 10 to 18, then everything should be fine, or if the rule is changes to “If(age<21, “error”, “no error”)” then the new condition should be applied to all data.
Is something like this possible?
With the evaluate function only ‘simple’ formulas work.
Thanks in advance,
Martin
Attached you can find the
Excel-Sample File
You will definitely need some VBA here. Make a custom EVAL function:
Public Function EVAL(ByRef Rng As Range, Formula As String) As Variant
Dim RngAddress As String
RngAddress = "'" & Rng.Parent.Name & "'!" & Rng.Address(External:=False)
EVAL = Evaluate(Replace(Formula, "$", RngAddress))
End Function
Then you can easily evaluate your values with formulas passed as text ($ is for parameter):
=EVAL(A1, "IF($<21,""error"",""no error"")")
(note the escaped double quotes). But you would rather pass formula from another cell - then you can specify formula in cell with single quotes:
IF($<21,"error","no error")
=EVAL(A1, B1)
I personally would rename check_desc!B2 to "Check_1" (named range) and then refer to that. You can use the INDIRECT function as well once you've renamed your column header "Check_1" as well.
Note: the value in this case should be "18" instead of "age below 18". You can of course change the number format to "age below "0.
If the relations are changing too I would insert a table that would have uniform formulae changing in each cell when changed in one cell.
The only issue you would then face is the non-expanding nature of your table. You can use VBA for this, but maintaining formulae increases your accountability even if it would be slightly easier not to deal with nasty nested functions.
I'm using Excel VBA to insert an HLOOKUP function at the end of a given row. I've been attempting to use the R1C1 functionality in VBA for inserting the HLOOKUP function, which should appear as follows in Excel:
=HLOOKUP(D2,'DM NYASSOV'!3:34,32,0)
My issue is that I need the HLOOKUP to be dynamic enough that it can reference variables from the same row on which the HLOOKUP function is to be pasted.
Currently my VBA reads as follows:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
RC[-17] references the variable I'm looking for;
RC[-19] is the underlying book/tab identifier;
RC[2] contains the initial row value, and
RC[3] contains the final row reference range.
My main issue is with correctly identifying the dynamic range selection:
'DM NYASSOV'!3:34 / 'DM RC[-19]!'RC[2]:RC[3]
Any pointers are greatly appreciated.
I think you have a few issues here. First is using VBA to dynamically build a formula that then calculates a third value that then gets used in the formula which finally calculates a result. This seems like an unnecessary amount of runaround for a value that can be done with either a formula built on the front end or calculated via VBA in the back end. The second is all the dynamic lookup of it all. It's not so much a problem, but rather a lot to keep track of as you jump through the four hoops. Just the same...
The first parameters of your HLOOKUP can either be a value like "SM1804" or a reference to a cell that contains "SM1804". You can either use VBA to bring this value directly into the formula and save Excel some processing by having to lookup that value at formula processing time:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(" & Sheets(selectTab).Cells(r, 21).Offset(0, -17).value & ",'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
Or you can stick the reference to the cell in there (which is what you are doing now):
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],'DM RC[-19]!'RC[2]:RC[3],RC[3]-RC[2]+1,0)"
On to the second parameter... I believe you have a sheet name in DM!RC[-19] This is totally OK, but you'll need to use 'Indirect' to get that sheet name into the HLOOKUP formula:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],Indirect("'" & DM!RC[-19] & "'!RC[2]:RC[3]"),RC[3]-RC[2]+1,0)"
...this is where things get a little tricky. If, for instance, in DM!RC[-19] you have the sheetname "Sheet1" then indirect is going to return: 'Sheet1'!RC[2]:RC[3] and your HLOOKUP will use that range to do the lookup... Doesn't make a lot of sense to do a HLOOKUP on a range with two cells. So I assume that you have number values in RC[2] and RC[3] there that represent rows. So really the indirect would have to look like:
ThisWorkbook.Sheets(selectTab).Cells(r, 21).FormulaR1C1 = "=HLOOKUP(RC[-17],Indirect("'" & DM!RC[-19] & "'!R" & RC[2] & "C:R" & RC[3] & "C"),RC[3]-RC[2]+1,0)"
Now if your RC[2] has the value "4" and your RC[3] has the value "20" your indirect will return: 'Sheet1'!R4C:R20C and your HLOOKUP will use that value as the range in which it will look up.
You are also doing some math on those values in RC[2] and RC[3], so that's probably all good and doesn't need to be changed. You just need to keep in your head what VBA is going to return as a formula, and then what that formula is going to get from Indirect and then what the resulting HLOOKUP is going to find.
It's a lot to keep track of and may be simplified just by writing the formulas directly in the cell and copying down, or just doing the HLOOKUP functionality directly in VBA.
I want to count the number of numbers in a single cell.
Example:
In cell A1, I have the following addition:
=12+45+23+51+10 which totals (and shows) 141.
In cell B1, I would like the see how many numbers have been added together, which means that there should be 5 (12 is a number, 45 another one, etc... and all together, there are 5 numbers in cell A1).
I know it seems to be a ridiculous question, but I scanned all the platforms for this issue and did not find any suitable solution. Tried all the LEN and LEN SUBSTITUTE alternatives out there, but somehow it does not work.
Thank you upfront for your help. Optimal solution would be a excel formula, alternatively VBA would also work.
Excel 2013 has a new function Formulatext() which returns the, well, formula text. Using that the Len() and Substitute() approach works.
=LEN(FORMULATEXT(A1))-LEN(SUBSTITUTE(FORMULATEXT(A1),"+",""))+1
Hit Alt+F11 and Insert->Module with the following VBA:
Function NumCount(Rng As Range)
x = Split(Rng.Formula, "+")
NumCount = UBound(x) + 1
End Function
Then you can call =NumCount(A1) on any cell to get the number of numbers in the formula for that cell.
Use this VBA:
Function GetFormula(Cell as Range) as String
GetFormula = Cell.Formula
End Function
and then to get the number of numbers...
=LEN(GetFormula(D99))-LEN(SUBSTITUTE(GetFormula(D99),"+",""))
on this as my D99 contents...
=45+46+47+50+100
The one major drawback here is that I'm assuming everything is + if you have -, *,/ or other operators this gets more challenging. you might be able to use replace for each but you'd always be limited to the 4 basic operators... if someone used exponents or mod, this would be harder.
Also possible in earlier Excel versions without VBA - subject to (i) there is always at least one value in the cells, (ii) the operator is always + and (iii) the cells are in a column.
Replace = with '= in that column, apply the substitution, say:
=LEN(A1)-LEN(SUBSTITUTE(A1,"+",""))+1
in a different column and Paste Special, Value the results for that other column. Then apply Text To Columns on the original column with ' as the delimiter.
*There is no way to do this without using a User Defined Function (UDF) written in Excel VBA. Something like this should work:
Public Function numsAdded(cell1 As Range)
Dim formulaString As String
formulaString = cell1.Formula
numsAdded = Len(formulaString) - Len(Replace(formulaString, "+", "")) + 1
End Function
Once you've added that to a VBA module, you can use it as a function in any cell in your spreadsheet.
*Edit - Apparently there is a way if you have Excel 2013, as teylyn suggests. If you use 2010 or earlier like me, you'll need VBA.
Try this:
=LEN(SUBSTITUTE(F16,"+","+"))
Note: F16 is only an example name for the cell you want to do the counting on.
Example:
F16=45+65+76 # Gives 186
F17=LEN(SUBSTITUTE(F16,"+","+")) # Gives 3