Converting MATCH array formula to VBA code - excel

I'm attempting to convert the formulas in a sheet into VBA code in a macro, and am stumped by the following:
{=IF(ISNA(MATCH($A8&$B8&$C8&E$7,'Raw Data'!$E:$E&'Raw Data'!$D:$D&'Raw Data'!$C:$C&'Raw Data'!$G:$G,0)),"","Yes")}
It's trying to look at multiple columns in one sheet, compare them to another, and see if the value of the column header is in the fourth column "G" to return "Yes" or blank. I've attached a screenshot of the sheet it fills out:

This array formula will take a long time to compute, since each column has over one million rows. Array formulas should not use whole column references.
The same result can be returned with a non-array formula, which can be used in VBA without any special commands.
=IF(ISNA(MATCH($A8&$B8&$C8&E$7,Index('Raw Data'!$E$1:$E$1000&'Raw Data'!$D$1:$D$1000&'Raw Data'!$C$1:$C$1000&'Raw Data'!$G$1:$G$1000,0),0)),"","Yes")
If you want to use an array formula in VBA, you will need .FormulaArray instead of .Formula or .FormulaR1C1
If you don't want to enter a formula into a worksheet cell, but perform the calculation in VBA, you can use Worksheetfunction (https://learn.microsoft.com/en-us/office/vba/api/excel.worksheetfunction) to use the worksheet functions and their syntax.

Related

How to only run a formula if the cell is blank

I am writing a formula to run a matching analysis on some elements of a spreadsheet. The column containing the formula already has values filled in, but I need to run the formula on the blank cells. The formula is working but overwriting the current info I have within the filled cells.
I have tried a VBA code which got too complicated and did not work. With VBA I tried inserting the formula into only the blank spaces but was having some issues. I have also tried a basic excel formula.
=IF(COUNTIFS(A:A,A2,BU:BU,"CLOUD")=0,"Not Cloud",IF(COUNTIFS(A:A,A2,BU:BU,"NOT CLOUD")=0,"Cloud","Hybrid"))
VBA Code I tried:
If (IsEmpty(Bucket) Or Bucket = "" Or Bucket = vbNullString) And _
(GetCellValue(.Cells(i, "BU")) = "CLOUD") Then
Range("CC:CC").Formula = "=IF(COUNTIFS(A:A,A2,BU:BU,""CLOUD"")=0,"Not Cloud", _
IF(COUNTIFS(A:A,A2,BU:BU,"NOT CLOUD")=0,"Cloud"","Hybrid"))"
A reminder this is a high-level version
I want that formula to only run in the cells that do not have a value already in place. It should not overwrite the data from the VBA script that I previously ran before doing the formula. The disposition column should be completely full of values. The formula needs to run in only the blank cells.
You could achieve this with an additional column.
In the column to the right of Disposition (insert one if necessary) write the following formula (example for row 2, assuming Disposition is Column C):
=IF(C2=""; [Your formula here]; C2)
This will provide you with a column full of values, anytime you put a value into column C it will override the formula.
Edit: You can then copy this formula down the entire column to achieve the desired effect.

Excel VBA - Convert a string Formula to an Excel Calculation in a range of cells

I'm just wondering if this is possible to do without a loop - In my excel sheet, in, say, Range("A1:C10") I have text concatenation formulas that, once concatenated, create real Excel functions.
As a stupid example, suppose I had the following in cell A1:
A1: ="=Sum(D"&C2&":E"&C3&")"
Now, I know in VBA I can do something along the following for any one specific cell:
Range("A1").Formula = Range("A1").Text
And it will convert my text formula into an Excel formula and evaluate it.
Now, what I'm curious about is, whether there a way to say, for example:
Range("A1:C10").Formula = Range("A1:C10").Text
Without looping through each cell individually?
Also, I can't use INDIRECT() as, unfortunately, my formulas refer to closed workbooks :/
Any ideas??
Range.Text contains the string representation of the cell's value. The actual calculated value (which I suspect is what you're after) is accessed using Range.Value - try this:
Range("A1:C10").Formula = Range("A1:C10").Value
Not sure if this is what you are trying to do, but if for example you use:
Range("A1:C10").Formula = "=Sum(D1:E1)"
then the relative references will be auto adjusted:
A1: =Sum(D1:E1)
A2: =Sum(D2:E2)
B1: =Sum(E1:F1)
... etc.

