I have a sheet setup that calculates totals. Easy enough if the data is already there but not if adding new data. So what I would like to be able to do is to not specify a specific end cell for the sum formula but let it update as more columns are added.
How can I do this with =SUM(m4:m?)
Suppose you need totals for data in M4:M10.
To make just open-ended range, you can make lower limit "too far": =SUM(M4:M100000).
Alternatively you can make it as =SUM(M:M) - SUM(M1:M3)
But this is not applicable when you need to have totals value just below the set of values. In this case you have 2 ways.
Using Excel embedded features
The formula will look like his: =SUM(M4:M10). If you insert a new row between M4 and M10 (for instance, select row 5, right-click, insert row), you formula will be automatically adjusted to =SUM(M4:M10).
The problem may happen if you want to insert a new value above the first row (select row 4, right-click, insert row) or below the last row (select row 11, right-click, insert row). In these cases totals formula will not be adjusted.
Possible workarounds:
For the "above first row" issue, I prefer to make some empty row above and hide it. In our case I would hide row 3 and make totals formula look like =SUM(M3:M10), so, when you insert a new row above the first row, in fact you insert a row to the middle of the table, and totals formula will be adjusted.
For the "below last row" - leave empty row below; but in this case you cannot hide it; just make it different color and make some remark like "new values shall be inserted ABOVE this line".
INDEX()
Interesting trick is using INDEX() function, which returns a reference to a cell in the array. For our case, the array can be the whole M row and, the index - row number.
For the "above first row" issue make totals formula like this =SUM(INDEX(M:M;4):M10). So, calculation will always start at row 4, even if some lines will be added/deleted.
"below last row". Suppose you have your "totals cell" in M13 and you want to have totals for all value between M4 and the "totals cell". The formula may look like =SUM(M4:INDEX(M:M;ROW(M13))) or, considering "above first row" case: =SUM(INDEX(M:M;4):INDEX(M:M;ROW(M13)))
Hope this helps
Sum(m4:m?) insinuates that you are looking to add more rows as opposed to adding column data.
If you want to auto sum a row data you can use something like:
=SUM(OFFSET(A1;0;0;COUNT(A:A);1))
However this assumes that the data is contiguous in each cell and also empties are not allowed for 0 because it gets the count wrong.
However: You could also define a table for the data range. If you add data to columns/rows that are in that data range, they will be included in the adjusted formula automatically - very nice indeed.
Select your data range, then Select Insert:Table. This will give your table a name like Table1.
Your sum function would now be adjusted to look something like:
=SUM(Table1)
Now, as you add to the range, the table resizes, and your function just works.
The beauty of using a table, is that if you add data to the row/column immediately after the table it resizes and includes that range. This is hard to do without a table. You can also change the format of the table, or make the format colours invisible but you're probably better off with some format to show the data area of the table to the user.
You can compute the last row containing a number using this formula:
=LOOKUP(2,1/ISNUMBER($J:$J),ROW($J:$J))
This formula would not have a problem if you had text or blanks in the range.
You could then define that formula as a Defined Name
and use the formula:
=SUM(OFFSET(J4,0,0,LastRow-3))
to Sum the range. Note the -3 at the end to compensate for the first cell being in row 4.
Another option would be to just set your range to a fixed range that you can guarantee will be larger than any range you might actually use:
=SUM(J4:J1000)
You can use a counta to find the max row number. Then pushing that into an indirect will give you the range you need.
=SUM(INDIRECT("A1:A" & COUNTA(A1:A1000000);TRUE))
Assumptions:
Data are on column A
Data start from first row
There are no blanks rows
Related
I think I made a breakthrough with "ultra-dynamic" ranges. That's how I call them because not only they are dynamic; but also they refer to different ranges based on the cell address in which they are written in! Now I need to advance this breakthrough even further. Those of you using dynamic ranges in Excel, especially the dynamic-range-gurus, will be thrilled to read below and can possibly help in this advancement:
Disclaimer: If you are not familiar with dynamic ranges do not attempt to read below!
Background:
Our sheet has cells with calculations on top and a pivot table below.
Each cell above refers to the pivot table cells below in the same column.
The first column of the pivot table (titled "Row Labels" by default) is sorted from top to bottom in descending order. Each of the next columns has the result of a different test.
At one point somewhere in the middle rows of the pivot table there is a "marker line" that separates the top part of the pivot from the bottom one.
Let's call the top part "Uppers" and the bottom part "Downers".
Let's call both parts together "Population". Population is a non-contiguous range because the "marker line" that separates the Uppers from the Downers intervenes.
For each cell above the pivot there are calculations for the pivot column exactly below that need to refer to the Uppers or Downers or Population of the column itself.
Previously, my formulas in all of the cells above were a repetition of something like this below:
= MAX( OFFSET($A$79,$B$5+1,COLUMN()-1,$B$6,1) )
This example gives the maximum of the area of the Downers in the same column below.
Where:
A79 is the top left corner of the pivot table,
B5 has the row number of the marker line (relative to A79) to signify that our column's Downers area starts from the first row below that marker row (hence the "+1"). The formula of that cell has an XMATCH formula to produce the resulting row number. For example if the Uppers are positive numbers and the Downers are negative numbers, all sorted in descending order, the XMATCH is searching for the 0 row that separates the two parts of the population.
COLUMN()-1 returns the current column's number for offsetting to the right and the -1 is necessary because the first column is 0 rather than 1 offset to the right, and
B6 has the number of rows ("height") to the last row number of the pivot (relative to B5) where our Downers end. The cell contains the usual COUNTA function that counts the number of rows in the pivot table and from this number it subtracts the number of the marker row in B5 to get the "height" of the Downers range.
The OFFSET... part of the formula when copied to any cell with calculations above the pivot will always give the Downer's area in the same column.
And here we come to the "ultra"-dynamic part: I tested (and it works!) naming a range as:
ColDowners: =OFFSET($A$79,$B$5+1,COLUMN()-1,$B$6,1)
And I substituted all the cells with calculations that refer to the Downers with something like:
= MAX( ColDowners )
Miraculously, all cells with this named ultra-dynamic range, are calculated with the correct values for the Downers exactly below them in the same column! Sometimes when the Workbook is initially loaded, the cells appear with 0 values, but immediately when you hit F9 to Calculate they get the correct value (which of course is not a problem).
So this range is "dynamic" in two ways: (1) because start and end rows are dynamic (as usual) and (2) because it results to a different range depending on where it's written!!
And now for the advancement. Any dynamic-range-guru's input would be extremely valuable:
OFFSET is a volatile function with the known performance issues. Can we replace it with two non-volatile INDEX functions separated by a colon (":")? I know how to name a range that starts from a specific cell and ends in a different one every time (eg. =A$155:INDEX(...COLUMN()...)). But can BOTH the start and end of the range be INDEXified [sic]? i.e. can it be something like =INDEX(...COLUMN()...):INDEX(...COLUMN()...). And, consequently, if we name a range with this formula, will it work?
Answers will have to exclude volatile functions like INDIRECT and will have to be as simple as possible. The resulting range of the formula of the ultra-dynamic range will have to be different depending on which COLUMN() it's written in in the sheet (like the OFFSET one above) and will have to be "able" to start from a specific number of rows below A79 (the number written in B5 in the example above) and end in the one written in B6.
The correct formula that defines an ultra-dynamic-range for replacing the 'OFFSET' formula:
=OFFSET($A$79,$B$5+1,COLUMN()-1,$B$6,1)
Is:
=INDEX($A:$XX,ROW($A$79)+$B$5+1,COLUMN()):INDEX($A:$XX,ROW($A$79)+$B$7,COLUMN())
Where in B7 is the number of the last row of the pivot. (=Something like B5+B6 plus/minus 1 or 2 - test it for your case)
If you Define a Name of a Dynamic Range with this ultra-dynamic formula, it will adapt to give you different ranges depending on the location of the cell where you copied it to!! It will always give you the same parallel range in your column and will produce different results in different columns! I tested it and it works perfectly, plus it made my calculations lightning faster since INDEX is non-volatile (as opposed to OFFSET).
One more tip for the example above: I also tried nested range names and they work! For example I Defined the Range for ColPopulation as:
=(ColUppers,ColDowners)
Note that this is an ultra-dynamic-nested-range-name! Of course, it can work only for simple functions (such as =MAX(ColPopulation)) and will not work in functions such as SUMPRODUCT that need contiguous ranges. Still, it is a very useful thing to know that you can Define Ranges by adding other range names with commas!
Great help from all involved! Thanks a lot!
I have two table, this one is the initial table that contains raw data (on Sheet 2)
And the second table (on Sheet 1) contains formula based on data from first table
I use this formula to calculate the data, but as we can see on the picture, it doesn't produce right result. Could you please help me to modify the formula?
=IFERROR(INDEX(Sheet2!$E$2:$E$12,MATCH(Sheet1!$B$1&Sheet1!B$2&Sheet1!$A3,Sheet2!$C$2:$C$12&Sheet2!$B$2:$B$12&Sheet2!$D$2:$D$12,0)),"")
First the auxiliar column, using the concatenate operator & :
Then the formula would be:
=VLOOKUP(B$2&$E$1&$A3;Sheet2!$A:$G;6;0)
Change 6 for 7 if you want the description instead of Activity.
Please try this formula. It should go into cell Sheet1!B3 where it must be confirmed with Ctl+Shift+Enter because it's an array formula. (017)
=IFERROR(INDEX(Table,MATCH(1,(INDEX(Table,,3)=$A$1)*(INDEX(Table,,2)=B$2)*(INDEX(Table,,4)=$A3),0),5),"")
In preparation of this formula to work you need to set up a named range by the name of "Table" which comprises of Sheet2!A2:Fxx. Better set this range up dynamically so that it expands as you add more data but you can also declare it as Sheet2!A2:F1000 where 1000 is a number of rows you expect never to need.
This table has 6 columns, A:F which I intentionally made to include column A, which you don't need so that range columns and sheet columns are identical. Table,,3 simply defines the 3rd column. You can replace it with Sheet2!$C$2:$C$1000. If you do, make sure that all your ranges have identical sizes.
The 5 near the end of the formula, at ,0),5),"") identifies the 5th column of the range Table from which the result is returned if the 3 criteria match. Change this number to 6 to return the result from column F or to 1 if you ever need the value from column A.
I have an excel document with two sheets, data and edu-plan. The sheet data has the following information:
The sheet edu-plan looks like this:
My question is: how do i create an excel formula that checks if the target group on the specific row in edu-plan! has the course name in question on the same row as the target group in sheet data!, i.e. if Sales and Sales course is on the same row in the sheet data!?
In reality, the data sheet as a couple of hundred rows and will change over time, so i am trying to develop a formula that i can apply easily on all rows/columns in edu-plan!.
The desired result in edu-plan would look like this:
A pivot table might be a good way to go.
If you would like to do it by formula, then you can just use a COUNTIFS
=IF(COUNTIFS(data!$A$2:$A$10,$A2,data!$B$2:$B$10,B$1),"X","")
A possible way to solve your issue with an array formula:
Write in B2 of sheet edu-plan
{=IFERROR(IF(MATCH('edu-plan'!$A2&'edu-plan'!B$1,data!$A$2:$A$6&data!$B$2:$B$6,0)>0,"x",""),"")}
Since it is an array formula, you need to hit shift + ctr + enter.
Here is the formula broken down:
MATCH('edu-plan'!$A2&'edu-plan'!B$1,data!$A$2:$A$6&data!$B$2:$B$6,0)
checks whether the combination of row header and column header is in the data table. MATCH returns the index of the found combination. Since we are not interested in the location, we only ask IF(MATCH > 0, "x", "") to write an "x" if a match was found. If MATCH finds nothing, it returns an error, which is why we add an IFERROR(VALUE, "") around the construct.
I have a table that is pulling thousands of rows of data from a very large sheet. Some of the columns in the table are getting their data from every 5th row on that large sheet. In order to speed up the process of creating the cell references, I used an OFFSET formula to grab a cell from every 5th row:
=OFFSET('Large Sheet'!B$2572,(ROW(1:1)-1)*5,,)
=OFFSET('Large Sheet'!B$2572,(ROW(2:2)-1)*5,,)
=OFFSET('Large Sheet'!B$2572,(ROW(3:3)-1)*5,,)
=OFFSET('Large Sheet'!B$2572,(ROW(4:4)-1)*5,,)
=OFFSET('Large Sheet'!B$2572,(ROW(5:5)-1)*5,,)
etc...
OFFSET can eat up resources during calculation of large tables though, and I'm looking for a way to speed up/simplify my formula. Is there any easy way to convert the OFFSET formula into just a simple cell reference like:
='Large Sheet'!B2572
='Large Sheet'!B2577
='Large Sheet'!B2582
='Large Sheet'!B2587
='Large Sheet'!B2592
etc...
I can't just paste values either. This needs to be an active reference, because the large sheet will change.
Thanks for your help.
And here is one last approach to this that does not use VBA or formulas. It's just a quick and dirty use of AutoFilter and deleting rows.
Main idea
Add a reference to a cell =Sheet1!A1 and copy it down to match as many rows as there are in the main data.
Add another formula in B1 to be =MOD(ROW(), 5)
Filter column B and uncheck the 0s (or any single number)
Delete all the rows that are visible
Delete column B
Voila, formulas for every 5th row
Some reference images, these are all taken on Sheet2.
Formulas with AutoFilter ready.
Filtered and ready to delete
Delete all those rows (select A1, CTRL+SHIFT+DOWN ARROW, SHIFT+SPACE, CTRL+MINUS)
Delete column B to get final result with "pure" formulas every 5th row.
If you want to take a VBA approach to this, you can generate the references very quickly using simple For loops.
Here is some very crude code which can get you started. It uses hard-coded sheet names and variables. I am really just trying to show the i*5 part.
Sub CreateReferences()
For i = 0 To 12
For j = 0 To 5
Sheet2.Range("H1").Offset(i, j).Formula = _
"=Sheet1!" & Sheet1.Range("A5").Offset(i * 5, j).Address
Next
Next
End Sub
It works by building a quick formula using the Address from a reference to a cell on Sheet1. The only key here is have one index count cells in the "summary" rows and multiply by 5 to get the reference to the "master" sheet. I am starting at A5 just to match the results from INDEX.
Results show the formula input for H1 and over. I am comparing to the INDEX results generated above.
Here is one approach using INDEX instead of OFFSET. I am not sure if it is faster, I guess you can check. INDEX is not volatile, so you might get some advantage from that.
Picture of ranges, you can see that Sheet1 has a lot of data and Sheet2 is pulling every 5th row from that sheet. The data in Sheet1 goes from A1:F1000 and just reports the address of the current cell.
Formulas use INDEX and are copied down and across from A1 on Sheet2.
=INDEX(Sheet1!$A$1:$F$1000,ROW()*5,COLUMN())
I know how to make a named range in Excel.
I have a spreadsheet, with various columns going across as parameters, and then finally a formula in the last cell. This is repeated many times in each row, with each row having a different set of data, and the formula updated to reference the correct row index.
However, the formula looks like (three rows worth):
=G2*(10*D2 + 20*E2 + 5*F2)
=G3*(10*D3 + 20*E3 + 5*F3)
=G4*(10*D4 + 20*E4 + 5*F4)
I would like to use named ranges, but I can't find a way to do something like
=Count * (10*var1 + 20*var2 + 5*var3)
where count, var1, var2, and var3 automatically update to be the particular column of the current row. I can create a named range for every cell, but that isn't helpful. I can name range the column, but then I can't find a way to put an offset into the formula.
Also the whole point of this is readability, so if it ends up being some nasty complex formula function call, that probably doesn't help too much.
Simple, at least when using Excel 2010:
name your column: select full column, enter name
use column name in formula; Excel will combine the referenced column with the current row to access a single cell.
Using the example from Alex P:
select column D by clicking the column header containing the "D", enter name "input1" into name field, and press Enter.
repeat for columns E to F, using "input2" and "input3", respectively.
Do not define additional names defining names "input1" [...] as in example above!
use the formula as given in the example above
Attention:
Using named columns this way, you cannot access any other row as the one your formula is in!
At least I'm not aware of the possibility to express something like <ColName>(row+1)...
I would suggest creating a Table. Select your range A1:H4, then go to the Tables widget > New > Insert Table with Headers (on Mac). This will mark A2:H4 as body of the table, and A1:H4 as header.
From that, you get:
Whatever you put into the header column will define the name for this column automatically, e.g. Count, Radius, Density, Height
You can then write your formula using =[#Count]*(10*[#Radius] + 20*[#Density] + 5*[#Height])
When you change the formula in cell H2, Excel will automatically "copy down" this formula to all cells in column H. So no more accidental inconsistencies in the formulas.
When you need to add another row, simply click the last cell (in our example H4) and hit Tab. Excel adds another row, and also makes sure to "copy down" your formula into the new row.
If you need a total row, add it with the Total Row checkbox in the Tables widget. Excel adds a total row automatically. If you click any cell in the total row, you can change the "total formula" with the "▼▲" button, for example to calculate the Average instead of the Sum of the column.
If you have a long table and scroll down so that the header is not visible anymore, Excel automatically displays the column header instead of the column names (Count instead of G for example).
I can really recommend the video You Suck at Excel with Joel Spolsky which explains all of that.
Suppose I have the following numbers set up in columns D to F in rows 2 to 4:
D E F G
2 10 15 20
3 1 2 3
4 20 30 40
Now suppose I want the value in column D to be known as input1, column E to be input2, and column F to input3:
In Insert > Name > Define...
input1 RefersTo =OFFSET(Sheet1!$D$2,0,0,COUNT(Sheet1!$D:$D),1)
input2 RefersTo =OFFSET(Sheet1!$E$2,0,0,COUNT(Sheet1!$E:$E),1)
input3 RefersTo =OFFSET(Sheet1!$F$2,0,0,COUNT(Sheet1!$F:$F),1)
Now if I write my formula in column G as follows I should get correct answers:
G2 =(10*input1+20*input2+30*input3) // 1000
G3 =(10*input1+20*input2+30*input3) // 140
G5 =(10*input1+20*input2+30*input3) // 2000
I haven't fully reviewed the previous answers, but I think this is closer to what #Jason Coyne the OP was looking for. So, I hope I get a lot of up votes. ;-)
Excel allows your formula to refer to tables and columns by name if you "Format as Table". Here is an article titled Using structured references with Excel tables that goes into detail.
FWIW, it looks like this feature has been available since Excel 2007.
Here is a screenshot of an example:
You should be able to see the formula in E2 is =[#Count] * (10*[#Var1] + 20*[#Var2] + 5*[#Var3]) which is pretty close to what #jason-coyne wanted to type.
I don't like that you are forced to pick a style (or define a new one if you don't see a style you like). The good news is you can reformat the cells all you wish without undoing the "tableness".
It insists on turning on auto-filter. But, auto filter is easy to turn off (see the Filter Button checkbox under the Table Tools Design menu).
It also insists on having non-empty, unique values in the header row (Which kinda makes sense). If you delete a header cell, or insert a column, Excel will invent a new, unique name and stuff it in for you. D'oh!
If you want a column to not have a header, you can enter an apostrophe (') followed by one or more blanks. Remember header values need to be unique, so keep adding blanks if you want more than one column without a header.
If you would like to download the sample workbook in the screenshot, here is a link: https://filebin.ca/3vfaSDn4NLEA/SampleWorkbook.xlsx
Adding to Alex P's answer:
Instead of using =OFFSET(Sheet1!$D$2,0,0,COUNT(Sheet1!$D:$D),1) as the formula for input1, I recommend to use =Sheet1!$D$2:INDEX(Sheet1!$D:$D,COUNT(Sheet1"$D:$D))
It produces the same result, but it is non-volatile, i.e., only recalculate when a predecessor cell changes. This is much better in a larger model!
If you're using VBA, then you can select the whole column and name it, say MyCol, in the name box (upper left input box). The in your code you can refer to a cell in the column MyCol (line 12) using the following code:
Cells(12, Range("MyCol").Column)
You might be able to use the row() function. This returns the current row that you are in. So depending on the layout of the spreadsheet you can use it like this:
=offset(NamedColumn1, row()-1)
The -1 is because you are saying how many rows to move down from row 1 which if you are in row 1 you want to be 0.
Use the Excel feature called named references.
To name a cell or range of cells
select that cell or range of cells
Enter its name in the Name Box ( its left of the formula widget and has the cell name )
You can't use names that conflict with cell names, like k0.
The named cells can be used if formulas. E.g.,
=pi*radius*radius
I'd like to propose a slight variation of the cell reference made by Dror. This will work as well:
Range("MyCol").Rows(12)