How to use index match formula in VBA excel - vba

I'm trying to include this index match formula in my VBA script. However, I'm having issues getting it to apply the proper formula to each line. This code adds a new column at AK and then inserts the formula.
Sub test()
Columns("AK:AK").Insert Shift:=xlToRight
Range("AK:AK").Value = "=INDEX('[BCHP Group Info Updated.xlsx]Pay to Provider (Edit) (2)'!$J:$J,MATCH(AG1,AG:AG,0))"
End Sub
The issue comes in where "MATCH(AG1" would only apply to row one and I need it to continue down for the rest of the data(MATCH(AG2,MATCH(AG3, etc.)
Is there another to reference another worksheet and match the data in order to fill this column? Or perhaps an easier way to do this with an If then statement?
Thanks

Related

Selecting columns based on specific text strings

I'm trying to put together a macro which will select certain columns and paste them into a new sheet. The problem is that columns tend to be added and deleted as people see fit which throws off the absolute referencing.
I have been trying to tinker with the basic macro produced using the macro recorder but I haven't had any luck selecting columns based on their contents. I have a sheet that is generated from our database daily with changing fields. For example, I would like to select just the Part #, Cost, and Contact fields but the addition of the IDN today threw my old macro off.
So far, I've tried to use basic excel find functions like vlookup, index against a list of constants and the find function below but none seem to work. Is there something I am missing here to select the column with my desired text?
Columns(find("Part #")).Select
Firstly, be careful with .Select and it looks like you're not fully qualifying your references to the worksheet so take note of the full Workbook.Worksheet.Range type referencing below.
Here's your quick fix:
Public Sub Test()
'the Range approach
ThisWorkbook.Worksheets("Sheet1").Rows(1).Find(What:="Part #", LookAt:=xlWhole).EntireColumn.Copy
ThisWorkbook.Worksheets("Sheet2").Range("A1").PasteSpecial xlPasteValuesAndNumberFormats 'or xlPasteAll to include formulas
End Sub
Using entire column ranges isn't usually the best idea. It will work, but only as long as you remember to paste your copied column into the first row of the destination worksheet every time.
Here's the better option (IMO):
Convert your data to a Table (know as a ListObject in VBA) by clicking "format as table" on the home tab of the ribbon. It's now much easier to reference your column - just do it by name, no need to use Find.
Public Sub Test()
'the ListObject approach
ThisWorkbook.Worksheets("Sheet1").ListObjects("MyTable").ListColumns("Part #").Copy
ThisWorkbook.Worksheets("Sheet2").Range("A1").PasteSpecial xlPasteValuesAndNumberFormats 'or xlPasteAll to include formulas
End Sub
You need to know the name of your table (I called it MyTable here), which you can do by clicking on "Table" on the ribbon when your table is selected
You need to specifically find the column, then you can paste off to a destination location, such as:
Sheets("Source").Columns(Sheets("Source").Rows(1).Find("Part #").Column).Copy Sheets("Dest").Cells(1,1)

Referencing a sheet by index number

I've got a LibreOffice Calc spreadsheet that I use to keep track of my accounts receivable at work. Each sheet lists invoices and their status (paid, unpaid, etc) as well as info about each invoice. I'm trying to create a Summary sheet that lists certain data from each sheet. Creating the sheet manually is easy, but I'm trying to "automate" the process. I want the summary page to auto-update if I add a new sheet (or remove one) as I add and remove accounts to the file.
I know that LibreOffice assigns each sheet an index number that I could refer to in some sort of formula, but I cannot find a function that I can use to refer to that index number when getting a value from a cell within it. One would expect that a function like Sheet(2) would reference the second sheet, but, alas, that is not so!
I've tried using the indirect and address functions without success, but I'm not sure if I'm not understanding these functions or if they're not appropriate for what I'm trying to accomplish.
This has been a missing piece in Calc for a long time. The preferred solution is to write a user-defined function. Spreadsheet formulas do not access sheets by index number but Basic can.
The following function is from https://ask.libreoffice.org/en/question/16604/how-do-i-access-the-current-sheet-name-in-formula-to-use-in-indirect/.
Function SheetName(Optional nSheet)
If IsMissing(nSheet) Then
SheetName = ThisComponent.getCurrentController().getActiveSheet().getName()
Else
SheetName = ThisComponent.getSheets().getByIndex(nSheet-1).getName()
EndIf
End Function
Then get a relative address of the first sheet cell A1 like this.
=ADDRESS(1,1,4,,SHEETNAME(1))
A slightly different function is given at https://forum.openoffice.org/en/forum/viewtopic.php?f=9&t=49799.

get multiple column names (header) in table associated with particular value in to a cell

i need to get multiple column names (header) in table associated with particular value in to a cell
as i explained, i need to get the heading names corresponding to value "n" to column E.
i used the formula
=INDEX((A$1:D$1),MATCH("n",A2:D2,0))
here. but it only give one column name.
i am open to vba scripts also. but i think it doesn't need vba. just improve the the above formula, may be. i tried and failed. any help. thank you guys
if you are really "open" to vba, I'll use one simple UDF like:
Function HeatherNames(rg As Range, rf As String) As String
For Each cell In rg
If cell = rf Then HeatherNames = HeatherNames & Cells(1, cell.Column).Value & "-"
Next cell
HeatherNames = Left(HeatherNames, Len(HeatherNames) - 1)
End Function
you can use it in the column E `=HeatherNames(A2:D2;"n") now you can select the arg.1 (range) and type (or referring to another cell) the arg.2
Assuming you have Excel 2010 or later, in E2:
=IF(COLUMNS($A:A)>COUNTIF($A2:$D2,"n"),"",INDEX($1:$1,AGGREGATE(15,6,COLUMN($A2:$D2)/($A2:$D2="n"),COLUMNS($A:A))))
Copy to the right and down as required.
It would actually be slightly more efficient (and certainly if your dataset in reality is quite large) to have the initial IF clause held within its own cell, such that it is calculated for each row only once, rather than for each instance of the formula within that row. So a better set-up would be, in E2:
=COUNTIF($A2:$D2,"n")
copied down. Then, in F2:
=IF(COLUMNS($A:A)>$E2,"",INDEX($1:$1,AGGREGATE(15,6,COLUMN($A2:$D2)/($A2:$D2="n"),COLUMNS($A:A))))
copied to the right and down again.
Regards

Keeping column formulas in a table header

Is it possible to have the formulas that I need applied on columns be saved or applied to a column header or some kind of metadata so that as and when I add new rows to my Excel table the Formulas get applied to the columns?
Scenarion:
I am creating a template Table, which will have no rows at first.
On a separate sheet (or same sheet for that matter) once the user selects the number of rows to be generated in the table, I dynamically add rows to the table using VBA.
The idea is I may not have any rows in the table at beginning OR user may have deleted rows manually.
When I programmatically add new rows, I want the Formulas applied on the cells as well. Most of the formulas I am using are either of the three types:
Structured table reference, Excel functions like SUM, AVERAGE etc and custom function names.
Updated:
Here is what I have tried:
1> tried applying the formula to the header itself.
Result: The header it self changes with #REF! error. I think the behavior is correct. So it's a no-go option.
2> Tried creating one row and apply the formula to the row. That works, but the problem is, I do not want a dummy row to begin with.
3> Using VBA code to add row to the table using
ActiveWorkbook.Worksheets("Sheet3").ListObjects("Table2").ListRows.Add AlwaysInsert:=True
inside a for loop.
The new rows retain the visual style sheets, but does not seem to retain the formulas. Just blank cells.
Could the fomrmulas be in header cell commnets?
And then with VBA add the formula for the current row:
Sub test()
Dim headerCells As Range
Set headerCells = Range("B2:E2")
OnNewRow 3, headerCells
End Sub
Sub OnNewRow(newRow As Integer, headerCells As Range)
Dim headerCell As Range, targetCell As Range, formulaFromComment As String
For Each headerCell In headerCells
formulaFromComment = GetFormulaFromComment(headerCell)
If (formulaFromComment = "") Then _
GoTo NextHeaderCell
Set targetCell = Intersect(headerCells.Worksheet.Rows(newRow), _
headerCell.EntireColumn)
AddFormula newRow, targetCell, formulaFromComment
NextHeaderCell:
Next
End Sub
Sub AddFormula( _
newRow As Integer, _
targetCell As Range, _
formula As String)
formula = Replace(formula, "{ROW}", newRow)
targetCell.formula = formula
End Sub
Function GetFormulaFromComment(headerCells As Range) As String
' TODO
GetFormulaFromComment = "=SUM($C${ROW}:$E${ROW})"
End Function
Just use tables.
If you highlight cells and choose Insert Table from the ribbon, it doesn't just give you formatting and filters. It also, if you build them the right way, stores column formulas once per column instead of once per cell. Also, the formulas are more readable!
For formulas, you can't use cell addresses if you want it to be a single column formula unless they are absolute. (E.g. $A$1, not A1.) Instead, you use [ColumnTitle] for the entire column (where "ColumnTitle" is the actual title of that column) and [#ColumnTitle] for the column value in the same row. So if "Cost" was the title of column B, "RunningTotal" was the title of column C and your formula for C6 was therefore =B6+C5, you'd instead use a formula of =[#Cost]+OFFSET([#RunningTotal],-1,0)] which is longer but much easier to read/maintain/debug, and if you change a column title then the formulas change too! No VBA required. Given this, plus being able change columns for the entire columns at once, plus being able to refer to other columns in other tables without worrying about cell addresses (e.g. MAX(Table1[Cost])), plus being able to style the tables so easily, plus the integration with Power-Query, and VBA support. (See learn.microsoft.com.) Whether VBA or otherwise, add a row to your table and the columns with a single column formulas will automatically carry over into the new row.
Not sure about Table templates or VBA but perhaps there is another option by using =ARRAYFORMULA()
For example, say you had a header row and 3 columns and wanted your last column to be the product of the first two. In cell C2 you could enter the following:
=ARRAYFORMULA(A2:A*B2:B)
This has three benefits:
Skips the first row completely
Effectively applies the formula to every row which is useful if you later decide to insert a row (your question)
Only one location to modify the formula for every single row
Although, it may not be immediately obvious where how/where the cells are being calculated. (hint: ctrl+~ may help)

Incrementing the row and Deleting a row using vba IN EXCEL

Range("H25")
The above statement selects the 25th row of H column.Now The thing I want to know is,
How do i increment the row putting H constant?
yeah I have seen these on the google $h24 where column stays constant and row keeps on incrementing.
But i have to increment it from H25 to the end I dont know where does H column end. how do i make that?We can declare a variable right using VBA and incremenet it?
I was thinkin to put it like these Range("Hvariablename")?
The actual Task I need to do is I have to check rows from H25 to the end and get their values to my VBA and make some calcutaions then right it back to them Im stucked at incrementing the rows.And could anyone please let me know the macro to delete a row from the vba itself?Thank you
I believe you can provide some further details about how this range is supposed to looks like. When you mean "have to check rows from H25 to the end and" what's the END here?
If you're manually copying the formula down, it will automatically goes until the last row with values in column G. Is that your case? I'm not assuming the H rows below row 25 already have some values. Is this the case?
If you use as END the last row with values in column G, you can use Selection.AutoFill.
If you already have values in column H and want to go through them, you can define a dynamic range and loop through it in VBA.
To define a dynamic range: Add a new range, based in this formula (you may need to adapt it according to your needs, obviously)
=OFFSET(Sheet1!$H$25,0,0,COUNTA(Sheet1!$H:$H),1)
And then, in VBA, go through it.
Sub TEST()
Dim oCell As Excel.Range
Dim oRange As Excel.Range
Set oRange = [TestRange]
For Each oCell In oRange
Debug.Print oCell.VALUE
Next oCell
End Sub
In time: To delete an entire row in Excel, you'll use
Sheets(1).Rows(25).EntireRow.Delete
A Do While() Loop sounds like what you might need.
Do While(cells(row,col)<>"")
'Some code to be executed on cell(row,col)
Loop
Or you could do the same thing with for loop
and find the last cell using lastRow=Cells("H24").End(xlDown).Row. (It is the same thing as pressing Ctrl+Down. so if there are empty cells between cell H25 and the end you will need to account for that).
Either way I'd definitely look into using the R1C1 cell reference style for moving through cells instead of the A1 style. You moving through lettered columns is much more difficult than numbered columns. Also you should keep in mind that the "last row" in Excel 2007 is a very high number and looping all the way until the end can take a lot longer than looping until the last important cell.
I hope that's on the right track.