Suppose the other sheet mentioned is called 'Ref Data' and it looks similar to this:
MrExcel_20240104.xlsx |
---|
|
---|
| B | | | | | | | | | K | | | N |
---|
1 | Charge Code | | | | | | | | | Primary Criteria | | | Hours |
---|
2 | XY-1100 | | | | | | | | | A | | | 1 |
---|
3 | X-0110 | | | | | | | | | B | | | 3 |
---|
4 | X-0120 | | | | | | | | | C | | | 5 |
---|
5 | XY-1100 | | | | | | | | | D | | | 7 |
---|
6 | X-0110 | | | | | | | | | G | | | 9 |
---|
7 | X-0120 | | | | | | | | | F | | | 11 |
---|
8 | XY-1100 | | | | | | | | | G | | | 13 |
---|
9 | X-0110 | | | | | | | | | A | | | 15 |
---|
10 | X-0120 | | | | | | | | | B | | | 17 |
---|
11 | XY-1100 | | | | | | | | | C | | | 19 |
---|
12 | X-0110 | | | | | | | | | D | | | 21 |
---|
13 | X-0120 | | | | | | | | | E | | | 23 |
---|
14 | XY-1100 | | | | | | | | | F | | | 25 |
---|
15 | X-0110 | | | | | | | | | D | | | 27 |
---|
16 | X-0120 | | | | | | | | | A | | | 29 |
---|
17 | | | | | | | | | | | | | |
---|
18 | X-0110 | | | | | | | | | | | | |
---|
19 | | | | | | | | | | | | | |
---|
20 | | | | | | | | | | | | | |
---|
|
---|
Note that I've inserted a blank row---I'm not sure whether this might be an issue, but the solution offered here addresses it. There are three columns of interest: Charge Code, some Primary Criteria used for column matching in the main sheet, and something to sum, such as Hours (columns B, K, and N here). If these data were in a formal Excel table, we could use structured references and always be assured that we would get the entire column of data. But if the data are not in a formal Excel table and exist only in a range to be referenced, it would be beneficial to know that the entire range of data were obtained. One option is to specify an overly large range such that we are certain to cover the data plus some extra blank rows. Another option is to create dynamically formed ranges, which is what will be done below.
The first part of the formula allows the user to specify a sufficiently large range on the 'Ref Data' sheet to cover the data of interest (given the variable name src). Then, I'm assuming column B can be used to determine the lowest extent of the data, so column B is defined as bcol for convenience and then used in a formula to determine the last row number where data can be found...and this value is called lrow. Then we can extract certain columns of interest in src and trim unnecessary rows to create a smaller data array...this is done in a formula assigned to the variable "data", and it takes column indexes 2, 11, and 14 (from the original A:N), then takes the upper lrow rows, and finally drops the top 1 row where the column headings are found. This leaves us with only the data of interest in a three column array. Then each column of "data" is separated and assigned to different named variables: cc (charge code) from the 1st column, pc (primary criteria) from the 2nd column, and h (hours from the 3rd column).
Finally, the subtotal sought can be found by constructing three arrays:
- the hours array (h)
- a logical array indicating which elements of pc match the Primary Criteria code column headings in the summary table
- a logical array indicating which elements of cc match any of the filtered Charge Codes in the summary table. This is the messiest part because a list of visible charge codes is necessary, and to do that, the SUBTOTAL function is used with the COUNTA option (1st argument) inside a MAP function to build an array of Charge Codes that are visibly displayed. This array is then used in a MATCH function to determine whether each element in cc matches any of the display-filtered Charge Codes...and the MATCH results are wrapped by ISNUMBER to create the logical TRUE/FALSE array.
These three arrays are multiplied together and the results summed to obtain the final subtotal. Note that this solution also uses some named ranges found on another sheet called 'Lists' (not shown),