How do I code a formula to apply to an entire column in Google sheets, even when you insert a new row? - google-sheets

I have a basic cash flow Google Sheet that I use to track my personal finances, cash in and out of my checking account.
Here's basically what it looks like:
Column A Column B Column C
Row 1 | Water bill | -50.00 | 400.00
Row 2 | Credit card | -300.00 | 100.00 >> the formula here is =sum(C1,B2)
Row 3 | Paycheck | 2000.00 | 2100.00 >> the formula here is =sum(C2,B3)
I project this out a full year. Anytime I want to add a row, I have to manually apply the formula in column C, and then I also have to fix the formula in the row just below it, which then fixes the problem for the rest of the sheet.
In Google Sheets, Is there a way for me to hard-code a formula for Column C that would allow me to insert a new row and always have it math perfectly without having to manually add the formula, and fix the formula in the row below it?
Let me know if there would be an easier way to do this by making fundamental changes to how it's setup - this is just how I've done it for so long, and I'm looking for a way to automate this going forward.
I've heard array formula might be helpful, but I'm not sure how to set it up.

There are many kinds of ArrayFormulas and LAMBDA functions. I suggest you look into them for different cases and uses. There is one kind in particular that would serve to your purposes:
=SCAN(0,B2:B,LAMBDA(a,v,a+v))
If you put this in C2 you'll have a cumulative sum row by row. Try it and let me know!
If you want to hide the results if column B is empty you can use another ARRAYFORMULA to check if B is empty it returns empty, either way returns the SCAN result:
=ARRAYFORMULA(IF(B2:B="","",SCAN(0,B2:B,LAMBDA(a,v,a+v))))

If you need to insert a new row in between then it's quite tedious as it will mess up the formulas below it, but if you just keep appending a new entry on the bottom row, then the formula will smartly mimic the behavior above it. Then you can simply do this:
Select the current last row, then click the small dot at the end and drag it down to as much as you want
OR, Ctrl+C (Copy) the last row, then select as much empty rows beneath it as you want, then Ctrl+V (Paste)

Related

How can I use Array Formula with multiple SUMIFs?

