I asked this question a couple of week back, however deleted it after going down a different track. It has now come up again.
I use the following formula to total the values in the DK range, based on if the value in the associated EC column equals "EE", which works perfectly.
I also want to keep this type of formula so that I can filter on other columns and it will automatically alter the total based on what is being displayed.
=SUMPRODUCT(SUBTOTAL(9,OFFSET($DK$18,ROW($DK$18:$DK$4102)-ROW($DK$18),,1)),--($EC$18:$EC$4102 = "EE"))
Below is a snippet from the spreadsheet
The Question
I would like to expand this formula to round the values in the DK range to 2 decimal places before it gets subtotalled.
Is this possible and if so how?
It sounds like you are trying to set the ROUND operation in the wrong place. Each cycle of the SUMPRODUCT function is acting on a single digit from the SUBTOTAL function; it only matters whether SUBTOTAL believes it to be hidden or not. That is what needs to be ROUNDed, not the range in the OFFSET function. The range in the OFFSET function has been converted to an incremental set of numbers with the ROW function (e.g. {0, 1, 2, ... 4082, 4083, 4084}).
=SUMPRODUCT(ROUND(SUBTOTAL(9, OFFSET($DK$18, ROW($DK$18:$DK$4102)-ROW($DK$18), 0, 1, 1)), 2), --($EC$18:$EC$4102 = "EE"))
I'm not going to retype your image's data so no pretty pictures. You might also want to look into the more recent AGGREGATE function as a substitute for SUBTOTAL (xl2010+).
Related
A colleague has an array of values in "X4:X38". Since these are in a table which may be filtered, she wants to use the subtotal function to sum them - but wants all of the values to be rounded up first.
={SUM(ROUNDUP(X4:X38,0))}
works perfectly well. However,
{SUBTOTAL(9,ROUNDUP(X4:X38,0))}
Generates a generic "The formula you typed contains an error" message. I have tried various obvious things, like putting additional brackets around the "roundup" section, etc.
Any help would be appreciated.
You can do this without a helper column by using this formula:
=SUMPRODUCT(SUBTOTAL(2,OFFSET(X4:X38,ROW(X4:X38)-MIN(ROW(X4:X38)),0,1)),ROUNDUP(X4:X38,0))
OFFSET effectively breaks the range down in to individual cells which are passed to SUBTOTAL function and that returns an array of 1 or 0 values based on whether each cell is visible after filter or not - this array is multiplied by the rounded values to give the overall sum of the rounded visible values.
Another way is to use AGGREGATE function like this
=SUMPRODUCT(ROUNDUP(AGGREGATE(15,7,X4:X38,ROW(INDIRECT("1:"&SUBTOTAL(2,X4:X38)))),0))
Given the complexity a helper column might be the preferable approach
After investigation, looks like this is not possible without helper column.
Add a helper column which rounds the individual values in column X, e.g. type the following formula into cell Y4 and drag down to Y38:
= ROUNDUP(X4,0)
And then instead of
= SUBTOTAL(9,ROUNDUP(X4:X38,0))
use:
= SUBTOTAL(9,Y4:Y38)
Then if necessary you can just hide the helper column. Of course the helper column doesn't have to be column Y, it could be any column, e.g. a column far to the right of where the data ends.
So I've looked up tutorials on how to do this, and I'm still struggling, so I could use some expert help. I know it involves a very complex nested formula with things like SMALL, ROW, INDEX, etc...
So here are two screenshots that provide a sample of what I'm looking for. In realities there is over 1000 rows, but this makes it easier for you guys.
So here is my first example, lets call this Sheet1!:
Code, ID_1 and ID_2. So as you can see (and just focus on the input in A2) there will be two separate IDs in the linked workbook. That sheet, or at least a tiny sample of it, looks like this:
In the first column we see the code we're looking for (which is what we have in A2 of the first one), each of them with different IDs. So as I'm sure you can tell by now, I'm looking for a formula that will allow me to return those values in ID_1 and ID_2 in the first sheet.
I have been going at this for an hour and I'm stumped, so I would greatly appreciate any help provided!
This is a more generic code if the ids are NOT listed consecutively: Obviously I have done this as an example to take in a more general case where the ids occur anywhere throughout the second dataset, AND where there are potentially several.
IFERROR(INDEX($V$2:$V$15, SMALL(IF($U$2:$U$15=$M2, ROW($U$2:$U$15), FALSE), COLUMNS($N2:N2))-ROW($V$1), 1), "")
This formula must be entered with Ctrl-Shift-Enter before copying across and down! Note all absolute and relative referencing/locking ($ signs)
The logical steps in constructing such a formula:
1) We use IF function to test if the values in the column U match the value in column M.
2) In the 'value-if-true' parameter, we will get the corresponding row number of values in column U. These numbers will be fed later in the SMALL function.
3) In the value-if-false part, we just return false, as that will later be used as a non-number in the SMALL function
Above 3 steps in the part: IF($U$2:$U$15=$M2, ROW($U$2:$U$15), FALSE)
4 ) We have now an array of mixed row numbers and FALSE values, which we want to feed to the INDEX function to simply get the corresponding value in column V(our second datset). BUT as we wish to retrieve the different row matches for each code, we have to fish them out of the mixed array with the SMALL function.
5) using our columns as an incrementer, we apply the SMALL function to the array with a varying k parameter. We USE the COLUMNS function (note carefully the different $ sign usage), so that as we drag the formula across, the column count increments: COLUMNS($N2:N2) - giving K values of 1, 2, 3, 4 as we drag the formula across from column N to column Q. Note that it is useful that the SMALL function disregards FALSE values when looking through the array for the values by size.
6) There is an adjustment to account for the fact that the rows are relative to the 'Ids' range which we will feed into the INDEX function to retrieve the different ids. SMALL(IF($U$2:$U$15=$M2, ROW($U$2:$U$15), FALSE), COLUMNS($N2:N2))-ROW($V$1).
This can be avoided if we use the entire column V as the look-up array parameter in the INDEX function, but that's another way...
7) This resulting value can now be passed to the INDEX function to obtain the various ids. The column_num parameter of 1 which I put in the function isn't necessary in a single-column look-up array, but is there for completeness.
8) The entire construction is then wrapped in an IFERROR function to give an empty string if there is no match, but some people may wish to have error outputs there...
well if the two ID will be consecutive in the second list try this:
=index('workbookname'SheetName!columnrangeofserialnumbers,match(A2,'workbookname'Sheetname!columnrangeofIDs,0))
Assuming your other workbook is called Serials, and all the info is on sheet1 you would enter the follow in B2:
=index('serials'sheet1!$B$2:$B$1000,match(A2,'serials'sheet1!$B$2:$B$1000,0))
in C2 enter the following (assuming ids will show up consecutively)
=index('serials'sheet1!$B$2:$B$1000,match(A2,'serials'sheet1!$B$2:$B$1000,0)+1)
This only works if the other workbook is open as far as I know and with the understanding that the two ID will be listed consecutively in the list.
this should be simple enough, but numbers (on OSX) keeps throwing an error about the ranges being different sizes.
I have a list of numbers, each with an associated date, and I want a sum of all numbers within a particular month (to give, on a separate sheet, a monthly total).
Here is what I've tried:
SUMIFS(
Sheet1::Table 1::D2:D84,
MONTH(Sheet1::Table 1::A2:A84), "=04",
YEAR(Sheet1::Table 1::A2:A84), "=2014"
)
Sorry if this is a stupid question, but I've tried fiddling with it and it just won't accept it.
Thanks in advance.
You cannot put a function inside the range:
=SUMIFS(C1:C25;Month(A1:A25);"=3")
than you need to add two (hidden?) columns with Month & year function.
After you build SUMIFS based on the new columns
=SUMIFS(C1:C25;D1:D25;"=4";E1:E25;"=2014")
sum all value from C1 to C25 if column of month (D) is equal to 4 and column of year (E) is equal to 2014.
I would suggest considering using a SUMIFS function with an upper\lower limit, and then either referencing a cell with the dates, or using their numerical value in the formula (the former is my preference, to reduce hard coded values = easily updated\reused). So something like:
=SUMIFS(D2:D84, A2:A84, ">="&E1, A2:A84, "<="&E2)
In this example:
column 'D' has the values you want to sum
column 'A' has the date values
columns 'B' and 'C' are treated as irrelevant (for the sake of this formula)
column 'E' has 2 values, in row 1, the lower limit (for this specific question, the first of April) and in row 2 the upper limit (for this specific question, the final day of April)
Then have your lower limit for dates (the first day from when you would like column 'D' to be counted) in cell E1, and your date upper limit in E2.
Easily updated for future months, so might save you some work down the line.
The next easier option would be to update it to be formatted as a table, because your formula would be slightly more legible, add in some named ranges (in this case, E1 = 'lowerlimit' and E2 = 'upperlimit) to once again make it easier to read the formula, in which case you'd end up with something like:
=SUMIFS(table[FigureToBeAccrued], table[dates], ">="&lowerLimit, table[dates], "<="&upperlimit)
Might've overcooked this answer, it's my first, so wanted to make sure I didn't skimp. Let me know if you've got any follow up questions.
I'm having an issue with a spreadsheet formula that uses the MATCH() function.
=IFERROR(IF(LENB(Y2461)<> 0, "Complete", IF(LENB(Q2461)<> 0, IF(Q2461-$Y$1<MATCH($Y$1,R2461:X2461),"ON HOLD"), INDEX($R$4:$X$5,1,MATCH($Y$1,R2461:X2461)))),"ON HOLD")
This is the formula in the cell with the specific problem. I'm using match to look through a horizontal range of data and determine which column contains the most recent change, with exceptions for when the "Complete" column has a date, and the "ON HOLD" column has a date. Cell Y1 contains =TODAY(), so it checks each cell against today's date. The cells are formatted into dates, and are entered as dates from left to right. However, the entries can start again from an earlier column and leave the dates out of order.
The issue is, on only a few occurrences at a time, MATCH() will return a column that isn't the most recent. As far as I've been led to believe, and how it works for the other instances of this formula, is that it reads the array from right to left and stops at the first "highest" date.
The error is occurring on one row specifically, while the expected result works multiple times elsewhere on the sheet.
Am I using MATCH() wrong by assuming that it will read in a certain direction every time? Is there a different error in the code? Or is there a different way to get the result I've programmed it for?
MATCH with no third argument as you are using it is the same as MATCH with 1 or TRUE as third argument, which means that you can only guarantee that it will work OK if the range used - R2461:X2461 - is always in ascending order....but you say that isn't the case so I don't think you can guarantee the formula will work
Try using this version instead [revised as per comments]
=IFERROR(IF(LENB(Y2461)<> 0, "Complete", IF(LENB(Q2461)<> 0, IF(Q2461-$Y$1< MATCH(MAX(IF(R2461:X2461<=$Y$1,R2461:X2461)),R2461:X2461,0),"ON HOLD"), INDEX($R$4:$X$5,1,MATCH(MAX(IF(R2461:X2461<=$Y$1,R2461:X2461)),R2461:X2461,0)))),"ON HOLD")
confirmed with CTRL+SHIFT+ENTER
The logic of the alterations is that this revised MATCH part
=MATCH(MAX(IF(R2461:X2461<=$Y$1,R2461:X2461)),R2461:X2461,0)
will do the same as this part
=MATCH($Y$1,R2461:X2461)
whether R2461:X2461 is in ascending order or not - it finds the largest values which is <= to Y1 and gives you the position of the first instance.
Revised
If you want the rightmost date where the largest date <= today is duplicated then you can use this construction in place of MATCH
=MAX(IF(R2461:X2461<=$Y$1,COLUMN(R2461:X2461)-COLUMN(R2461)+1))
which would make the complete formula like this:
=IFERROR(IF(LENB(Y2461)<> 0, "Complete", IF(LENB(Q2461)<> 0, IF(Q2461-$Y$1< MAX(IF(R2461:X2461<=$Y$1,COLUMN(R2461:X2461)-COLUMN(R2461)+1)),"ON HOLD"), INDEX($R$4:$X$5,1,MAX(IF(R2461:X2461<=$Y$1,COLUMN(R2461:X2461)-COLUMN(R2461)+1))))),"ON HOLD")
Omitting the [match_type] from the syntax MATCH(lookup_value, lookup_array, [match_type]) may lead to unexpected results when the lookup_array is not sorted.
http://office.microsoft.com/en-gb/excel-help/match-function-HP010062414.aspx
I have a 2 variable 100x100 data table in excel.
I need to have a function that returns all the possible sets of variables that yield a given target value.
What I am looking at is some kind of a reursive 2 dimensional lookup function. Can someone point me in the right direction?
It can be done without VBA, fairly compactly, like so.
Suppose your 100x100 table is in B2:CW101, and we put a list of numbers 1 to 100 down the left from A2 to A101, and again 1 to 100 across the top from B1 to CW1
Create a column of cells underneath, starting (say) in B104
B104=MAX(($A$2:$A$101*100+$B$1:$CW$1<B103)*($B$2:$CW$101=TargetValue)*($A$2:$A$101*100+$B$1:$CW$1))
This is an "array" formula,so press Ctrl-Shift-Enter instead of Enter, and curly brackets {} should appear around the formula.
Then copy down for as many rows as you might need. You also need to put a large number above your first formula, i.e. in B103, e.g. 999999.
What the formula does is to calculate Rowx100+Column, but only for each successful cell, and the MAX function finds the largest result, excluding all previous results found, i.e. it finds the target results one at a time, starting from bottom right and working up to top left. (With a little effort you could get it to search the other way).
This will give you results like 9922, which is row 99, column 22, and you can easily extract these values from the number.
There is no built-in function that will do what you want, I'm 99% sure of that.
A VBA function that returns an array could be built, along the lines of the quick-and-dirty Sub already shown. Create an Variant to hold the output, perhaps Redimmed to the maximum possible number of results and Redim Preserve-d down to the actual number at the end. Then return that as the result of the function which then needs to be called as an array function (Control-Shift-Enter).
One down-side is that you'd have to ensure that the target range was large enough to hold the entire result: Excel won't do that automatically.
Would the Solver suit?
http://office.microsoft.com/en-us/excel/HA011118641033.aspx
I tried this a lot without using VBA but doesn't seem to be possible without it.
To solve this issue , I needed to loop through the entire array and found closest values. These values were then derefernced using calls and range properties and the output was generated in a range being incremented at each valid match.
The quick and dirty implementation is as under:
Dim arr As Range
Dim tempval As Range
Dim op As Integer
Set arr = Worksheets("sheet1").Range("b2:ao41")
op = 1
Range("B53:D153").ClearContents
For Each tempval In arr
If Round(tempval.Value, 0) = Round(Range("b50").Value, 0) Then
Range("b52").Offset(op, 0).Value = Range("a" & tempval.Row).Value
Range("b52").Offset(op, 1).Value = Cells(tempval.Column, 1).Value
Range("b52").Offset(op, 2).Value = tempval.Value
op = op + 1
End If
Next
Range("b50").Select
I am still looking for an approach without VBA.
I've got a solution that doesn't use VBA, but it's fairly messy. It involves creating a further one-dimensional table in Excel and doing lookups on that. For a 100x100 data table, the new table would need 10,000 rows.
Apologies if this doesn't fit your needs.
A summary is below - let me know if you need more detail. N = the dimension of the data, e.g. 100 in your example.
First, create a new table with five columns and NxN rows. In each case, replace my column names with the appropriate Excel reference
The first column (call it INDEX) simply lists 1, 2... NxN.
The second column (DATAROW) contains a formula to loop through 1, 2... N, 1, 2...N... This can be done using something like =MOD(INDEX-1, N)+1
The third column (DATACOL) contains 1, 1, 1... 2, 2, 2... (N times each).
This can be done with =INT((INDEX-1)/N)+1
The fourth column (VALUE) contains the value from your data table, using something like:
=OFFSET($A$1, DATAROW, DATACOL), assuming your data table starts at $A$1
We have now got a one-dimensional table holding all your data.
The fifth column (LOOKUP) contains the formula:
=MATCH(target, OFFSET(VALUERANGE, [LOOKUP-1], 0),0)+ [LOOKUP-1]
where [LOOKUP-1] refers to the cell immediately above (e.g. in cell F4 this refers to F3). You'll need a 0 above the first cell in the LOOKUP column.
VALUERANGE should be a fixed (named or using $ signs) reference to the entire VALUE column.
The LOOKUP column then holds INDEX numbers which can be used to look up DATAROW and DATACOL to find the position of the match in the data.
This works by searching for matches in VALUERANGE, then searching for matches in an adjusted range starting after the previous match.
It's much easier in a spreadsheet then via the explanation above, but that's the best I can do for the moment...