sumproduct, fix one array - google-sheets

I have two columns I do the sumproduct operation on them this way:
=SUMPRODUCT(I37:I61, **D37:D61**)
and it works perfectly well - I put the result in the cell I8
but when I copy this function to cell J8
it transfers to:
=SUMPRODUCT(J37:J61, **E37:E61**)
I want TO FIX one array, so my function would look like
=SUMPRODUCT(J37:J61, D37:D61)
I hope it's clear what do I want to achieve :)
are there any ways to do so?

Not sure about google spreadsheet, but in microsoft Excel you would need to use below formula for ur use. I think same will work in Google Spreadsheet too.
=SUMPRODUCT(I37:I61, $D37:$D61)
Notice '$' which says not to translate D when you do copy-paste.

I would used named ranges to avoid any confusion. Here are the steps
1) Select the range D37:D61
2) give the name a range by tying in a name to the left hand side of the fx near where you insert the formula
3) let's call that range DATA1
4) then use the formula =SUMPRODUCT(I37:I61, DATA1)
5) when you copy this formula over to next cells it should show as =SUMPRODUCT(J37:J61, DATA1)
Let me know how you get on.

Related

Google sheets lookup with the query function within an array

I have a following formula in my google sheets
=TEXTJOIN(" -- ",TRUE,QUERY('sheetName'!B2:F,"SELECT F WHERE B = '"&$A3&"'"))
The formula is in a different sheet, same workbook though, let's call it "sheetResult". Basically it looks-up values and returns them if there is a match. There are two things I would like to achieve with it further. I need it to be an array so that it applies to all of the rows and I need it to return only the unique values found, I have tried the following but it does not work.
=ARRAYFORMULA(IF(A2:A = "" , , TEXTJOIN(", ",TRUE,UNIQUE(QUERY('sheetName'!B2:F,"SELECT F WHERE B = '"&$A2&"'"))) )) --> not sure what syntax to use
I tried filter but filter just returns all of the info stacked up, need the formula to return the data considering the rows in which the lookup value is held.
EDIT: Added a link to shared file to better describe the question.
I want to make the formula in Y3 on the "Students" sheet apply to all of the cells below it, much like an array formula does.
Example
After further studying your situation I came with a simple fix based on your original formula. I understand that you want to apply the Y3 formula to the whole table, but without altering its behaviour. I assume that the only moving part would be the students ID (Column A). Then you only need to modify your formula to lock the fixed variables with something like:
=TEXTJOIN(" -- ",TRUE,UNIQUE(QUERY('.data'!$B$2:$F,"SELECT F WHERE B = '"&A3&"'")))
After you write that on Y3 you would need to select it and drag it down to fill the table. Please leave a comment if you need further help.

Formula that will skip one column when calculating SUM() or similar functions

I'd like to run a =SUM(A1:G1), but always skip one column, regardless if it has value or not.
In this case, it should calculate A1+C1+E1+G1.
Is there another function I could append to SUM() or other similar functions as SUM in order to skip one column?
Thank you!
Using the following method you can calculate any number of alternate columns, without the need of manual +
Suppose your data is in second row onwards, use this formula
=SUMPRODUCT(A2:G2, MOD(COLUMN(A2:G2),2))
Simply a sumproduct of cell values and a array of {1,0,1,0,1...}
Another slight variation
=SUMPRODUCT(A2:G2*ISODD(COLUMN(A2:G2)))
But if the even columns contain letters instead of numbers this will give an error, so you can use instead
=SUMPRODUCT(N(+A1:G1)*ISODD(COLUMN(A1:G1)))
Comparing #AnilGoyal's answer, this works as well
=SUMPRODUCT(A1:G1,--ISODD(COLUMN(A1:G1)))
You can use:
=SUM(INDEX(A1:G1,N(IF(1,{1,3,5,7}))))
Or with Excel O365:
=SUM(INDEX(A1:G1,{1,3,5,7}))
A bit more of a general solution:
=SUMPRODUCT(MOD(COLUMN(A1:G1),2)*A1:G1)
Or with Excel O365:
=SUM(MOD(COLUMN(A1:G1),2)*A1:G1)
Or even:
=SUM(INDEX(1:1,SEQUENCE(4,,1,2)))
Since you included Google-Sheets, I'll throw in an option using QUERY():
=SUM(QUERY(TRANSPOSE(1:1),"Select * skipping 2"))
Maybe a bit more verbose, but very understandable IMO.
Consider something of the format:
=SUM(A1:G1)-INDEX(A1:G1,2)
The 2 in the formula means remove the 2nd item in the part of the row. (so the 999 is dropped)
So the formula =SUM(BZ10:ZZ10)-INDEX(BZ10:ZZ10,2) drops CA10 from the sum, etc.(a similar formula can be constructed for columns)
google sheets:
=INDEX(MMULT(N(A1:H3), 1*ISODD(SEQUENCE(COLUMNS(A:H)))))
=INDEX(IF(ISODD(COLUMN(A:H)), TRANSPOSE(MMULT(TRANSPOSE(
IFERROR(A1:H3*ISODD(COLUMN(A:H)), 0)), 1^ROW(A1:A3))), ))

