Excel - If + Index Match + Offset -- VBA or something else? - excel

I made a dummy version (fake names and extremely shortened) of the 2 spreadsheets I'm working with this spread sheets
Background:
I'm automating the data between Contracts and our Accounting Team's template. Note that neither of these spreadsheet's formats can budge so that why I'm stuck. It's a clunky process that I am trying to automate. The main source of data is the "Contracts" tab. Let's say out of the 300 subcontractors projects, in the week of 1/24/2019 my coworker approved 130 of the projects. The logic of what I am trying to accomplish:
In the Contracts tab, if Column R is "Yes"--
In the "Accounting Template" tab (the one with formulas) Column B, pull all the cells of Contracts!A of the vendors we are set to pay.
The same applies to Template! (a nickname for the path) Column M, pull the specific contract ID's of the approved Contract ID's from Contracts!C.
Note I intentionally showed that my fake Puppies program is NOT approved to get their payment, this will help demonstrate how to resolve my issue
My key issue is that the Accounting Template skips every 3 rows for the Project, and the Contracts row has Project day every single row. So, for Template!A5, I am pulling data from Contracts!A2, and Template!A8 I am pulling data from Contracts!A3, etc.
I was able to (sort of) make this work with an offset, row and index match:
=OFFSET(INDEX(Contracts!$C$2:$C$167,MATCH(ROWS(Contracts!$A$2:A17),Contracts!$AB$2:$AB$167,0)),-10,0)
See that negative -10? For each new 3rd row I am starting at template, I'm manually changing it to -10, -12, -14, etc etc. Not exactly sophisticated.
Looking at how offset and row work, it looks as though they heavily rely on the coordinates of cells in the Contracts workbook. However, I ideally am looking to do this:
=IF(Contracts!R2="Yes",OFFSET(INDEX(Contracts!$C$2:$C$167,MATCH(ROWS(Contracts!$A$2:A5),Contracts!$AB$2:$AB$167,0)),-2,0))
However, once I throw a conditional (IF) in the mix, that reorientating the rows of my offset match. Are there better formulas for what I am trying to accomplish? A VBA script that could accomplish this IF, INDEX, MATCH, OFFSET, ROW dream of mine? I'm not married to either of these formulas.
I've perused a few VBAs but nothing seems to have a conditional like IF as a component.
EDIT:
Per a request, adding screenshots. There's also a Google Sheet link:
Contracts tab, purposely hiding irrelevant columns:
Accounting Template Tab:

I'd do it with VBA, but this formula example might help you start. If your issue is basically turning horizontal data into vertical data and you have a fixed interval of 3 rows. You will need to adapt the formulae for your actual set up.
The formulas used are:
F1 and down =IF(MOD(ROW()-1,3)=0,INDEX($A$1:$A$3,(ROW()+2)/3),"")
G1 and down =INDEX($B$1:$D$3,CEILING(ROW(),3)/3,1+MOD(ROWS($G$1:G1)-1,3))
I'm sure there are better ways ...

Related

Excel design consideration - infrequent change and impact for VBA/formula/add-on

