I am trying to find a formula to use in Google Sheets that would combine an Index Match and a Max Date formula. Attached a screenshot for reference.
Index would be 'Phase' column C
Match would be 'ID Number' column B
With an additional step of selecting the most recent/Max date of 'Last Modified Date' column A
The end result should be the same as the example 'Current Phase' column D.
Google Sheet
//copy of Array Data
/*Current Phase is the desired end result
Last Modified Date |ID Number| |Phase| |*Current Phase|
2/26/2022 165432 Welcome Health Check
3/1/2022 165432 Adoption Health Check
3/2/2022 165432 Health Check Health Check
2/26/2022 165432 Prep Health Check
2/26/2022 165432 Close Health Check
6/21/2022 412356 Welcome Adoption
6/23/2022 412356 Adoption Adoption
2/26/2022 412356 Health Check Adoption
2/26/2022 412356 Prep Adoption
2/26/2022 412356 Close Adoption
Answer
The following formula should create the desired behaviour:
=ARRAY_CONSTRAIN(FILTER($C$2:$C,$A$2:$A=MAX(FILTER($A$2:$A,$B$2:$B=$B2))),1,1)
Note that if multiple phases are tied for most recent, this will return only the first (i.e. lowest row number).
Explanation
The inner =FILTER selects only those rows from column A where column B has the same ID as the current row being evaluated. Then, the =MAX gets the most recent date from among those rows. Next, the outer =FILTER selects only those rows from column C where column A has the most recent date among all rows with the same phase (as determined by the =MAX). Finally, if there's a tie (multiple phases are tied for most recent date), =ARRAY_CONSTRAIN returns only the first.
Functions used:
=FILTER
=MAX
=ARRAY_CONSTRAIN
Related
I am using the countifs function to add up a lot of different conditions - I need help to simplify the process so that it doesn't require so much manual formatting every time.
Here is a screenshot of a hypothetical spreadsheet. Here is a hypothetical scenario that will help convey my question. Let's say I am working with 3 clients, Macy's, abercrombie, and gap, to fill several open positions. We are reviewing multiple candidates. When I have reviewed them and approved, I select "yes" in the verdict column (E). When they have been processed, I selected yes in the F column. If I do not approve them, I select No in the column. So on and so forth.
So now I'd like to keep track of how many candidates I've approved and processed for each client for each open position. Here is my spreadsheet for that. I have used the countifs function from the previous spreadsheet, called "Review Document" as follows:
Column C, Row 2 - counting sales associate for abercrombie who have been approved and not yet processed:
=COUNTIFS(
'Review Document'!$B:$B,"abercrombie",
'Review Document'!$C:$C, "sales associate",
'Review Document'!$E:$E,"yes",
'Review Document'!$F:$F,"no")
I essentially do this for every single client, for every single role, for both column C and D. Imagine that there are ~300 rows with different companies and roles - The formula text changes every time to count if "position" and "company".
What I would like to do is now find an easy way to automatically apply a date range to all of these cells, without having to manually add a date criterion for every single formula. For example, in the first spreadsheet, there are dates in Feb, Mar, And April. Is there a way to apply a date range on my second spreadsheet so that it only counts the dates I specify? E.G. - apply some date range to ALL cells in that sheet so that it only counts if the date is 2/15/2022-3/31-2022? I would ultimately like to be able to change the date range quickly without having to manually add a date criterion to 300 cells, and then change it every time I want to see the numbers for a different date range. I was tinkering with conditional formatting but I haven't figured it out.
Thanks!
use:
=INDEX(QUERY(QUERY({A2:A, PROPER(B2:C),
IF((E2:E="yes")*(F2:F<>"yes"), 1, 0),
IF((E2:E="yes")*(F2:F= "yes"), 1, 0)},
"select Col2,Col3,sum(Col4),sum(Col5)
where Col1 is not null "&
IF(J1="",," and Col1 >= date '"&TEXT(J1, "yyyy-mm-dd")&"'")&
IF(J2="",," and Col1 <= date '"&TEXT(J2, "yyyy-mm-dd")&"'")&"
group by Col2,Col3"),
"offset 1", ))
I'm trying to create a fundraising spreadsheet that will say whether funders are currently open or closed for applications. Ideally this would be based on just the month and day, so it doesn't have to be updated every year, but I ran into problems with funding cycles that begin at the end of one year and end in the next (eg. Dec 2020 - Feb 2021). This is what I came up with to get around it, but is there a simpler way to achieve the same result?
It should return Open if today's date falls within the funding window; otherwise it should say Closed. Rolling deadlines are always Open. What I have currently returns the correct output but slows down the sheet. I'm also working with a group of volunteers with varying levels of computer skills and ideally would like to leave them with something that is easy to understand/maintain.
Here is a link to the demo sheet: https://docs.google.com/spreadsheets/d/1lHFd0f_y2PCzLSvXYM6XD1rCfdzCglsQvyfpu7xJiRQ/edit?usp=sharing
=IF(B77="rolling","Open",IF(YEAR(B77)=YEAR(C77),
IF(
AND(
DATE(YEAR(B77),MONTH(TODAY()),DAY(TODAY()))>=B77,
DATE(YEAR(C77),MONTH(TODAY()),DAY(TODAY()))<=C77),
"Open",
"Closed"),
IF(
OR(
DATE(YEAR(B77),MONTH(TODAY()),DAY(TODAY()))>=B77,
DATE(YEAR(C77),MONTH(TODAY()),DAY(TODAY()))<=C77),
"Open",
"Closed")))
I've added a new sheet ("Erik Help") to your sample spreadsheet.
I deleted your header and all of your row-by-row formulas from Column C and replaced them with the following single array formula in C1:
=ArrayFormula({"Status Today"; IF(A2:A="",,IF(ISTEXT(A2:A),"Open",IF((TODAY()>=A2:A)*(TODAY()<=B2:B),"Open","Closed")))})
This one formula will produce the header (which you can change as you like within the formula itself) and all column results.
First, an IF test is run to see if each cell in Column A is blank. If it is, then the corresponding cell in Column C is left null; otherwise the next IF test is initiated.
Since all of your dates are numbers, the second IF test simply checks to see if the value in Column A ISTEXT. If so, then we know it is "rolling," and the return value is "Open"; if not, then the final IF test is initiated.
The final IF test simply checks whether two parenthetical conditions are true (joined by the asterisk, which in array formulas, means AND). The two conditions are that TODAY() is greater-than-or-equal-to the value in Column A and that TODAY() is less-than-or-equal-to the value in Column B. If so, "Open" is returned; otherwise, "Closed" is returned.
I have the list of dates A and list of prices B.
Then manually filled search range in D and E.
I need to perform a search for number, that will be higher than G, or lower than H.
As result we show founded date in J. If no matching number is found, return E. Price (G or H), that triggered successful result in L. And founded price M, just B from date J.
Which functions can help me to implement this type of search? I tried to use INDEX, FILTER, but can't properly set the range like IF "HIGHER THAN" or "LOWER THAN" on every cell.
The main target is gradually checking each cell vertically, one by one, searching for a price, that will be higher or lower than sought. And if the number was not found, return the end date of the search.
Added the Google Sheets link, so you can test your solution and compare it.
https://docs.google.com/spreadsheets/d/1gmw7I778MGfCZENsOos4HhKB07X0wLp7fKs9hyn0a-Q/edit?usp=sharing
You can use following formulas:
for Expected result:
=IFERROR(INDEX($A$14:$A$23;MATCH(1;((D14<=$A$14:$A$23)*(E14>=$A$14:$A$23)*(((G14<=$B$14:$B$23)+(H14>=$B$14:$B$23))>0));0));E14)
for Triggered price:
=CHOOSE(1+(M14>=G14)+(M14<=H14)*2;"None";G14;H14)
for Founded price:
=IFERROR(INDEX($B$14:$B$23;MATCH(1;((D14<=$A$14:$A$23)*(E14>=$A$14:$A$23)*(((G14<=$B$14:$B$23)+(H14>=$B$14:$B$23))>0));0));ARRAYFORMULA(MAX($B$14:$B$23*(E14=$A$14:$A$23))))
See sheet "Search formula test" in your file.
To return date following formula is used
=IFERROR(IFERROR(INDEX(FILTER($A$14:$B;$A$14:$A>=D14;$A$14:$A<=E14;$B$14:$B>=G14);1;1);
INDEX(FILTER($A$14:$B;$A$14:$A>=D14;$A$14:$A<=E14;$B$14:$B<=H14);1;1));
MAX(FILTER($A$14:$B;$A$14:$A>=D14;$A$14:$A<=E14)))
Where it filters dates based on "Search from" / "Search until" data and Price check, first for "Higher than" then if no values found - for "Lower than".
Date result is returned with INDEX(filterFormula;1;1).
Last part MAX(FILTER()) returns last date in checked range in case no values were found.
For price the same formula is used but INDEX(filterFormula;1;2) returns price and last part VLOOKUPs price for last date in checked range.
However, there is a problem with using formulas as it first checks selected range for one condition and then for next one. Better solution would be script to check each cell in selection for both conditions.
I have the spreadsheet attached.
I'd like to find Client No from lookup sheet based on the date provided in the live sheet.
The same client can appear with a different client number, so i need to lookup the name and date (from live sheet) and find the corresponding client number in the lookup sheet where the date from live sheet falls between the 2 dates on the lookup sheet.
I hope this makes sense.
Any help appreciated.
Thank you
This might do what you're looking for.
=IFERROR(
QUERY(SORT(FILTER(Lookup!A$2:D,Lookup!C$2:C=B2,Lookup!A$2:A<=A2),1,0),
"SELECT * WHERE COL4 >= DATE '"&TEXT(A2,"YYYY-MM-DD")&"' LIMIT 1",0),
QUERY(SORT(FILTER(Lookup!A$2:D,Lookup!C$2:C=B2,Lookup!A$2:A<=A2),1,0),
"SELECT * LIMIT 1",0) )
I've added a tab Live-GK to your sheet, with this formula in C2. It has to be dragged down. There may be another approach where it can be done as an arrayformula, but I haven't figured that out.
Note that on my tab, I'm doing the lookups from Lookup-GK, since I could add more test data there. The above formula can be used as is, pasted into cell C2 in your Live tab.
Note that for debugging purposes, column H of my tab returns all of the columns, not just the client #, so the start and end dates can be verified.
Let me know if this helps you.
Explanation:
The inner filter selects all rows from the Lookup tab where:
i) the client name (column C in Lookup) matches the client name in column B (of Live), and,
ii) the start date (column A in Lookup) is less than or equal the client date in Live.
These records are sorted in descending date order.
Then the query selects the first record where the end date (column D in Lookup) is greater than the client date in Live.
If the Lookup record has no end date, this gives an error (empty query result) so IFERROR, a second query is run, but without the filtering by end date, selecting the one record with no end date, but an appropriate start date.
These seemed to work with the few test records I used. If there is a duplication of client dates, the first client # is returned. See client #1 and #7 in my test data. Some more error handling might be necessary if your client records might have overlapping date ranges, as CalculusWhiz asked.
Could not find a suitable solution, hence this post.
Have 2 sheets - Attendance & Payroll where attendance is filled in a pivoted manner (see sample).
For a given date range, I want to count the number of "Absent" days for the staff. The Non-Array-Formula (in Payroll column "Absent") below does that. Note: column A with staff ids is a dynamic list even though its fixed in the sample.
How this formula works:
match the payroll-staffid to the attendance column-header-staffid
using MATCH
date range given in cells payroll B1,B2
Settings!$B$13 contains the columnar range as per (2)
OFFSET (3) by MATCH to get the staff attendance
COUNTIF the number of "Absent" entries in staff attendance range - CORRECT
ArrayFormula does NOT work when the payroll-staffid "A5" is changed to "A5:A15"
Note: there is no guarantee that payroll-staffids order and attendence-header-staffids are both in same order -> that's why each staffid is mapped MATCHed and OFFSET.
=COUNTIF(OFFSET(INDIRECT(Settings!$B$13),0,MATCH(A5,Attendance!$B$1:$1,FALSE)),"Absent")
Sample sheet here.
=ArrayFormula(VLOOKUP(A5:A15, TRANSPOSE({INDIRECT(AttHeader,FALSE);MMULT(TRANSPOSE(SIGN(ROW(INDIRECT(AttUnitMatrix)))),IF(INDIRECT(AttData,FALSE)="Absent",1,0))}),2,FALSE))
See linked sample sheet in OP.
For defined names; see the Settings sheet. All ranges are computed separately to reduce the size of the formula.
1) Start operating in "block mode", ignoring order of staff-ids. "AttData" is the string representation of the data block and mapped to 1 if "Absent" else 0.
IF(INDIRECT(AttData,FALSE)="Absent",1,0)
2) This matrix is multiplied by a unit row matrix from range string "AttUnitMatrix"
TRANSPOSE(SIGN(ROW(INDIRECT(AttUnitMatrix))))
3) MMULT returns a row of "Absent" counts
4) { } is used to prepend the staff-ids to the "Absent" counts for a 2 row matrix.
{INDIRECT(AttHeader,FALSE);MMULT(...)}
5) TRANSPOSE result to be accessed by VLOOKUP (2 column matrix)
6) VLOOKUP takes care of out of order staff-ids by matching the key-staff-ids to the generated row matrix of (staff-id / absent-count) pairs.
fireworks ... pat on my back :)
In this case and others, and I've sent feedback to Google about this, a feature request "Named Formulas" akin to "Named Ranges", to be used in standard formulas. This is WITHOUT resorting to GAS. When formulas become large, this is NOT a luxury, but a NECESSITY. If readers find such a feature useful, please send feedback to Google.
eg: UnitMatrix($1) => TRANSPOSE(SIGN(ROW(INDIRECT($1))))
MMULT(UnitMatrix(AttUnitMatrix),IF(INDIRECT(AttData,FALSE)="Absent",1,0))