Fill down excel values between dates - excel

I have an excel sheet (called Sheet1) with rows of data that look like this:
Unit | Names | Begin_Date | End_Date
-----------------------------------
A | Jones | 1/1/2016 | 1/4/2018
A | Frank | 2/11/2018 |
B | Adam | 3/5/2011 |
C | Jane | 6/9/2012 | 7/14/2016
C | John | 7/28/2016 | 9/22/2017
C | Joe | 12/31/2017 | 1/1/2019
C | Joe | 1/2/2019 |
I am trying to get it into a format that has the units as column headers and dates as rows. The idea is that for every day between the begin and end dates, the name of the person should be in the appropriate cell. If there is a gap between the end date of one person and the begin date of the next within the same unit, the formula will list "vacant". It is assumed each unit was vacant before the first "begin date" for that unit, and blanks for end dates mean that the person still occupies that unit. Ideally the completed data set would look like this, on Sheet2:
Date | A | B | C |
-------------------------------------
3/5/2011 | Vacant | Adam | Vacant
3/6/2011 | Vacant | Adam | Vacant
...
6/9/2012 | Vacant | Adam | Jane
...
1/1/2016 | Jones | Adam | Jane
...
7/14/2016 | Jones | Adam | Jane
7/15/2016 | Jones | Adam | Vacant
7/16/2016 | Jones | Adam | Vacant
...
7/28/2016 | Jones | Adam | John
...
1/4/2018 | Jones | Adam | Joe
1/5/2018 | Vacant | Adam | Joe
etc.
The formula I have thus far populates the first values, i.e. the first person to live in the unit or, if no one, then it lists "vacant" on Sheet2. However, I am not sure how to extend it to look for the next person. I've listed all the dates in column A and all of the unique Unit names in row 1. Any help or advice would be appreciated!
=iferror(if(index(Sheet1!Names,match(1,(Sheet2!A$2=Sheet1!Begin_Date)*(Sheet2!$A3=Sheet1!End_Date),0))=Index(Sheet1!Names,match($A2,ArrayFormula(min(Sheet1!Unit=B$2,Sheet1!Begin_Date)),"Vacant",Index(Sheet1!Names,match($A2,ArrayFormula(min(Sheet1!Unit=B$2,Sheet1!Begin_Date))),Index(Sheet1!Names,match($A2,ArrayFormula(min(Sheet1!Unit=B$2,Sheet1!Begin_Date)))

This uses aggregate and is basically an array formula but without having to be entered with
CtrlShiftEnter
=IF($F2="","",IFERROR(INDEX($B:$B,AGGREGATE(15,6,ROW($A$2:$A$10)/
(($A$2:$A$10=G$1)*($F2>=$C$2:$C$10)*(($F2<=$D$2:$D$10)+($D$2:$D$10=""))),1)),"Vacant"))
Aggregate(15,6...1) woks out the minimum value of the array inside it, ignoring any error values. This array consists of the rows 2-10 divided by the conditions on the rows. The conditions are set up (as you did) using * for AND and + for OR. Where the conditions are false, this leads to a division by zero which gives an error, so only the rows which satisfy the condition are taken into account.
You can also use this
=IF($F2="","",IFERROR(INDEX($B$2:$B$10,MATCH(1,
($A$2:$A$10=G$1)*($F2>=$C$2:$C$10)*(($F2<=$D$2:$D$10)+($D$2:$D$10="")),0)),"Vacant"))
entered as an array formula.

Related

Excel formula to apply a type of true/false condition

I have two excel files; the original file contains 10K+ patient names and medical condition, the goal is to identify patients (about 400+) with special conditions so that the mail that gets sent to them is different than the rest of the list.
Original File Template:
Last Name
First Name
Diagnosis
Doe
John
Cancer
Smith
John
HIV
Smith
Jayne
Broken Arm
Rock
Dwayne
Common Cold
Foster
Jane
Common Cold
Mailing Template:
Last Name
First Name
Type of Mail
Doe
John
Smith
John
Smith
Jayne
Rock
Dwayne
Foster
Jane
In the Mailing Template, I want to classify the Type of Mail based on the diagnosis. Common diagnosis would be "LV1" and anything that I would identify as a special diagnosis, like cancer or HIV, would be "LV2"
My initial approach would be to filter the Original File by the special diagnosis and then use a True/False condition of that filtered list against the Mailing template and manually flag LV1 or LV2. But is there a method or formula that could scan the Original File to look for the keywords (eg cancer and HIV) and automatically assign the corresponding names in the Mailing List with "LV1" or "LV2"?
I believe if you can cover all the cases you're interested in, it's possible with a IF(OR) statement, for example:
Let's say B5 is the cell with the diagnosis, in your target cell (where you want "LV1" or "LV2" to appear) you will write the next formula:
=IF(OR(B5="Common*", B5="Broken*"), "LV1", "LV2")
Note the "*" in the diagnosis condition text, it will allow any cell that begins with such text to be considered true. For example, "Common*" will consider both "Common Cold" and "Common Fever" as "LV1" cases.
This solution may be problematic if you have a lot of different diagnoses to cover.
Exact Matches
If you expect to add additional condition/mailing types down the road, =XLOOKUP() would be a good option.
In column D this would match the diagnosis to a set of values in column F, and return the value in column G.
You can add as many diagnosis/mailing type values as you need without changing formulas.
In cell D2: =XLOOKUP(C2,F:F,G:G):
| | A | B | C | D | E | F | G |
|---+-----------+------------+-------------+----------------------+---+-------------+-------|
| 1 | Last Name | First Name | Diagnosis | Type of Mail | | Match | Index |
| 2 | Doe | John | Cancer | =XLOOKUP(C2,F:F,G:G) | | Cancer | LV2 |
| 3 | Smith | John | HIV | LV2 | | HIV | LV2 |
| 4 | Smith | Jayne | Broken Arm | LV1 | | Broken Arm | LV1 |
| 5 | Rock | Dwayne | Common Cold | LV1 | | Common Cold | LV1 |
| 6 | Foster | Jane | Common Cold | LV1 | | | |
Note =XLOOKUP() uses the same concept as using =INDEX(G:G, MATCH(C2, F:F, 0)) in previous versions of excel (and produces identical results).
Wildcard Matching
To support using keywords, you would then need to set the [match_mode] argument in =XLOOKUP() equal to 2, which adds the ability to use wildcards (eg * and ?).
The following would match any diagnosis where the first word matches any first wordcommon using common*.
In cell D2: =XLOOKUP(LEFT(C2, IFERROR(SEARCH(" ", C2)-1, LEN(C2)))&"*",F:F,G:G,0,2)
| | A | B | C | D | E | F | G |
|---+-----------+------------+-----------------+-------------------------------------------------------------------------+---+------------+----------------|
| 1 | Last Name | First Name | Diagnosis | Type of Mail | | Match | Index |
| 2 | Doe | John | Cancer | =XLOOKUP(LEFT(C2, IFERROR(SEARCH(" ", C2)-1, LEN(C2)))&"*",F:F,G:G,0,2) | | Cancer | LV2 |
| 3 | Smith | John | HIV | LV2 | | HIV | LV2 |
| 4 | Smith | Jayne | Broken Arm | LV1 | | Broken Arm | LV1 |
| 5 | Rock | Dwayne | Common Cold | Matches Common | | Common | Matches Common |
| 6 | Foster | Jane | Common Anything | Matches Common | | | |
You would need to adjust some in the event there is crossover in keywords or to search for multi-word keyword, but this should be a good place to start.

Find data in other row from data in another row in excel spreadsheet

I have a spreadsheet like so:
| A | B | C |
|------|---|----------------|
| Bob | | Mary is Nice |
| Mary | | Tim is happy |
| Tim | | Bob is awesome |
and I'm trying to use Excel to find the name values in column A and match the content in column C and then match the output in column B like so:
| A | B | C |
|------|----------------|----------------|
| Bob | Bob is awesome | Mary is Nice |
| Mary | Mary is Nice | Tim is happy |
| Tim | Tim is happy | Bob is awesome |
I'm not sure if there is a formula that can find, match, and sort into column B out of the box. Or if I would need to write a macro. I've been looking and the only thing I can find so far is a match based of a specific value and move it into a seperate worksheet.
I can do this with PHP/MySQL, but that's not the intended result, obviously.
Also, maybe something easier to do within Google Sheets instead?
Use INDEX/MATCH with wild cards:
=INDEX(C:C,MATCH("*"&A1&"*",C:C,0))
OR
VLOOKUP:
=VLOOKUP("*"&A1&"*",C:C,1,FALSE)

Formula to get the month of the last value

I have sales data by customer as follows:
| - | A | B | C | D | E | F | G |
|---|---------------|--------|--------|--------|--------|--------|--------|
| 1 | Customer Name | Jan-18 | Feb-18 | Mar-18 | Apr-18 | May-18 | Jun-18 |
| 2 | Mr.A | 1000 | 500 | 0 | 200 | 0 | 0 |
| 3 | Mr.B | 0 | 300 | 200 | 0 | 0 | 100 |
I need the formula to know the last sales of the respective customer booked (the name of the month)
in this case, Mr. A last order is in Apr-18 while Mr.B is in Jun-18.
I have 2,000 plus customer and sales data since Apr 2016 up to last month, it will be a huge time saving to have a formula to help.
Assuming your 'months' are dates, not Text. Courtesy #barry houdini:
=LOOKUP(2,1/(B2:G2<>0),B$1:G$1)
in Row2 and copied down to suit, formatted mmm-yy.
Ref
An alternative to using LOOKUP() as in this answer, not sure what impact it has performance-wise as both need to create an array but I would take a stab in the dark that this is less performant:
=INDEX($B$1:$G$1,,MAX((B2:G2<>0)*COLUMN(B2:G2)-1)) - Ctrl+Shift+Enter
Ofcourse this could be edited to a dual lookup on the customer too:
=INDEX($B$1:$G$1,,MAX(INDEX(($B$2:$G$3<>0)*COLUMN($B$2:$G$3)-1,MATCH("Mr.B",$A$2:$A$3,0),0)))
This doesn't require the CSE as INDEX() handles the array manipulation

Lookup rate with Index/Match with two criteria including one date range

In our Consulting business, we charge our clients according to a personal billing rate. These rates can change over time. To be able to invoice customers for any service back in time, I want to build an Excel sheet that can facilitate this process.
+--------------+------------+------------+-----------+
| Name | Begin | End | Rate |
+--------------+------------+------------+-----------+
| Paul Brown | 2016-01-01 | 2016-01-31 | $10.00 |
| Paul Brown | 2016-02-01 | 2016-03-02 | $20.00 |
| Paul Brown | 2016-03-03 | 2016-04-02 | $30.00 |
| Paul Brown | 2016-04-03 | 2016-05-03 | $40.00 |
| Anna Red | 2016-02-15 | 2016-03-16 | $100.00 |
| Anna Red | 2016-03-17 | 2016-04-16 | $127.00 |
| Anna Red | 2016-04-17 | 2016-05-17 | $145.00 |
| Martin Blue | 2016-01-01 | 2016-04-30 | $300.00 |
| Martin Blue | 2016-05-01 | 2017-02-25 | $400.00 |
| Susan Yellow | 2014-01-03 | 2014-12-29 | $10.00 |
| Susan Yellow | 2014-12-30 | 2016-08-21 | $30.00 |
| Susan Yellow | 2016-08-22 | 2016-09-21 | $50.00 |
| Susan Yellow | 2016-09-22 | 2016-10-22 | $190.00 |
| Susan Yellow | 2016-10-23 | 2016-11-22 | $200.00 |
| Susan Yellow | 2016-11-23 | 2016-12-23 | $210.00 |
+--------------+------------+------------+-----------+
In my Excel Sheet, I want to be able to enter the name of the person and any date and it should give me the correct billing rate.
So e.g. typing Susan Yellow and 08/26/16 should return $50 because it fell in this date range.
+-------------+------------+----------+
| Susan Yellow | 2016-08-26 | $50.00 |
+-------------+------------+----------+
Dates before the first billing rate should default to the first known one, and ones with no current billing rate should default to the last known one (e.g. 01/02/2018).
Normally, I would just use an Index/Match formula but my issue is that I cannot combine criteria / build a helper column because that breaks the date range function. I could define custom table arrays instead, but I do not know how long each search area is because some consultants can have quite the history and others might be short.
Anyone have a clue with what formula I can solve this in Excel/Google Sheets?
Thank you!
Edit:
SottCraner's formula is much neat and simple.
=SUMIFS(D:D,A:A,F3,B:B,"<=" & G3,C:C,">=" & G3)
This should work : {=SUM(IF(F3=$A$2:$A$16,IF((G3>=$B$2:$B$16)*(G3<=$C$2:$C$16),$D$2:$D$16,0),0))}
This will deal with the two situations where the date is not in ranges as required:
It is an array formula, so with required name in G1, and required date in H1, enter it in I1 with
Ctrl-Shift-Enter
=INDEX($D:$D,MAX(MAX(IF($A$2:$A$16=$G$1,IF($H$1>=$B$2:$B$16,ROW($C$2:$C$16)))),MATCH($G$1,$A:$A,0)))

Create Distinct ID by Group in Excel without sorting

I have an Excel column that cannot be sorted and for which I need to create a unique id by group, similar to what is below:
+--------+------+
| Name | ID |
+--------+------+
| Jim | 1 |
| Sarah | 1 |
| Tim | 1 |
| Jim | 2 |
| Rachel | 1 |
| Sarah | 2 |
| Jim | 3 |
| Sarah | 3 |
| Rachel | 2 |
| Tim | 2 |
+--------+------+
You can do this with a simple COUNTIF() and getting a little creative with your cell references:
=COUNTIF($A$1:$A1, A2) + 1
Put that in B2 (assuming your list with headers starts in A1) and then copy down.
COUNTIF() here is counting the number of times the name in the adjacent cell has appears in all of the cells above it. As you copy it down, that range will grow to include all cells between A1 and the next row up.

Resources