nothing stuck or broken, just I am inspired after a discussion with another Excel author.
His situation:
Read from an existing Excel monster file (column FG), and hard-coded the following
Range("FF:FG").Copy
Potential issue:
data in FF:FG will be pushed to GF:GG every couple of months because newer columns will be inserted in between. (It's a pivot-like design... sorry, but end-users need this appearance, but categories are increasing, summary need to be at right end side)
He has 2 other choices (if he don't want to maintain VBA code every few months):
A: Store "FF","FG" in a Cell (fixed location!), then read the location parameter using VBA
B: Read a second dedicated CSV file (copy/paste from the monster file, consumed by another user so available readily), it only has the 2 columns required..
To me, none is obviously better than the other, just a matter of preference.
Similar but simpler Scene of mine
I produce the monstrous file by lots of Vlookup from manual data sources (inherited the design... and I refactored the design using another automation tool but there is license consideration atm).
In a column there is a formula doing something like
=if(A1="SALES PERSON SICK","void result",(if(A1="MACHINE BROKEN",C2*0.8),"")..
say 5000 rows with this formula
To reduce hard-coding I moved
"SALES PERSON SICK","MACHINE BROKEN" to a reference sheet cell A1,A2, and changed formula to:
=if(A1=Ref!$A$1,"void result",(if(A1=Ref!$A$2,C2*0.8),"")
I feel it's a good practice.
Question: Is method A or B better? Considering column position will move every ~3-6 months, still worth choosing 1 from A/B?
data in FF:FG will be pushed to GF:GG every couple of months because newer columns will be inserted in between
Then you should use named ranges in what you call "monster file" (see Define and use names in formulas) and use them in your VBA.
Eg define a name for Columns FF:FG like CopySource (use a name that describes the data in that columns) and finally you can use that in your VBA code.
Range("CopySource").Copy
Whenever the range moves because new columns are inseted before, the named range moves too, so it still points to the same data.

Automation of Subtotal range picking

For my internship I am trying to do an analysis of travel patterns in public transport.
Due to privacy reasons I cannot share the file, but I may describe the columns.
This is how it works.
I have a spreadsheet in Excel (2007) and it is called ReizigersData. That contains 15,000 rows of checkins.
The columns are: stopname, stopID, problemStop, D, E, productname, workday, saturday, sunday.
stopID can be seen as a primary key.
As you'll understand, the stops are repeated in several rows, because many different productgroups travel from the same stop.
Using a Advanced filter I have filtered out 3 relevant productgroups, reducing it to approx 300 rows.
The other sheet in the file is called ReizigersData (bundled).
In this sheet I want to get the subtotals per stop, combining the numbers of the three productgroups, although separated by workday/saturday/sunday.
This sheet contains the following columns: stopname, stopID, workday, saturday, sunday.
I have used the following codes:
In ReizigersData (bundled) stopname:
=INDEX(ReizigersData!$A$3:$A$14326;MATCH(B3;ReizigersData!$B$3:$B$14326;0))
In ReizigersData (bundled) stopID:
=SUBTOTAL(109;'ReizigersData (2)'!G174:G205)
These codes work.
The problem though is that I entered that range by hand.
Since it is a big database, I would like the subtotal formula to automatically determine which range he should pick according to the stopID in the bundled sheet.
I have experimented a bit and came up with this formula:
=SUBTOTAL(109;(INDIRECT("'ReizigersData (2)'!G" & Match(B3;'ReizigersData (2)'!$B$3:$B$14326))):(INDIRECT("'ReizigersData (2)'!G" & Match(B3;'ReizigersData (2)'!$B$3:$B$14326))))
Unfortunately this does not work; it returns 0. In Formula evaluator, it looks that the reference in the match part is the issue, because it refers to row 2297, which is not the one it should be.
Has anyone got any idea how to reach my goal?

In Excel VBA, how do I select rows containing specific values in a column and hide them?

I'm trying for the life of me to figure out Excel VBA but I've been getting nowhere.
Here's what I'm needing to do:
Have a list of thousands of entries - each one corresponding to a ticket for a customer. Columns include information like client name (Column B), # of minutes worked on per ticket (Column I), etc.
We're trying to make a macro that totals the # minutes of worked on for all tickets of a specific client in a new row directly below, then hide all of those rows.
The end result should be only seeing a row containing "Total -client name here-" in the name column, then the total number of minutes in the # of minutes column.
The previous macros I've done aren't dynamic and were done via recordings within excel (which obviously don't work the way I wanted to, apparently).
Programming isn't my forte, and all this has been doing is making me want to pull my hair out. Any help?
It sounds like you'd be better off using a database like Access. You can enter all your information into a table and then write a query to find what you need. If you don't want to use Access, we'll need a better idea of what you're trying to do.

How can this lookup (find the last relevant item) be improved?

One of the reports that wastes a bunch of my time at work is the Roster. It's a multi-site, multi-contract listing of every employee currently assigned to a specific client. Currently, it has a little over 6,000 lines by 20-something columns, indexed against 3 different datasets. Not the largest mess in the world, but still a pain. And it's almost all in excel, because I somehow don't have a business case for Access.
But one part of this monster stands apart. One tab per site Site Totals, listing off every time any agent has gone through training. A second tab (again, one per site) Site Data displaying only the most recent training class, and the credentials they had during that class.
That second tab is driven by variations of this array formula - Last_Row is a named range on another tab, and column A is a pivot of the UID column on Site Totals. I've broken it apart for readability:
=IF(INDEX('Site Totals'!B:B,LARGE(($A2=INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row))*
(INDIRECT("'Site Totals'!B1:B"&Last_Row)<>"")*
ROW(INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row)),1))="Trainer",
"",
INDEX('Site Totals'!B:B,LARGE(($A2=INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row))*
(INDIRECT("'Site Totals'!B1:B"&Last_Row)<>"")*
ROW(INDIRECT("'Site Totals'!$A$1:$A$"&Last_Row)),1)))
I know what this formula does, but I don't know how to improve it. This formula needs to be changed, because it currently is on the order of 500 Million calculations (I'm not allowed to delete historical data), and it takes me 3 hours to calculate the workbook ... if it doesn't crash Excel first.
I'm open to VBA and / or custom functions, but would prefer to have native Excel functions. I'm not able to install anything, so any solution must be native Excel, and Must be compatible to Excel 2007.
If your source is a pivot table, try is the GETPIVOTDATA function. You might be able to accomplish what you want without INDIRECT and INDEX.
What i have understood is that every person has/has not attended a training and you want to retrive the name of that training, in case he has not, you want a blank space in the cell. If this description is correct you can try this formua, press ctrl+shift+enter to execute.
=IFERROR(INDEX('Site Totals'!B$1:B$12,MATCH(A2&"Trainer",'Site Totals'!A$1:A$12&'Site Totals'!B$1:B$12)),"")
Here A2 contians the name of the person. I can be more precise with this formula if you can provide some sample data butI would recommend to not to use entire B & Columns in Site Total workssheete as this will definately slow down computing process, instead you can use B1:B8000 or smaller range, to speed up process. Hope that helps.

Grouping rows by area codes

I have a table of customers to which my company ships products. The problem is that these customers need to be sorted by their area codes, so that the products can be sent to the appropriate shipping companies (we have two partner companies that ship to certain parts of the country). Each company sent us a list of area code numbers to which they can ship and I need to divide the Excel sheet into two sheets, each containing the customers with the area codes compatible with the respective company.
I tried to solve this problem with VLOOKUP function, but it only works on individual row basis, and I need a solution that will find all rows that contain a number from the specified group of area codes.
Another way would be IF function that would put a True or False (one IF function for each company) value in new column and then I could sort by that value, and copy the data into a new sheet. This approach would work, but the IF function would be extremely long and hard to control.
Can you suggest a way to solve this problem?
Edit to incorporate details provided via Comment:
Presently I have about 5,000 rows but in future it might be more though I doubt over 10,000 rows.
A VLOOKUP seems very promising, of the kind =VLOOKUP($B2,F:G,1,0) in C2 copied across and down as required, with a layout as below:
This does not group as you say you require (but do you really need to?) because it seems possible some locations will be served by both shippers. You might resolve this by flagging those rows where both are viable and then by sorting to split into three groups (Shipper1 only, Shipper2 only, both) before transferring the ranges as desired.
Edit in response to OPs comment
If you can be certain there is no overlap between Shippers, a single column with this formula, say in E2copied down, might be preferable:
=IF(ISERROR(MATCH(B2,F:F,0)>0),"Shipper2","Shipper1")
and would not routinely show #N/A. (This assumes no area is outside the range of both shippers.)

Resources