How to extract column from cell (Excel, VBA)

I'm running into a (run-time error '1004': Application-defined or object-defined error) error while trying to write my first Excel VBA Macro. I've looked at similar questions on stack overflow and other sites, but my issue seems to be more basic than issues others are having.
Currently, I'm trying to take the data from two cells from one sheet and write them to another sheet. I understand that trying to find the column or row of a cell that I reference by cell or row is unnecessary, but eventually I will use for-loops and will substitute the specific cell references with variables.
Here are the two lines of code that I have:
Worksheets("Sheet2").Range("A1").Value = Worksheets("Sheet1").Range("A" & Worksheets("Sheet1").Range("B2").Row).Value
Worksheets("Sheet2").Range("B1").Value = Worksheets("Sheet1").Range(Worksheets("Sheet1").Range("B2").Column & "1").Value
The first line runs fine. It writes Sheet1's A2 to Sheet2's A1.
The second line does not run, does not write Sheet1's B1 to Sheet2's B1, references the error, and I'm not sure why.
Thank you for your time and help!
The .Columns property returns an integer, not a letter. Use the Range.Cells property if you want to define a range with a numerical row and numerical column.
Worksheets("Sheet2").Range("B1").Value = Worksheets("Sheet1").Cells(1, Range("B2").Column).Value
I suppose there is a larger purpose to this but as it sits, it is very verbose code.
your last lines from your question say that you want to fill Sheet2-A1 with Sheet1-A2 and Sheet2-B1 with Sheet1-B1
the most straightforward way is
Worksheets("Sheet2").Range("A1") = Worksheets("Sheet1").Range("A2")
Worksheets("Sheet2").Range("B1") = Worksheets("Sheet1").Range("B1")
I am a beginner at VBA just like you. You don't need to know everthing in VBA to make productive use of it. I made my first macro by RECORDING it, and it worked (but was hopelessly inefficient).
I had a problem similar to yours: looking up data on another worksheet. I created the following function:
Function GetMyNumber(C3ll)
MyCol = C3ll.Column
GetMyNumber = MyCol
End Function
To use it in a spreadsheet, just enter the formula into some cell, like D5,
=GetMyNumber(D5)
When you recalculate, the number 4 appears in cell D5. If you copy cell D5 into Cell F3, you will see in F3, =GetMyNumber(F3), and calculate will return a 6. Of course you can fill down or across, the argument is changed to the cell the formula is in. And if you want, you can offset with an argument referring to any cell.
Once you get this working, you can insert the code to do you matching and other tasks that make use of your column number MyCol to extract the number from the other worksheet. Remember, MyCol is an integer.
Hopes this helps.

vba code to change column formula by dynamic dragging

i need to write vba code wherein cell GQ4 has formula
ActiveCell.Formula = "=SUM(CO4:CQ4)"
Now there is new month added every month in excel data hence the formula will also change dynamically every month.
ie next month it will be
"=SUM(CP4:CR4)"
in short it is dragging its column selection by 1 column
Please help me write a vba code that will dynamically change the formula.
Note sure if it is possible to return a formula from a custom function, but a solution might be to write a custom function that returns the range you want, and then have the formula in GQ4 take the range as an argument.
Or you can solve it with a normal worksheet formula.
=SUM(INDIRECT(ADDRESS(4;15));INDIRECT(ADDRESS(4;16));INDIRECT(ADDRESS(4;17)))
Replace the column numbers with a base + offset that you can get by using a date function. E.g.
=SUM(INDIRECT(ADDRESS(4;14 + =MONTH(TODAY())));INDIRECT(ADDRESS(4;15 + =MONTH(TODAY())));INDIRECT(ADDRESS(4;16 + =MONTH(TODAY()))))

HLOOKUP in R1C1 notation

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.

Resources