Below is an example of a table I have, what I am trying to do is get the value in the value column for a specific criteria based on the last occurrence (not including today's date).
So in the example below I want to find the value for the last occurrence of 'A', which is 12.
I think this can be done using an Index-Match, I just can't get my head around it though.
For example
Todays Date: 15/12/2013
---------------------------------|
|Date | Criteria | Value
|--------------------------------|
|12/11/2013 | A | 3 |
|16/11/2013 | B | 6 |
|27/11/2013 | C | 7 |
|3/12/2013 | A | 12 |
|5/12/2013 | B | 8 |
|15/12/2013 | A | |
----------------------------------
EDIT:
I would also like to add that this formula will be in a different sheet to the table above. The sheet reference in the formula also needs to be dynamic, it will draw the sheet name from another cell.
I would use this formula:
=index(C:C,max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))),1)
This formula assumes that your data is in the columns A,B,C and for every "A" value in the Criteria column, the Date is different. (If that's not the case, then this formula won't work, see below.
Let's look the formula inside from outside:
filter(A:A,B:B="A",C:C<>"") - This will result with the dates where there is an "A" in the Criteria column, and where the Value column is not empty.
arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0)) - In this step we basically find the row number in which those dates are present. The match function will search for the dates (counted in step 1). The arrayformula is needed because there will be more results.
max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))) - This will find the maximum row number (The maximum row number which contains an "A" in the Criteria column)
index(C:C,max(arrayformula(match(filter(A:A,B:B="A",C:C<>""),A:A,0))),1) - Finally, we use the INDEX function to navigate to the value, which has the maximum row number.
Now, if you want this formula to work on another sheet, you should write, instead of for example:
=index(C:C,... => =index(Data!C:C,...
Assuming that your data is in your Data worksheet.
If you want to this sheet to be dynamic, it's a bit tricky. Let's assume, that you're getting the value of the sheet name from the G1 cell. Then you should write:
=index(indirect(concatenate(G1,"!C:C")),...
This is not so pretty as you should do this for every occasion when it occurs in that long formula (described earlier). Instead you can do some pre-work.
Let's write this to your H1 cell: =concatenate(G1,"!C:C") - If in the G1 cell the sheet name is "Data", then the H1 cell should contain: Data!C:C, similarly you can add to the
H2 cell: =concatenate(G1,"!A:A"),
H3 cell: =concatenate(G1,"!B:B")
Now you can write (and that's the final answer for your question I think):
=index(indirect(H1),max(arrayformula(match(filter(indirect(H2),indirect(H3)="A",indirect(H1)<>""),indirect(H2),0))),1) - where H1,H2,H3 will reference to your Data sheet's columns.
I hope it helps.
Use the following formula to accomplish that.
Formula
=QUERY(
B1:D6, // data
"SELECT D // select
WHERE // where clause
C = 'A' AND // first criterium
D IS NOT NULL // second criterium
ORDER BY B DESC // order by
LIMIT 1, // limit
0" // headers
)
for copy/paste
=QUERY(B1:D6, "SELECT D WHERE C = 'A' AND D IS NOT NULL ORDER BY B DESC LIMIT 1", 0)
Explained
The clue to the formula is the usage of the ORDER BY and the LIMIT options within the QUERY formula. The WHERE clauses will prepare the result in the first place. Next, column B (the dates) is ordered descendingly (highest first). The LIMIT option sets the amount of rows to be displayed at 1.
Example
I've created an example file for you: Lookup value based on latest matching Criteria
I appreciate this is a slightly old question, but there is a way that I achieved the goal of filtering an array which I found both more conceptually straightforward, and also more generally applicable than the other answers I have seen, using vlookup's definitional ability to pick the first matching value in an array.
PROBLEM, RESTATED:
Assuming sample data:
A...B...C...D...E, created by a google form
A is the form entry date
B, C and D are entries from a list (let's assume they are e.g. product name, geography, and sales date)
E is the value
If a new value is entered for a particular product, in a geography, on a date, then I want this to be used in preference to the older version of that same data.
SOLUTION:
If, in your form, you create three new columns:
F Unique test
G Test cells combined
H Unique cells
Then in column G, you create a combination of all the cells you want to test on (in this case B, C and E)
cell G2: "=arrayformula(B2:B & char(9) & C2:C & char(9) & D2:D)"
The next column is a restatement of the cells you want to filter based on (in this case the date in A)
cell H2: "=arrayformula(A2:A)"
And then finally in column F we actually undertake the test:
cell F2: "=arrayformula(A2:A=vlookup(G2:G,sort({G2:H},2,false),2,false))"
Breaking that down, the vlookup (vlookup(G2:G,[RANGE],2,false) compares the data in G2, G3...Gn with a [RANGE], which is a virtual array consisting of two columns, G and H, pre-sorted according to cell H in descending order.
i.e. For any unique value of G (the combination of test data) the vlookup will return the largest value of H
The last part is a simple comparison to the original data (A2, A3... An) to return TRUE or FALSE based on whether it is the latest version of the unique value.
A final step if needed would be to create a new sheet with "=filter('Form Responses 1'!A:E,'Form Responses 1'F:F=TRUE) to recreate the data without the older versions.
Hope this helps.
Related
I have a google sheet with 2 columns, one has unique values the other one a list of several values;
I need to know if all the values of my first column are somewhere in the second one
Thank you
Column A
Column B
A
A, B, C
B
D, E, F
D
G,R, Y
I tried with =COUNTIF(FILTER(B:B,A:A=ROW(A:A)),C:C) > 0
But I can't manage to write this formulae correctly
I expected the column A to be green if the value exists in column B
With REGEXMATCH you'll be able to find the value in the next column. Try with:
=REGEXMATCH(B1,A1)*(A1<>"")
OPTION 2
Above was to checking if it appears in the corresponding row. To check the entire column with more than one value per row:
=REGEXMATCH(TEXTJOIN(",",1,B:B),A1)*(A1<>"")
I am trying to find a way to see which employees are not working between 2 dates.
Should I use vlookup, index & match, filter, query, or something else?
Sheet 1 contains employee details & start/end dates.
Sheet 2 accepts user input to select 2 dates, and it will automatically display a list of available employees who are not working.
Sheet 1 - Database/Log of all employees and days worked.
#
A
B
C
D
1
ID
Name
Start Date
End Date
2
12345
John
01/01/2021
01/08/2021
3
54321
Sarah
01/24/2021
01/29/2021
4
00731
James
02/05/2021
02/15/2021
5
00731
John
02/10/2021
02/30/2021
Sheet 2 (Row 1-2)- Manually enter in two dates.
#
A
B
1
Start Date (Manual input)
End Date (Manual input)
2
01/01/2021
01/30/2021
Sheet 2 (Row 3+)- List of all employees that are not working between the two dates entered in Sheet 2!A2:B2 (Expected Results)
#
A
B
3
ID
Name
4
00731
James
try:
=INDEX(SUBSTITUTE(UNIQUE(QUERY(""&SPLIT(FLATTEN(IF(SEQUENCE(1, MAX(D2:D-C2:C))<=D2:D-C2:C,
"♥"&A2:A&"♦"&B2:B&"♦"&C2:C+SEQUENCE(1, MAX(D2:D-C2:C), 0), )), "♦"),
"select Col1,Col2 where not Col3 matches '"&JOIN("|", "^$",
IF(SEQUENCE(1, G2-F2)<=G2-F2, F2+SEQUENCE(1, G2-F2, 0), ))&"'", 0)), "♥", ))
demo sheet
Assuming the name of your first sheet with the full data is actually Sheet1, place the following in Sheet2 cell A4:
=FILTER(Sheet1!A2:B,Sheet1!A2:A<>"",(Sheet1!C2:C>G2)+(Sheet1!D2:D<F2))
The combined either/or condition (Sheet1!C2:C>G2)+(Sheet1!D2:D<F2) in the FILTER means "either the start date is after the range date given, or the end date is before the range date given."
The other condition of Sheet1!A2:A<>"" just rules out blank rows in the original data set. It's not strictly necessary as far as the visual results are concerned; but it keeps null rows from being added to those results, which would allow you to enter data below the results in Col A and B of Sheet2 if you wanted, or to have fewer rows in Sheet2 than in Sheet1 without the formula adding more rows to accommodate null returns.
Your posted sample data is unclear. You have two different names for the same ID (i.e., 00731). And you have an "End Date" in D5 of February 30, 2021—which is not a valid date. In any case, it's unclear whether the same person/ID may turn up twice in the original data set. My formula above assumes you will not.
If your original data list may, in fact, contain duplicates, things get a bit trickier. In that case, use the following formula instead, in Sheet2 cell A4:
=UNIQUE(FILTER(A2:B,ISERROR(VLOOKUP(A2:A,FILTER(A2:A,((C2:C>=F2)*(C2:C<=G2))+((D2:D>=F2)*(D2:D<=G2))),1,FALSE))))
Here, the inner FILTER first forms a list of all people who are working during that range, and then the outer FILTER filters in a UNIQUE set of the people who are not on that inner list (i.e., trying to VLOOKUP them returns IS(an)ERROR).
I have a Googlesheet with Column A= ID like B-124992 or D-133739 and several different ID's as well, Column B= Title description. I want to Merge only the "B-" and "D-" -like ID's with their respective Title description. I'm using ArrayFormula in column C like:
= ArrayFormula(IF(ISNUMBER(FIND({"B-","D-"};'BacklogData'!A2));A2&" - "&B2;""))
The result is merging as expected but the output is distributed in column C (shows all "B-" merge results) and column D ((shows all "D-" merge results).
How can I get the results all in column C?
In C2 try:
=ArrayFormula(if(len(B2:B); if(regexmatch(A2:A; "(B-|D-)"); A2:A&"-"&B2:B;);))
This will reference the colA and output the concatenation of col A and colB if col A starts with either B- or D.
NOTE: you will have to erase all formulas you currently have in col C.
Hope that helps ?
EDIT: not sure if you are referencing another sheet, but in that case you will have to add in the sheet name, like you did in the example you gave.
I don't think you need an array formula for this - all you need is an OR condition in a standard formula:
=IF(OR(LEFT(A2,2)="B-",LEFT(A2,2)="D-"),A2&" - "&B2,"")
and copy as far down column C as you need. Since this is not an array, it will only return one result per cell which is what you want.
I am trying to conditionally format a row in Google Sheets based on the result of a QUERY operation. I can get the QUERY to return the value I want (either 0 or non-zero), however QUERY insists on returning a header row.
Since the QUERY now takes up 2 rows for every row of data, changing the format of the row based off the QUERY result starts to get weird after just a few rows.
The problem I am ultimately trying to solve in the case where I enter a list of names, and I want to compare each name to a list of "NSF Names". If a name is entered, and it exists on the NSF list, I would like to flag the entry by highlighting the row red.
Help is greatly appreciated.
Edit: Formula, as requested:
=query(A:D,"select count(A) where C contains '"&E1&"' and D contains '"&E2&"'")
A:D is the data set (A is a numeric ID, B is full name, C and D are first and last names respectively).
E1 and E2 are placeholders for the person's first and last name, but would eventually be replaced with parsing the person's name, as it's inputted on the sheet (TRIM(LEFT(" ", A2) etc...)
I can get the QUERY to return the value I want (either 0 or non-zero),
however QUERY insists on returning a header row.
There might be better ways to achieve what you want to do, but in answer to this quote:
=QUERY(A:D,"select count(A) where C contains '"&E1&"' and D contains '"&E2&"' label count(A) ''")
A query seems a long-winded approach (=countifs(C1:C7,E$1,D1:D7,E$2) might be adequate) but the label might be trimmed off it by wrapping the query in:
index(...,2)
Two sheets, one called Core Data, one called Schedule. The Schedule sheet needs to take information about deadlines from Core Data and display it concatenated in deadline-order. (Simple example with numbers and letters instead of dates and tasks given below.)
Here's what I have so far in 'Schedule' (cell B2 specifically in this case):
=JOIN(", ", FILTER('Core Data'!A2:A, 'Core Data'!B2:B=A2))
It's saying no matches are found so I assume this is a problem with the filter component of the formula. However, I've checked the help pages and can't see a problem with the condition I've created.
The formula should:
Get all the values in the given range (cells A2 downward on a 'Core Data' sheet),
Filter them so that only those with certain values are selected. (The information from 'Core Data' should only be selected if the date in the same row on column B matches the date in the cell in the A column on the Schedule sheet.)
Join all these values together and list them as a comma-delimited list.
Example (without dates, for ease):
Core Data sheet:
A | B
-----
a | 5
b | 7
c | 5
d | 3
Schedule sheet (or what it should look like):
A | B
---------
3 | d
5 | a, c
7 | b
Any idea what is going wrong with my formula or if there is an easier way to solve this problem?
The error message I was getting in the cell is:
Error: No matches are found in FILTER evaluation.
It turns out that the cell I was trying this formula on simply had no matches from the filter (no dates corresponded) but instead of returning empty it threw an error. This sounds simple but it's an annoying quirk for me that the cell didn't end up empty which made me assume the formula was at fault.
While the example in the question works you can quickly break it by adding an extra row to the 'Schedule' table with "8" as the value in the A column and the formula in B:
A | B
---------
3 | d
5 | a, c
7 | b
8 | N/A
The "8" throws an error since it isn't found in the 'Core Data'.
Conversely, on my original spreadsheet, When I tried the formula in a cell which did correspond to a noted deadline, it worked.
I found the solution here is to add an IFERROR function to the formula to deal with this.
So a formula that works for this is:
=JOIN(", ", IFERROR(FILTER('Core Data'!A:A, 'Core Data'!B:B=A5)))
One does not use the second IFERROR argument as advised in Google's own helpsheet. I tried putting in an empty array at first ({}) but this threw a different error. It seems if you miss the argument out, the JOIN knows it has nothing to work with and the cell ends up with a nice blank value.