I am a beginner with google sheets formulas, I created a formula which is not very efficient nevertheless it works and gives correct output, here is the formula:
=if($C$2:$C = "Check-Out",
SUM((SUMIFS($D$2:$D,$C$2:$C,"Check-In",$B$2:$B,B2,$A$2:$A,"<"&A2)+
SUMIFS($D$2:D,$C$2:$C,"Request Extra Key",$B$2:$B,B2,$A$2:$A,"<"&A2))-
(SUM(SUMIFS($D$2:$D,$C$2:$C,"Check-Out",$B$2:$B,B2,$A$2:$A,"<"&A2)+
SUMIFS($D$2:$D,$C$2:$C,"Return Extra Key",$B$2:$B,B2,$A$2:$A,"<"&A2)))),D2)
I want to copy this formula automatically to the last nonempty row, and I used ArrayFormula to copy this to last row:
=ARRAYFORMULA(if($C$2:$C = "Check-Out" ,SUM((SUMIFS($D$2:$D,$C$2:$C,
"Check-In",$B$2:$B,B2:B,$A$2:$A,"<"&A2:A)+SUMIFS($D$2:$D,$C$2:$C,
"Request Extra Key",$B$2:$B,B2:B,$A$2:$A,"<"&A2:A))-
(SUM(SUMIFS($D$2:$D,$C$2:$C,"Check-Out",$B$2:$B,B2:B,$A$2:$A,"
<"&A2:A)+SUMIFS($D$2:$D,$C$2:$C,"Return Extra Key",$B$2:$B,B2:B,$A$2:$A,"
<"&A2:A)))),$D$2:$D))
it does copy the formula to the last row but the output values are not correct, here is the sheet, Column E contains correct values by dragging down the formula. I want to get same values by using ArrayFormula. Any help would be much appreciated. Thank you
From what I'm understanding you're trying to keep track of how many keys are dispensed and whether it is permitted to dispense an additional key or not (based on rules).
For this I would take a different approach.
I would use a separate Tab (KeyCount) for calculations and only return the OK or NOT OK message back to the KeyLog Tab.
In the KeyCount Tab I would list all the Keys and the number of times they were added to the system, subtracted by check ins etc.
KeyCount Tab
| Key ID | Add Key | Check-In | Check-Out | Return Extra | Count |
For the Key ID Column I would list all the unique keys:
=unique(KeyLog!B2:B)
For Add Key I would sum all the entries that list that unique key:
=arrayformula(sumif(KeyLog!B2B:B,KeyCount!A2:A,KeyLog!D2:D))
For Check-In I would do the same as above but make it a negative by surrounding the formula with -( ). This way this will be a negative number regardless of the sum.
Do the same as above for the other Triggers.
Finally I would add a Count column which simply uses an Array to add and subtract the different triggers in each row to tell you the current balance of keys for each unique key.
This is the figure you use in your KeyLog to decide if it's OK or NOT OK.
BONUS: You can set up a table in another tab which decides if its ok or not ok. For example if number of keys should not exceed 2, then have your array formula in KeyLog look up this table table and return the OK or NOT OK Message. This way if you change policies and allow extra keys you can easily change the rules in this table without messing with the formulas in other tabs. You can also add a longer explanation message such as "Not enough keys" or "Number of allowed keys exceeded" to this table which can show in the KeyLog table.
I hope this helps you solve your problem. Let me know if you need further explaining.
Happy coding!

Google sheets - select multiple columns for data validation

I'm new on google spreadsheets, and I'm having this little problem:
I want to create a project manager with an external spreadsheet just for customer-info. In my "main-hub" sheet, I have created a dropdown menu on B11 which copys the customer names from the extrenal sheet. That works fine.
Now the problem I am trying to solve: I want to keep the drop-down menu on B11, i dont want to add any new drop down menus. Whenever I select an item from the menu on B11, additional information about the customer should be inserted into different cells in different columns. Example:
| __________ B11 __________ | __________ J11 __________ | __________ K11 __________ |
Selected Name dynamicly inserted data 1 dynamicly inserted data 2
Please keep in mind, I really don't want to add any new drop down menu, I want to keep only this one for the names of the customers.
What you're looking for is "VLOOKUP". This is a Formula where you can define a specific range and select the part you want to display. I've edited your spreadsheet.
=IFERROR(VLOOKUP(A2;'Customers static'!$A$2:$C$5;2;FALSE);"")
IFERROR Value, [value if error]
VLOOKUP Search key, area, index, is sorted
Seeing that you have not solved your answer. I have created a new sheet in your spreadsheet showing you a possible answer.
Possible solution
Basically you can have a dynamically expandable sheet with the use of ARRAYFORMULA.
Which is kind of basically repeat this operation for the whole range. In this case you just would need to put one formula for each column:
=ARRAYFORMULA(IFERROR(VLOOKUP(A:A;'Customers static'!A2:D;2;FALSE)))
Look how instead of using a single value for VLOOKUP you are using the whole range and ARRAYFORMULA will handle that. Therefore you just need to write the formula at the top of each column, changing the index for every single column in the original data.
You can take a look in the Raserhin's help on the sheet you have provided.

Arrayformula - Adding together a dynamically generated list of ranges

I'm looking for a way to add together a dynamically generated list of ranges using (I'm guessing) an ARRAYFORMULA.
The normal way of attacking this is fine if there is a known list of ranges, the example of the results I want would work using this:
=ARRAYFORMULA( A1:A10 + B1:B10 )
In the case I'm after I want to add together ranges in multiple sheets. I don't want the users to have to manually adjust the array formula every time they add a new sheet to be calculated, and I also want to be able to add some logic to include or remove the particular sheet from the calculation, but for now I'm happy to ignore that and just focus on adding cells together.
My approach to this was to create a column with a list of names, each one matching a sheet in the document, and then using that list to dynamically build the list of ranges to add together, using INDIRECT.
.------------.
| sheet1 | <---- SheetListNamedRange
|------------|
| sheet2 |
`------------'
Here's a quick example
=ARRAYFORMULA( INDIRECT("'" & SheetListNamedRange & "'!D4:75") )
There are lots of failure modes depending on how it's done, but this particular formula only puts in the values of the first sheet and ignores any others, which I guess makes sense.
What I'm after is kind of the equivalent of i++ in a loop found in a normal coding language. Is there some way of making this work?
If I understand you correctly, you'd like to get a list generated based on different ranges across different sheets. If your case is as simple as the one you mention in the beginning of your post, the following would do the job.
={Sheet1!A1:A2; Sheet2!B1:B2}
If you want the sum of all these values, you can use SUM.
=SUM({Sheet1!A1:A2; Sheet2!B1:B2})
Please let me know if this isn't what you were looking for, so I can change the answer accordingly.
you can't refer to array of arrays in INDIRECT. you will need to INDIRECT each sheet which contains array.
=SUMPRODUCT(ARRAYFORMULA(INDIRECT(A1&"!"&"D:D")+
INDIRECT(A2&"!"&"D:D")+
INDIRECT(A3&"!"&"D:D")+
INDIRECT(A4&"!"&"D:D")))
note1: in this case result is 25 as sum of 10 + 15.
10 is sum of sheet1!D:D
and 15 is sum of sheet2!D:D
note2: there is no sheet3 and sheet4 which is equal to 0 in INDIRECT
note3: D:D of the sheet where you have the list of sheets needs to be empty

Sum above cells ignoring blanks

I have a spreadsheet where I have data from a bank account. Each bank transaction has a date and an indication if that transaction is already done or if it's just expected. When it's already done, it must be added to the total balance up to date. If not, then the total balance up to date must be blank. I need to autofilter the data, so I can filter and order it depending on date or other conditions, that's why I've been using this formula:
=IF(D3="Y";B3+INDIRECT(ADDRESS(ROW()-1;COLUMN()));"")
Problem here is that when the cell above is blank, total sum resets and it starts from the value of that transaction. I need a formula that ignores the upper blank cells, and sums all cells above that are not blank plus the amount of that transaction.
Besides, once I change the "N" in "Done" Column to a "Y" I need the formula to update and show the correct balance.
I share an example sheet for better understanding https://docs.google.com/spreadsheets/d/1_gk0YaziUhOZfRbrlfHizMrVu6OT7njIaTUyQaE6Lbs/edit?usp=sharing
Ok I THINK I understand what your going for - please let me know if I am confused, but I added an example on your sheet.... basically what I ended up doing was including one of your conditionals, but then also adding another function to exclude the blank rows by way of filter , index and counta It looks more complicated than it is because I nested it all back into one formula:
=IF(I3="Y";sum(G3;index(filter(indirect("F2:"&address(row()-1;column();4));ISNUMBER(indirect("F2:"&address(row()-1;column();4))));counta(filter(indirect("F2:"&address(row()-1;column();4));ISNUMBER(indirect("F2:"&address(row()-1;column();4)))))););)
To work it from the inside out - the way I am excluding the blank rows is by using FILTER to get all the rows from the first row with a value ( Like A2 in your example) and using INDIRECT and ADDRESS to end the array I want to include exactly one cell above the current cell.
Then I use the condition that the range I built has a number value in it, there fore excluding the blanks.
In order to get the last value available, I use COUNTA to find out the total rows in the filter, then wrap the formula with INDEX to use the counta value as the row to return (which automatically is the last row available above the current cell)
Try this in A3 and copy down:
=IF(D3="Y";B3+INDIRECT(ADDRESS(ROW()-1;COLUMN()));A2+0)
If you want to display the "N" rows as blank, add a column (B) fill in the header and the starting number (5000) then put this in B3:
=if(E3="N";"";A3)
Copy it down then hide column A.

Google Spreadsheet sum which always ends on the cell above

How to create a Google Spreadsheet sum() which always ends on the cell above, even when new cells are added? I have several such calculations to make on each single column so solutions like this won't help.
Example:
On column B, I have several dynamic ranges which has to be summed. B1..B9 should be summed on B10, and B11..B19 should be summed on B20. I have tens such calculations to make. Every now and then, I add rows below the last summed row , and I want them to be added to the sum. I add a new row (call it 9.1) before row 10, and a new raw (let's call it 19.1) before row 20. I want B10 to contain the sum of B1 through B9.1 and B20 to contain the sum of B11:B19.1.
On excel, I have the offset function which does it like charm. But how to do it with google spreadsheet? I tried to use formulas like this:
=SUM(B1:INDIRECT(address(row()-1,column(),false))) # Formula on B10
=SUM(B11:INDIRECT(address(row()-1,column(),false))) # Formula on B20
But on Google Spreadsheet, all it gives is a #name error.
I wasted hours trying to find a solution, maybe someone can calp?
Please advise
Amnon
You are probably looking for formula like:
=SUM(INDIRECT("B1:"&ADDRESS(ROW()-1,COLUMN(),4)))
Google Spreadsheet INDIRECT returns reference to a cell or area, while - from what I recall - Excel INDIRECT returns always reference to a cell.
Given Google's INDIRECT indeed has some hard time when you try to use it inside SUM as cell reference, what you want is to feed SUM with whole range to be summed up in e.g. a1 notation: "B1:BX".
You get the address you want in the same way as in EXCEL (note "4" here for row/column relative, by default Google INDIRECT returns absolute):
ADDRESS(ROW()-1,COLUMN(),4)
and than use it to prepare range string for SUM function by concatenating with starting cell.
"B1:"&
and wrap it up with INDIRECT, which will return area to be sum up.
REFERRING TO BELOW ANSWER from Druvision (I cant comment yet, I didn't want to multiply answers)
Instead of time consuming formulas corrections each time row is inserted/deleted to make all look like:
=SUM(INDIRECT(ADDRESS(ROW()-9,COLUMN(),4)&":"&ADDRESS(ROW()-1,COLUMN(),4)))
You can spare one column in separate sheet for holding variables (let's name it "def"), let's say Z, to define starting points e.g.
in Z1 write "B1"
in Z2 write "B11"
etc.
and than use it as variable in your sum by using INDEX:
SUM(INDIRECT(INDEX(def!Z:Z,1,1)&":"&ADDRESS(ROW()-1,COLUMN(),4))) - sums from B1 to calculated row, since in Z1 we have "B1" ( the 1,1 in INDEX(...,1,1) )
SUM(INDIRECT(INDEX(def!Z:Z,2,1)&":"&ADDRESS(ROW()-1,COLUMN(),4))) - sums from B11 to calculated row, since in Z2 we have "B11" ( the 2,1 in INDEX(...,2,1) )
please note:
Separate sheet named 'def' - you don't want row insert/delete influence that data, thus keep it on side. Useful for adding some validation lists, other stuff you need in your formulas.
"Z:Z" notation - whole column. You said you had a lot of such formulas ;)
Thus you preserve flexibility of defining starting cell for each of your formulas, which is not influenced by calculation sheet changes.
By the way, wouldn't it be easier to write custom function/script summing up all rows above cell? If you feel like javascripting, from what I recall, google spreadsheet has now nice script editor. You can make a function called e.g. sumRowsAboveMe() and than just use it in your sheet like =sumRowsAboveMe() in sheet cell.
Note: you might have to replace commas by semicolons
NOTE
After testing this answer, it will only work if the sum is in a different column due to a circular dependency error. Otherwise, the solution is valid.
It's a bit of algebra, but we can take advantage of Spreadsheets' lower right corner drag.
=SUM(X:X) - SUM(X2:X)
Where X is the column you are working with and X2 is your ending point. Drag the formula down and Sheets will increment the X2, thus changing the ending point.
*You mentioned that you had tens of such calculations to make. So in order to fit your exact need, we would subtract your last summation to get that "middle" range that we wanted.
e.g.
B1..B9 should be summed on B10, and B11..B19 should be summed on B20
Because of the circular dependency error mentioned earlier, I can't solve it exactly and put the sum on the same line, but this could work in other cases where the sum needs to be stored in a different column.
=SUM(B:B) - SUM(B9:B) //Formula on C10 (Sum of B1..B9)
=SUM(B:B) - SUM(B19:B) - B10 // Formula on C20 (Sum of B11..B19)
This is based on #PsychoFish, here is the solution:
=SUM(INDIRECT(SUBSTITUTE(ADDRESS(1,COLUMN(),4),"1","")&"3:"&ADDRESS(ROW()-1,COLUMN(),4)))
Simply replace the "3:" for the row to start sum.
#PsychoFish is correct but cannot be dragged and copied since the column is literal and hard coded, and #Druvision was in the right direction but was wrong... basically ended up with the same issue of having to re-enter the ranges and then sliding the formulas over and over.
You guys are making this harder than you have to. I just leave a couple of empty rows above by "sum" row (you can format them to be filled with color or something to keep them from being inadvertently used), then just add your new rows just above those special rows.
Agree with what user7255446 said that everyone is overcomplicating. Keep one row blank before your sum row. And then whenever you want to insert a new row, click on your blank row and use "Insert row ABOVE" instead of "insert row below". Your sum formula will automatically adjust.
Example: I want to sum from B1 to B19. I leave row 20 blank. In cell B21, put =SUM(B1:B20). Then if you ever need to insert a new row, click on row 20 and choose "Insert row above". The sum formula automatically changes to =SUM(B1:B21) for you. And of course your sum cell is now B22.
General syntax:
=SUM(INDIRECT(cell_reference_as_string1 &":"& cell_reference_as_string2)
with for example:
cell_reference_as_string1 = ADDRESS(ROW(),COLUMN(),4)
cell_reference_as_string2 = ADDRESS(ROW()-1,COLUMN(),4)
I like how #abernier describes the general solution. So far only alphabet-based A1 notation (A being first column, 1 being first row) are being used. It keeps confusing me, especially when thinking of number of columns left of another column. I like the number-based R1C1 notation much better. To use R1C1 notation for INDIRECT, you need to pass FALSE like so:
=SUM(INDIRECT("R1C"&COLUMN()&":R"&(ROW()-1)&"C"&COLUMN(), FALSE))
I hope you find that helpful, too.
OFFSET() can be used/abused for this purpose. Give it the absolute address of the top left of the range, 0 and 0 for the row/column offsets, and the height/width of the range. Let OFFSET() be the argument to SUM(), SUMIF(), etc.
ROW() and COLUMN() are handy when computing the desired height/width. Be sure to remember to subtract one to exclude the current row/column, or else you're liable to end up with a circular reference. If you have header rows/columns, subtract for them too.
For example, to sum everything from A2 down, excluding the current row, try:
=SUM(OFFSET($A$2,0,0,ROW()-2,1))
To sum everything to the left of the current cell, wherever it may be, try:
=SUM(OFFSET(INDIRECT("RC1",FALSE),0,0,1,COLUMN()-1))
Now let's flip things upside down, to show that this works in the other direction. Suppose you want to sum the B column, starting below the current row, until (and including) row #10. Try this:
=SUM(OFFSET($B$10,ROW()-9,0,10-ROW(),1))
You can avoid negative offsets, while still summing column B:
=SUM(OFFSET(INDIRECT("RC2",FALSE),1,0,10-ROW(),1))
Remove the "2" to instead sum the current column:
=SUM(OFFSET(INDIRECT("RC",FALSE),1,0,10-ROW(),1))
(Credit to Tom Sharpe, who commented above.) INDEX() can be used in a range expression. You might prefer this over OFFSET(), so I'm putting it here. The following sums everything from G1 down to the row above the current:
=SUM(G1:INDEX(G:G,ROW()-1))
Here's how I do it.
This formula does not require you to edit or enter anything about the particular column you would like to sum
=SUM(INDIRECT(CONCATENATE(address(1,column(),4),":",LEFT(address(1,column(),4),1))&ROW()-1))
The answer by #PsychoFish led me in the correct way.
The only issue that I had to rewrite the formula again from each column and each sum. So here is the improved formula, which sums the previous 9 cells on the same column, without hardcoding the column or row numbers:
=SUM(INDIRECT(ADDRESS(ROW()-9,COLUMN(),4)&":"&ADDRESS(ROW()-1,COLUMN(),4)))
The only issue is that I had to rewrite the formulas if someone adds or deletes a row. In this case I should change 9 to 10 or 8 corrspondingly.

Resources