How to make google sheet formula just calculate once?

I have 3 rows in my Google sheet, that is stock, price, and total. so, I just use "multiple" formula for stock and price then put the value into the total row. but I don't want total row get an update or change the value whenever I change stock value.
Can someone help me?
Assuming you want cell A1 to only calculate its value once, you can put the following in cell A1. This tells the cell to just use its existing value if there is one (and it's not 0), otherwise run the formula.
=IF(A1<>0, A1, formula())
Since the cell is referencing itself, you will need to enable iterative calculation in File > Spreadsheet settings > Calculation.
I use something like the following for historical Google Finance data, since the value is never going to change, and sometimes Google Finance randomly returns an error. This will only run the GOOGLEFINANCE() formula until it returns a non-zero value without erroring.
=IF(IFERROR(A1)<>0, A1, GOOGLEFINANCE(...))
Google Sheets is not build to operate in such a manner. The most simple and fastest solution is to calculate what you need and then use CTRL + C and repaste with CTRL + SHIFT + V
use the copy paste value option per https://www.ablebits.com/office-addins-blog/google-sheets-convert-formulas-values/
Initially I was going with Grayson's solution, but this
=IF(IFERROR(A1)<>0, A1, GOOGLEFINANCE(...))
Places a FALSE on the cell until the result is placed.
I needed that to be empty, i.e. "" as whatever different from that (cell <>"") would trigger another cell to do another query/request.
I also needed the formula to be run depending on the trigger (the url in another cell). In this formula, if the trigger is placed after the formula has run, it won't trigger it.
So I have something like
=IF(AND(IFERROR(E53)<>0,E53<>""),E53, if(D53<>"",IMPORTDATA(D53),""))
<Update 2022-11>
While using this in arrayformula I noticed something that could be wrong.
IFERROR(E53)<>0 # Doesn't make sense.
It should be
NOT(ISERROR(E53))
And the whole thing in arrayformula (careful with AND/OR )
=ARRAYFORMULA( IF( NOT(ISERROR(E2:E)) * (E2:E<>"") ,E2:E, 'SOMETHING ELSE' ) )
I leave both versions in case someone spots errors in any of them.
<End of update 2022-11>
Explanation (It took me a while to understand it, so I could extend it):
D53 = myself
If I am nothing ("") or I am in Error (importdata not yet completed)
then
I am the result of -> If(D53<>"",IMPORTDATA(D53),"")
Which is:
If the cell before me is something different from "", run the importdata
with that cell as url, otherwise I am "" (nothing)
This achieves the goal of running the formula only once if the trigger is valid (the url on the cell before is there). Once the result is placed, it won't change.
If for whatever reason you need it to run again, you have to remove the formula and place it again.
Notes: If cellX has the result of an external fetch (IMPORTDATA for example) and on cellY=cellX, while on cellX you see "Loading ..." on cellY you will see a 0 (zero). I believe that explains why the other solution was comparing with 0.

How to make a relative reference in an array formula in Google Sheets

Here's the straightforward version of my question:
I want to change the following formula to an array formula...
Original formula (from cell J2):
=if(F4="VM:",G4,J1)
My attempt at converting to an array formula (in cell K1):
=arrayformula(if(row(A:A)=1,G3,if(F:F = "VM:",G:G,indirect("K"&row(A:A)-1))))
This works on rows where F = "VM:", but returns a #REF error on other rows. Function INDIRECT parameter 1 value is 'K0'. It is not a valid cell/range reference.
Thoughts on how to fix this?
The more complex version of my question. i.e. Why am I trying to do this?...
I have a weird spreadsheet with data that should really be in a Wiki.
I want to create filter views for each person so they can easily filter on only their own vendors. The original formula will work, but as more vendors are added, I'd like for the formula to automatically work for those rows as well.
If there's a better way to do this, I'm listening.
I don't exactly understand your needs, but If you want to autopopulate your formula, then you only need this code in desire column in row 4 (you can change this to any other - this will autofill down from this point):
=ArrayFormula(if(F4:F="VM:",G4:G,J1:J))
Is this what you are trying to get?
After clarification:
You need this code in J2 only:
=ArrayFormula(VLOOKUP(ROW(J2:J),
QUERY({F:G,ROW(G:G)},"select Col3,Col2 where Col1='VM:'",1)
,2,1)
)
Works for you?
maybe you just need to hide errors?
=IFERROR(ARRAYFORMULA(IF(ROW(A:A)=1,G3,IF(F:F = "VM:",G:G,INDIRECT("K"&ROW(A:A)-1)))),)

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