I've been trying to figure out what i'm doing wrong here when i'm doing the sumif formula's in b2,c2,d2
I have a lot going on, I realize. The data we are looking at, is between L5:U21
I have a query in a5 that pulls from l5:U that pairs any data in n5:n,p5:p,r5:r,t5:t to the selected data in the dropdown in a2. This part is working correctly for what I need.
B2 I am trying to extract from the top 3 options in the range b5:J that match a2, and add them together. Ultimately I'd like to do this if they do not have "Left" or "Right" in the J column as well.
To achieve this I pulled the data from b5:I into a sortn function seen in y5.
=SORTN(B5:I,3,,B5:B,false,D5:D,false,F5:F,false,H5:H,false)
and then my SUMIF function is as follows: =SUMIF(Z5:AF,A2,Y5:AE)
C2 is similar to B2, but I only data that matches the selection in a2, but also have "Left" in the J column.
I tried to achieve this with a similar SUMIF function i'm using in b2, but it seems to only pull the left most cell's data in the range given, not the matching column's data. So lets say if e9 = example1, it doesn't then grab the matching 2 in d9, it grabs whatever is in b9 only, and adds that. Which right now, it adds them all. I want to ultimately only pull the top 1, but I cannot even get it working correctly with all of them.
=SUMIF(J5:J,"Left",B5:H)
D2 is the same as C2, but "Right" in the J column.
This is my example / testing document I created to get a closer look at what's going on, if what i'm explaining isn't making a ton of sense.
https://docs.google.com/spreadsheets/d/1eZ7_yOrkoy_PCgcn_YxscPnDCvLXWK48JW-S7DqEgdQ/edit?usp=sharing
Try the following in C2
=QUERY({{B5:C;D5:E;F5:G},{J5:J;J5:J;J5:J}},
"select sum(Col1) where Col2='"&A2&"' and Col3='Left'
label sum(Col1) '' ",0)
For cell D2 all you need to do is use Col3='Right'
=QUERY({{B5:C;D5:E;F5:G},{J5:J;J5:J;J5:J}},
"select sum(Col1) where Col2='"&A2&"' and Col3='Right'
label sum(Col1) '' ",0)
In case you want to add more ranges like columns H-I you would adjust your formula like:
{{B5:C;D5:E;F5:G;H5:I},{J5:J;J5:J;J5:J;J5:J}}
(Do adjust the formula according to your ranges and locale)
SUGGESTION
I was experimenting earlier with SUMIFS & QUERY formulas to no success, as I also have a limited knowledge when it comes to implementing advanced Google Sheet formulas in a complex scenario. What I can suggest you try is by using a Custom Function formula in Google Sheet made possible by Google Apps Script that's integrated to the Google Sheet service.
This custom formula function will filter the range that does not contain Left or Right in column J based on the selected drop-down data, and then it returns the top 3 results in descending order.
The Custom formula Script named as CUSTOM_FUNC
/**
* Filters data in descending order from a range that doesn't contain any Left & Right based on selection in a cell dropdown selection & return the sum of the top 3 result.
*
* #param {B5:J21,A2} reference The range to be used.
* #returns The range and the cell reference to used in filtereing the data.
* #customfunction
*/
function CUSTOM_FUNC(data,dropdown_selection) {
/**Filter data that do not contain Left or Right on column J */
var lvl1 = data.map(x => {return x.toString().includes('Left') || x.toString().includes('Right') ? null : x }).filter(y => y)
/**Further filter lvl1 that matches the drop down selection*/
var res = lvl1.map(d => {
return d.map((find, index) => {return find == dropdown_selection ? d[index-1] : null}).filter(z => z)
});
/**Return the top 3 result in descending order */
return res.sort().reverse().slice(0, 3);
}
The parameters of this customer formula would be:
=CUSTOM_FUNC(data,dropdown_selection)
data
The sheet range (e.g. B5:J21) where the data you'd like to be processed resides.
dropdown_selection
The cell reference of the drop-down selection on your spreadsheet file.
To add this script in your spreadsheet file, copy and paste the script as a bound script in your Spreadsheet file by following this official guide
Demonstration
You can use the custom function formula named CUSTOM_FUNC similarly to how you use another Google Sheet formula on a cell, like this =SUM(CUSTOM_FUNC(B5:J21,A2))
I have a spreadsheet where some columns are progressively merged to represent the balance of a period. Roughly like this:
(don't mind the actual values, these are random just to illustrate)
It is easy enough to just use simple formulas to refer to the ranges to the left when you are looking at them and know, for instance, that this week is C16:C22, next week is C23:C29 and so on. Weeks are relatively simple as they are regular, but months are a bit more complex, yet still just as doable. It is toilsome, though.
What I would really like to do though, would be to just get the size of the merged cell, for instance, if there was a way to write a formula like CELL('rows') that would tell me how many rows it occupies.
Unfortunately I've only managed to find a ROW() formula function that only tells the first row of the current (merged) cell, and a ROWS() that requires that I pass it a range, which is what I'm trying to obtain in the first place. Once I have the cell size in rows, I can infer its data range to the left and won't have to manually edit the formulae for each week and month. Even if I still need to do the merging, that will save a ton of work.
I would prefer to stick with formulae only, but if the solution lies in a script, so be it.
counting merged cells is possible only with script.
but there is an alternative... for week count you can use:
=ARRAYFORMULA(IF(A2:A="";;ISOWEEKNUM(A2:A)))
then to turn it into a count like:
=ARRAYFORMULA(IF(A2:A="";;COUNTIFS(
ISOWEEKNUM(A2:A); ISOWEEKNUM(A2:A); ROW(A2:A); "<="&ROW(A2:A))))
respectively for a month, you can do:
=ARRAYFORMULA(IF(A2:A="";;MONTH(A2:A)))
I could not get the desired results with a formula like #player0 but as an alternative, you can also try this script.
Once you run the script, it will write on column F the number of rows and the range of the merged cells from column E. You can change ranges in the script to test it with other columns that have merged cells.
function numRows(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Página1");
var range = sheet.getRange("E2:E")
if( range.isPartOfMerge() ) {
var range = range.getMergedRanges();
for (i=0; i<range.length;i++){
var numRows = range[i].getNumRows();
var ranRows = range[i].getA1Notation();
var lastRow = range[i].getLastRow();
Logger.log("Number of rows in range "+ ranRows + " is: " + numRows)
sheet.getRange("F"+lastRow).setValue("Range: "+ranRows+"\n"+ "NumRows: "+numRows)
}
}
else {
}
}
Let me know if you have any questions.
please refer to the images below
Sheet1
sheet2
I have 2 sheets: sheet1 and sheet2, here's what I want to do: if sheet2!B37 = sheet1!B1, take the value of sheet1!B2, if not stay blank.
This part is easy, but what I want is that if I change the date in sheet1!B1 to 16 Mar 2021 and sheet1!B2 to 90, I want sheet2!C37 to stay 100 and sheet2!C38 returns 90.
One way is to copy the content of sheet2!C37 and paste it as value.
Reference: Convert formulas to values in Google Sheets
But I doubt that you would want to convert the formula into a value every time you need to change the condition. Hence, you might want to consider using Google Apps Script and run it using a button.
Sample Code:
function updatePrice() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
//Get Sheet1 object
var sheet1 = ss.getSheetByName("Sheet1");
//Get Sheet1 object
var sheet2 = ss.getSheetByName("Sheet2");
//Get Sheet1!B1 string value
var targetDate = sheet1.getRange("B1").getDisplayValue();
//Get Sheet1!B2 string value
var targetPrice = sheet1.getRange("B2").getDisplayValue();
//Get Sheet2 column B range
var dates = sheet2.getRange("B1:B");
//Create a textfinder and look for the target date (Sheet1!B1 value)
var textFinder = dates.createTextFinder(targetDate);
var firstOccurrence = textFinder.findNext();
if(firstOccurrence!=null){
//Date found
//Update price in column C
firstOccurrence.offset(0,1).setValue(targetPrice);
}
}
What it does?
Get the active spreadsheet using SpreadsheetApp.getActiveSpreadsheet()
Get the sheet object for Sheet1 and Sheet2 using Spreadsheet.getSheetByName(name)
Select the range for Sheet1!B1 and Sheet1!B2 using Sheet.getRange(a1Notation). Get the string value using Range.getDisplayValue()
Select the range for Sheet2!B1:B using [Sheet.getRange(a1Notation)]
Create a textFinder using Range.createTextFinder(findText)
Get the first occurrence of the date string that was being searched using TextFinder.findNext(). If date string has no match, return will be null. If date string has match it will return a Range of the matching cell
Matching cell will give you a range in column B, to set the price value move the range 1 column to the right by adding 1 column offset using Range.offset(rowOffset, columnOffset) and set the range value using Range.setValue(value)
Add A Google Sheets Button To Run Scripts
Add a Google Sheets button. You add a button via the Insert > Drawing menu.
Click Save and Close, this drawing gets added to your Google Sheet. You can right click on it to resize it or drag it around to reposition it.
To assign a script, Right Click the drawing and click the three little dots in the top right of the drawing and select Assign Script. Then type in the name of the function you want to run from your Apps Script code.
Output:
Note:
Please don't forget to click enter when editing your Sheet1 values before clicking the button. Apps Script cannot update Sheet2 when the cell to be read is still in edit.
To start, this is my first time posting and so please let me know if I can fix my post in any way to make it easier to answer.
I am trying to create an auto-expanding array formula
I have a sheet with my investment asset mix that including amounts of shares owned of each particular stock, and a sheet that tracks when I receive dividends. My goal is to write an automatically expanding array formula that will sum up the amount of shares that own of a stock on the date a dividend is received and return that value. I have written three different formulas that all accomplish this but none of them will auto-expand as an array.
I'm sure there are a lot of solutions I've overlooked. To boil it down, I need an expanding array formula that will sum the "Shares" column of my asset mix sheet ('Asset Mix'!D2:D, or 'AssetMixShares') conditionally. The name of the stock entered in 'Dividends'!C2:C needs to match the name of the stock in 'Asset Mix'!A2:A (or the named range 'AssetMixStocks'). It then needs to check the dates in 'Asset Mix'!C2:C (or 'AssetMixDates') against the dates in 'Dividends'!A2:A and sum all share amounts where the purchase date is less than (earlier than) the Ex-Dividend Date.
I could probably write some sort of vlookup array on the "Running Total" column -- 'Asset Mix'!E:E -- that would solve the issue, but I'm hoping to eliminate that column. I feel very strongly that what I'm trying to do should be possible without the help of a running total column -- I just don't have the knowledge.
I have tried countless functions and formulas, but the four that I currently have in my example worksheet are SUM, SUMPRODUCT, DSUM, and QUERY.
Attempt 1
SUM and IF
=ArrayFormula(SUM(IF('Asset Mix'!A:A=C2,IF('Asset Mix'!C:C<A2,'Asset Mix'!D:D))))
Attempt 2
SUMPRODUCT
=({arrayformula(SUMPRODUCT(--((AssetMixStock=(indirect("C"&ROW())))*(AssetMixDate<(indirect("A"&ROW())))),AssetMixShares))})
Attempt 3
DSUM
=DSUM('Asset Mix'!A:E,"Shares",{"Date","Stock";"<"&A2,C2})
Attempt 4
QUERY
=arrayformula(query(AssetMix,"Select sum(D) where A = '"&C2:C&"' and C < date'"&(text(year(A2:A),"0000") & "-" & text(month(A2:A),"00") & "-" & text(day(A2:A),"00"))&"' label sum(D) ''",0))
These will all work, as long as I manually drag the formula down, but I want to write some sort of formula that will auto-expand to the bottom of the Dividends sheet.
I have tried to create a Dummy sheet that has both of the relevant sheets. Please let me know if you can access it -- the link is below.
https://docs.google.com/spreadsheets/d/1wlKffma0NJ0KrlWxyX_N20y62azsGpFp3enhmjzJK1Q/edit?usp=sharing
Thanks so much for getting this far and any help you can provide!
We can focus in the first formula to understand a way to make it "self-expandable". As we see it contains references to the cells A2 and C2 in "Dividends" sheet:
=ArrayFormula(SUM(IF('Asset Mix'!A:A=C2,IF('Asset Mix'!C:C<A2,'Asset Mix'!D:D))))
Every time some data appears in these columns (A and C), the formula should work. We can control the presence of the formula by onEdit trigger, if editing is manual. Consider the code:
function onEdit(e) {
var sheet = SpreadsheetApp.getActive().getActiveSheet();
if (sheet.getName() == 'Dividends') {
var row = e.range.getRow();
for (var offset = 0; offset < e.range.getHeight(); offset++) {
sheet.getRange(3, 10).copyTo(sheet.getRange(row + offset, 10));
}
}
}
It checks any modification on the sheet "Dividends" and copies required formula to the modified row(s). This way the formula is expanded for other rows in use.
Well, it's solved! I'll leave this up in case anyone else has the same question.
A kind soul explained the magic of MMULT() to me, and wrote this solution.
=ARRAYFORMULA(MMULT((C2:C=TRANSPOSE('Asset Mix'!A2:A))*(A2:A>TRANSPOSE('Asset Mix'!C2:C)),N('Asset Mix'!D2:D))
I use the following function
=DAYS360(A2, A35)
to calculate the difference between two dates in my column. However, the column is ever expanding and I currently have to manually change 'A35' as I update my spreadsheet.
Is there a way (in Google Sheets) to find the last non-empty cell in this column and then dynamically set that parameter in the above function?
There may be a more eloquent way, but this is the way I came up with:
The function to find the last populated cell in a column is:
=INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) )
So if you combine it with your current function it would look like this:
=DAYS360(A2,INDEX( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ; ROWS( FILTER( A:A ; NOT( ISBLANK( A:A ) ) ) ) ))
To find the last non-empty cell you can use INDEX and MATCH functions like this:
=DAYS360(A2; INDEX(A:A; MATCH(99^99;A:A; 1)))
I think this is a little bit faster and easier.
If A2:A contains dates contiguously then INDEX(A2:A,COUNT(A2:A)) will return the last date. The final formula is
=DAYS360(A2,INDEX(A2:A,COUNT(A2:A)))
Although the question is already answered, there is an eloquent way to do it.
Use just the column name to denote last non-empty row of that column.
For example:
If your data is in A1:A100 and you want to be able to add some more data to column A, say it can be A1:A105 or even A1:A1234 later, you can use this range:
A1:A
So to get last non-empty value in a range, we will use 2 functions:
COUNTA
INDEX
The answer is =INDEX(B3:B,COUNTA(B3:B)).
Here is the explanation:
COUNTA(range): Returns number of values in a range, we can use this to get the count of rows.
INDEX(range, row, col): Returns the content of a cell, specified by row and column offset. If the column is omitted then the whole row is returned.
Examples:
INDEX(A1:C5,1,1) = A1
INDEX(A1:C5,1) = A1,B1,C1 # Whole row since the column is not specified
INDEX(A1:C5,1,2) = B1
INDEX(A1:C5,1,3) = C1
INDEX(A1:C5,2,1) = A2
INDEX(A1:C5,2,2) = B2
INDEX(A1:C5,2,3) = C2
INDEX(A1:C5,3,1) = A3
INDEX(A1:C5,3,2) = B3
INDEX(A1:C5,3,3) = C3
For the picture above, our range will be B3:B. So we will count how many values are there in range B3:B by COUNTA(B3:B) first. In the left side, it will produce 8 since there are 8 values while it will produce 9 in the right side. We also know that the last value is in the 1st column of the range B3:B so the col parameter of INDEX must be 1 and the row parameter should be COUNTA(B3:B).
PS: please upvote #bloodymurderlive's answer since he wrote it first, I'm just explaining it here.
My favorite is:
=INDEX(A2:A,COUNTA(A2:A),1)
So, for the OP's need:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A),1))
If the column expanded only by contiguously added dates
as in my case - I used just MAX function to get last date.
The final formula will be:
=DAYS360(A2; MAX(A2:A))
Here's another one:
=indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),""))))
With the final equation being this:
=DAYS360(A2,indirect("A"&max(arrayformula(if(A:A<>"",row(A:A),"")))))
The other equations on here work, but I like this one because it makes getting the row number easy, which I find I need to do more often. Just the row number would be like this:
=max(arrayformula(if(A:A<>"",row(A:A),"")))
I originally tried to find just this to solve a spreadsheet issue, but couldn't find anything useful that just gave the row number of the last entry, so hopefully this is helpful for someone.
Also, this has the added advantage that it works for any type of data in any order, and you can have blank rows in between rows with content, and it doesn't count cells with formulas that evaluate to "". It can also handle repeated values. All in all it's very similar to the equation that uses max((G:G<>"")*row(G:G)) on here, but makes pulling out the row number a little easier if that's what you're after.
Alternatively, if you want to put a script on your sheet you can make it easy on yourself if you plan on doing this a lot. Here's that scirpt:
function lastRow(sheet,column) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (column == null) {
if (sheet != null) {
var sheet = ss.getSheetByName(sheet);
} else {
var sheet = ss.getActiveSheet();
}
return sheet.getLastRow();
} else {
var sheet = ss.getSheetByName(sheet);
var lastRow = sheet.getLastRow();
var array = sheet.getRange(column + 1 + ':' + column + lastRow).getValues();
for (i=0;i<array.length;i++) {
if (array[i] != '') {
var final = i + 1;
}
}
if (final != null) {
return final;
} else {
return 0;
}
}
}
Here you can just type in the following if you want the last row on the same of the sheet that you're currently editing:
=LASTROW()
or if you want the last row of a particular column from that sheet, or of a particular column from another sheet you can do the following:
=LASTROW("Sheet1","A")
And for the last row of a particular sheet in general:
=LASTROW("Sheet1")
Then to get the actual data you can either use indirect:
=INDIRECT("A"&LASTROW())
or you can modify the above script at the last two return lines (the last two since you would have to put both the sheet and the column to get the actual value from an actual column), and replace the variable with the following:
return sheet.getRange(column + final).getValue();
and
return sheet.getRange(column + lastRow).getValue();
One benefit of this script is that you can choose if you want to include equations that evaluate to "". If no arguments are added equations evaluating to "" will be counted, but if you specify a sheet and column they will now be counted. Also, there's a lot of flexibility if you're willing to use variations of the script.
Probably overkill, but all possible.
This works for me. Get last value of the column A in Google sheet:
=index(A:A,max(row(A:A)*(A:A<>"")))
(It also skips blank rows in between if any)
This seems like the simplest solution that I've found to retrieve the last value in an ever-expanding column:
=INDEX(A:A,COUNTA(A:A),1)
For strictly finding the last non-empty cell in a column, this should work...
=LOOKUP(2^99, A2:A)
What about this formula for getting the last value:
=index(G:G;max((G:G<>"")*row(G:G)))
And this would be a final formula for your original task:
=DAYS360(G10;index(G:G;max((G:G<>"")*row(G:G))))
Suppose that your initial date is in G10.
I went a different route. Since I know I'll be adding something into a row/column one by one, I find out the last row by first counting the fields that have data. I'll demonstrate this with a column:
=COUNT(A5:A34)
So, let's say that returned 21. A5 is 4 rows down, so I need to get the 21st position from the 4th row down. I can do this using inderect, like so:
=INDIRECT("A"&COUNT(A5:A34)+4)
It's finding the amount of rows with data, and returning me a number I'm using as an index modifier.
for a row:
=ARRAYFORMULA(INDIRECT("A"&MAX(IF(A:A<>"", ROW(A:A), ))))
for a column:
=ARRAYFORMULA(INDIRECT(ADDRESS(1, MAX(IF(1:1<>"", COLUMN(1:1), )), 4)))
This will give the contents of the last cell:
=indirect("A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>""))))
This will give the address of the last cell:
="A"&max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
This will give the row of the last cell:
=max(ARRAYFORMULA(row(a:a)*--(a:a<>"")))
Maybe you'd prefer a script. This script is way shorter than the huge one posted above by someone else:
Go to script editor and save this script:
function getLastRow(range){
while(range.length>0 && range[range.length-1][0]=='') range.pop();
return range.length;
}
One this is done you just need to enter this in a cell:
=getLastRow(A:A)
Calculate the difference between latest date in column A with the date in cell A2.
=MAX(A2:A)-A2
To find last nonempty row number (allowing blanks between them) I used below to search column A.
=ArrayFormula(IFNA(match(2,1/(A:A<>""))))
The way an amateur does it is "=CONCATENATE("A",COUNTUNIQUE(A1:A9999))", where A1 is the first cell in the column, and A9999 is farther down that column than I ever expect to have any entries. This resultant A# can be used with the INDIRECT function as needed.
Ben Collins is a Google sheets guru, he has many tips on his site for free and also offers courses. He has a free article on dynamic range names and I have used this as the basis for many of my projects.
https://www.benlcollins.com/formula-examples/dynamic-named-ranges/
Disclaimer, I have nothing to gain by referring Ben's site.
Here is a screenshot of one of my projects using dynamic ranges:
Cell D3 has this formula which was shown above except this is as an array formula:
=ArrayFormula(MAX(IF(L2s!A2:A1009<>"",ROW(2:1011))))
Cell D4 has this formula:
="L2s!A2:E"&D3
This may work:
=DAYS360(A2,INDEX(A2:A,COUNTA(A2:A)))
To pick the last in a column of arbitrary, non-empty values ignoring the header cell (A1):
=INDEX(A2:A,COUNT(A2:A))
With the introduction of LAMBDA and REDUCE functions we can now compute the row number in a single pass through the cells (Several of the solutions above filter the range twice.) and without relying on magic text or numeric values.
=lambda(rng,
REDUCE(0, rng, lambda(maxrow, cell, if(isblank(cell),maxrow,row(cell)) ) )
)(A:A)
which can be nicely packaged into a Named Function for usage like
=LAST_ROWNUM(A:A)
It works on columns with interspersed blanks, and multi-column ranges (because REDUCE iterates over the range in row-first), and partial columns (like A20:A), still returning the actual row number (not the offset within the range).
This can then be combined with Index to return the value
=DAYS360(A2, Index(A1, LAST_ROWNUM(A:A)))
(In truth, though, I suspect that the OPs date values are monotonic (even if with blanks in between), and that he could get away with
=DAYS360(A2, MAX(A2:A))
This solution is identified above as relying on the dates being "contiguous" - whether that means "no blanks" or "no missing dates" I'm not certain - but either stipulation is not necessary.)