I'm trying to write a formula using SUMPRODUCT, SUMIF, INDIRECT and a named range. My formula is:
=SUMPRODUCT(SUMIF(INDIRECT("'"&INDIRECT("EightiesNames")&"'!G8:HI8"),$A$2,INDEX(INDIRECT("'"&INDIRECT("EightiesNames")&"'!G9:HI300"),MATCH($A$1,INDIRECT("'"&INDIRECT("EightiesNames")&"'!E9:E300"),0),0)))
The formula goes through every worksheet in the named range and does a lookup to both the columns (looking up $A$2 in G8:HI8. note that $A$2 may occur multiple times in one worksheet) and rows (looking up $A$1 to E9:E300) before summing together all the return values with SUMIF/SUMPRODUCT.
The formula was inspired by the below simplified version but with SUMPRODUCT and INDIRECT layered in to allow it to perform the same function across multiple tabs.
=SUMIF(G8:HI8, $A$2, INDEX(G9:HI300, MATCH($A$1, E9:E300,0), 0))
See below for a more detailed description of the workbook.
Worksheets:
Sheet1 - houses a named range in cells B2:B7 {Name1, Name2, Name3, Name4, Name5, Name6}. The named range is called "EightiesNames"
Name1 - where the formula is located. The formula references worksheets Name1, Name2, Name3, Name4, Name5, Name6, basically all the worksheets in the named range.
There are three occurrences of "INDIRECT("'"&INDIRECT("EightiesNames")" - after the SUMIF, one after INDEX and after the MATCH. The first occurrence of the two INDIRECTs, works the way I want it to (when I evaluate the formula). It expands the INDIRECT("EightiesNames") into an array {"Name1";"Name2";"Name3";"Name4";"Name5";"Name6"}. The formula then proceeds to tack on the range "'!G8:HI8" after each "Name" - "'Name1'!G8:HI8";...;"'Name6'!G8:HI8".
However, for the INDIRECTs that occur after the INDEX and the MATCH, it does not return an array like the first one. On my computer, it returns "Name2" (returns "Name1" on my friend's), not sure why its different and why it returns those values instead of the entire array.
I'm not really sure how to fix this as the three INDIRECT formulas are identical but do not produce the same result. I also know INDIRECT formulas take up a lot of processing power so I'll gladly take alternatives. Any help/insight would be greatly appreciated! Thanks!
While a single formula solution is possible, it would be very complex, inefficient, and not robust at all. For this reason, I would suggest that you use a regular SUMIF formula for each worksheet, where it would be placed in the same cell for each of your worksheets, let's say B1, and then you could simply use SUM to get your total, for example =SUM('Sheet1:Sheet5'!B1).
However, if you would like to try a single formula solution, try the following formula that needs to be confirmed with CONTROL+SHIFT+ENTER.
Note that I have assumed that G8:HI8 and E9:E300 for each of your worksheets contain text values. If G8:HI8 contains numerical values, replace...
T(OFFSET(INDIRECT("'"&EightiesNames&"'!G8:HI8"),,COLUMN(INDIRECT("G8:HI8"))-7,,1))=$A$2
with
N(OFFSET(INDIRECT("'"&EightiesNames&"'!G8:HI8"),,COLUMN(INDIRECT("G8:HI8"))-7,,1))=$A$2
Also, if E9:E300 contains numerical values, replace...
T(OFFSET(INDIRECT("'"&TRANSPOSE(EightiesNames)&"'!E9:E300"),ROW(INDIRECT("9:300"))-9,0,1))=$A$1
with
N(OFFSET(INDIRECT("'"&TRANSPOSE(EightiesNames)&"'!E9:E300"),ROW(INDIRECT("9:300"))-9,0,1))=$A$1
Here's the formula...
=SUM(IF(T(OFFSET(INDIRECT("'"&EightiesNames&"'!G8:HI8"),,COLUMN(INDIRECT("G8:HI8"))-7,,1))=$A$2,N(OFFSET(INDIRECT("'"&EightiesNames&"'!G9:HI9"),TRANSPOSE(MMULT(TRANSPOSE(ROW(INDIRECT("9:300")))^0,IF(T(OFFSET(INDIRECT("'"&TRANSPOSE(EightiesNames)&"'!E9:E300"),ROW(INDIRECT("9:300"))-9,0,1))=$A$1,ROW(INDIRECT("9:300"))-9,0))),COLUMN(INDIRECT("G9:HI9"))-7,,1)),0))
Hope this helps!
Related
I have a column which is a dynamic named range:
A
A
B
C
A
How can I apply a MATCH or other formula which returns the row or cell address of all A values in the dynamic named range?
A dynamic named range is used so all row or address of A values can automatically appear as a spill rather than having to drag down the formula.
I have seen numerous formulas in this structure:
=INDEX($B$2:$B$8, SMALL(IF($A$11=$A$2:$A$8, ROW($A$2:$A$8)-ROW($A$2)+1), ROW(1:1)))
However, most of these seem to return the first instance (row or cell address of the first match) and requires the formula to be dragged down manually rather than a spill, which is more preferable.
Any help will be greatly appreciated.
Use FILTER:
=FILTER(ROW(A1:A5),A1:A5=C1)
This will return the Row number everywhere they match.
From there it is pretty easy to include that in INDEX:
=INDEX(B:B,FILTER(ROW(A1:A5),A1:A5=C1))
If you do the full column in the index, you do not need the ROW($A$2:$A$8)-ROW($A$2)+1 as returning the actual row instead of relative works just fine.
Try something like =SORT(ROW($A$1:$A$5)/($A$1:$A$5=$C$1)). This will get you the matches of a value in C1 with a spill formula, leaving behind #DIV/0 errors
See example below:
Other answers that you might be able to take ideas from are here: Match Exact Row Number of Nth Largest Value In Data With Duplicates
You could be thinking of:
=SMALL(IFERROR(ROW(A1:A5)*MATCH(A1:A5,C1,0),FALSE),ROW(A1:INDEX(A:A,COUNTIF(A1:A5,C1),)))
Where your data start in A1 and your compare value is in C1.
If you have Excel 365, this is easier:
=INDEX(SORT(ROW(A1:A5)*MATCH(A1:A5,C1,0)),SEQUENCE(COUNTIF(A1:A5,C1)))
or better yet:
=LET( dataRange, A1:A5,
compareTo, C1,
INDEX(SORT(ROW(dataRange)*MATCH(dataRange,compareTo,0)),SEQUENCE(COUNTIF(dataRange,compareTo))) )
=ADDRESS(3,1) 'evaluates to $A$3
=ROW($A$3) 'evaluates to 3
Why can't I nest them?
=ROW(ADDRESS(3,1)) 'Gives an error.
Try:
=ROW(INDIRECT(ADDRESS(3,1)))
instead of using ADDRESS which returns a string, consider using INDEX which will return a cell reference. The general format of INDEX is:
INDEX(Range you want to look in, rows down from top row, columns right for first column)
so in order to reference your whole sheet like address would you would need to select the range of the entire sheet:
=INDEX($A$1:$XFD$1048576,3,1)
The above formula actually returns the cell reference of $A$3 ($ is due to 3 and 1 being hard coded) then turns around and displays the contents of $A$3. As a result you don't actually see the $A$3. On the interesting side of things it also means you can define a range with INDEX(...):INDEX(...). To finish off your formula you would nest the INDEX in your ROW function as follows:
=ROW(INDEX($A$1:$XFD$1048576,3,1))
This avoids the use of the volatile function of INDIRECT and some of its other restrictions.
I'm working on a spreadsheet that does some pretty bizarre calculations... The long and the short of it is that I need to search the values in the 4 folowing ranges.
C5:C293, E5:E293, G5:G293 & I5:I293. The issue is that those ranges can change but will stay consistent across the columns. So For example instead of 5:293 it might change to 5:290. Is there an easy way to say "Look at the cells that are rows X:Y and are in columns A, B, C or D?"
google-spreadsheets
ARRAYFORMULA: Commas , arrange the array horizontally and semi colons; arrange the array vertically( stacking on top of each other)
=ARRAYFORMULA ({C5:C293,E5:E293,G5:G293,I5:I293})
QUERY: If there's a pattern in the columns, This will isolate the array:
=QUERY(TRANSPOSE(C5:I293),"Select * skipping 2",0)
In Excel, use the INDIRECT() function.
So, have a Start cell in A1, and an End cell in A2. Then your formulas to sum a range would reference the ranges for C column as:
=SUM(INDIRECT("C"&A1&":C"&B1))
And D column as:
=SUM(INDIRECT("D"&A1&":D"&B1))
Use range names rather than Indirect() or Offset() functions in the worksheet.
Create one range that covers the desired rows in the first column, e.g. "red" in the example, then create additional range names that offset the required columns from that range name.
How you construct your initial range is totally up to the circumstances, but the range names with Offset() will be super fast to deliver a result, whereas Indirect() and Offset() in worksheet cells can cause significant speed issues.
Use offset function, if you are in google-spreadsheets, use it dinamically:
=offset(C5,,,counta(C5:C),1)
will reproduce the range of a proper length.
I would like to create a table with products and formulas on a sheet (Sheet2). For different products, different formulas apply.
I would like to retrieve the formula from that table but use the row numbers from the row in Sheet1
How do I enter a formula which is evaluated with the correct row numbers from Sheet1.
I have a UDF eval that can evaluate a text string:
=eval(vlookup(Product;Table;2;false)
The formula retrieved from the Table should use the row number of the actual row that the eval() is on.
I tried the following:
="D"&ROW(Sheet2!$A16)&"/G"&ROW(Sheet2!$A16)&"/F"&ROW(Sheet2!$A16)&"*5"
This retrieves the formula but the eval() does not calculate the result.
In your example, product is located on Sheet2 in the 16th row of the first column of table. If you want the 16th row on the worksheet, you can use the MATCH function on a full column reference, discarding the structured references of the ListObject table or you can use MATCH on the structured table reference and compensate for the 'position within' table by adjusting by the table header row.
That's probably confusing so here is an example.
To find the actual row-on-the-worksheet where bcd resides you would use one of these formulas.
=MATCH("bcd", Sheet2!B:B, 0)
=MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers])
The first simply returns row 6 on the worksheet. The second returns 2 since bcd is in the second row of the ListObject's .DataBodyRange property and this is adjusted by the row that the .HeaderRowRange property is in; e.g. 2 + 4 = 6.
Now that everything is clear, all you need to do is use the result from one of those formulas as the row_number parameter in an INDEX function.
=INDEX(D:D, MATCH("bcd", Sheet2!B:B, 0))/
INDEX(G:G, MATCH("bcd", Sheet2!B:B, 0))/
INDEX(F:F, MATCH("bcd", Sheet2!B:B, 0))*5
'or,
=INDEX(D:D, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))/
INDEX(G:G, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))/
INDEX(F:F, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))*5
Your own formula could have worked with a series of INDIRECT functions that convert constructed strings to actual cell references. However, INDIRECT is considered volatile and best avoided if possible.
=INDIRECT("D"&ROW(Sheet2!$A6))/INDIRECT("G"&ROW(Sheet2!$A6))/INDIRECT("F"&ROW(Sheet2!$A6))*5
This solution is based on the capability of Excel to reference the cells in R1C1 style. In order to use it, you will have to go to File -> Options -> "Formulas" tab, and check the box "R1C1 reference style" in "Working with Formulas" group.
In addition, your eval() function will have to be able to evaluate such kind of formulas.
Once, all of these is done, you only have to retrieve the formula.
In order to make the things clear, I will focus on an example.
The table below is the contents of Sheet1 (the "Database" of products).
The column "Formula" contains the relevant formula:
for apple: RC[-2]+RC[-1]
for banan: RC[-2]*RC[-1]
for lemon: RC[-2]/RC[-1]
The table below is the contents of Sheet2:
The column "Formula" here contains the formula, retrieved from Sheet1. The formula of the column "Formula" is as follows:
=FORMULATEXT(INDEX(Sheet1!R2C1:R4C4,MATCH(RC[-3],Sheet1!R2C1:R4C1,0),4))
The description of each of the functions, used here (formulatext, index and match) can be found in Excel help.
As it can be seen, the retrieved formula, represented in R1C1 style is correct in context of Sheet2, were the products are arranged differently, and may appear more than once. The only remaining work to do is to apply the eval() function, after it was adapted to evaluate R1C1-style referenced formulas.
I hope it helps.
I have been working on an attendance sheet and trying to make the monthly reports automatic. I have asked my previous question on the same issue and got the idea to accomplish the task.
But now I have stuck at one place. I have this below formula:
=COUNTIFS(C5:C27,">0", E5:E27,"G", F5:F27,"CAT1")
The value in cell "C" in the above is coming from the below formula (in cell "C")
=IF((COUNTIF(G5:AK5,"p"))>0,1,0)
I had to add this extra column ("C") only to supply input to my fist formula. My question is - "Can we merge the IF function inside the COUNTIFS to get the result in one go and to eliminate the use of an extra column (column C)"?
To perform these cell reference acrobatics you will likely need to switch to an array formula. Array formulas chew up calculation cycles logarithmically so it is good practise to narrow the referenced ranges to a minimum. A 'helper' column such as you've used in column C can generally reduce calculation cycles and make a worksheet more 'user friendly'.
A COUNTIFS function requires that the ranges being examined are not only the same size but also the same shape. Looking at G5:AK5 is not the same as looking at E5:E35 even though they contain the same number of cells¹.
In the sample data below, you formula is in A1 and uses the 'helper column' C. My array formula is in A2 and does not consider column C ahough it incorporated the logic.
The array formula in A2 is:
=SUM(IF(E5:E27 = "G", IF(F5:F27 = "CAT1", SIGN(COUNTIFS(OFFSET($G$5, ROW($1:$23)-1, 1, 1, 31), $I2)))))
Array formulas need to be finalized with Ctrl+Shift+Enter↵. Once entered into the first cell correctly, they can be filled or copied down or right just like any other formula.
¹Some functions not only accept but welcome cell ranges that are the same number of calls but transposed. Offsetting or staggering the ranges is also an option if the cell ranges are the same size. In difficult cases the TRANSPOSE function can be helpful.