Finding the value in excel or vba - excel

Column A Column B
13-06-2013 10:50
13-06-2013 11:30
13-06-2013 12:40
14-06-2013 10:30
I need to find the values which are before a particular entry date and time.
For example, say I want to find the values in the example table above that are immediately prior to the values "13-06-2013" and "12:30".
Since 12:30 is not in column B, how do I find the values I am looking for? The answer should be 13-06-2013 and 11:30.

C7 =VLOOKUP(A7&B7,A1:C4,3,TRUE)
Here A1 = B1&C1
A B C
1 414380.451388888888889 13-06-2013 10:50
2 414380.479166666666667 13-06-2013 11:30
3 414380.527777777777778 13-06-2013 12:40
4 414390.4375 14-06-2013 10:30
5
6 Enter date Enter Time Returned Time
7 13-06-2013 12:30 11:30:00
Setting 'range_lookup' as 'True' adds the flexibility to return the closest approximate value if the exact value is not available.

I think you're looking for something like this. using index and match.
I didn't take into account the date for now. but this gives you an example.

You can compare date strings with operators like > or < etc. Concatenate your values in columns A & B, compare to the desired date/time string. In cell C1 put the following formula, and then drag down:
="13-06-2013 12:30"<A1&" "&B1
or more specifically, depending on which "12:30" you want (AM or PM), ="13-06-2013 12:30AM" or ="13-06-2013 12:30PM"
Your data in column B may default to AM unless otherwise specified/imported differently, so you may need to tweak the data or to account for this.

Here is another approach to answering your question that uses a combination of MATCH, INDEX, and array operations to provide a compact formula solution that does not rely on helper columns.
I'll assume that your two columns of dates and times are in cells A2:B5, and the two date and time values that you want to look up are in cells A9:A10. Then the following two formulas will return what you require, the latest date and time values in your data that are less than or equal to the date and time that you are looking up. (The dollar signs in the formulas are hard on the eyes, but they are important if you will need to copy the formulas to other locations; for clarity, I omit them in the discussion that follows.)
DATE: =INDEX($A$2:$B$5,MATCH(A9+A10,$A$2:$A$5+$B$2:$B$5,1),1) --> 13-06-2013
TIME: =INDEX($A$2:$B$5,MATCH(A9+A10,$A$2:$A$5+$B$2:$B$5,1),2) --> 11:30 AM
These are array formulas and need to be entered with the Control-Shift-Enter key combination. (Of course, only the bits starting with the equal (=) sign and ending with the last parenthesis need to be entered into the worksheet.)
Things to consider:
The formulas assume that your data are valid Excel date and time values. Excel date values are whole numbers that count the number of days that have elapsed since January 1, 1900; Excel time values are decimal amounts between 0 and 1 that represent the fraction of 24 hours that a particular time represents. While your example data don't display AM or PM, I assume that their underlying values do have that information.
If your values are text (having been imported from another source, for instance), you should convert them to date/time values, if lucky, using only Excel's DATEVALUE and TIMEVALUE functions; if not so lucky, using some combination of Excel's string manipulation functions as well. (The values could be kept as strings, but you would almost certainly need to massage them so they would compare correctly "alphabetically" - much easier just to deal with Excel date/time values.)
If they are not already, your dates and times will need to be sorted from smallest to largest. (Your sample looks like they are sorted, and the formulas assume as much.)
How the formulas work
The basic idea behind the formulas is two-fold: first find the row in your data that holds the latest (largest) date and time that is still less than or equal to the date and time you are looking up. That row information can then be used to fetch the final result from each column of the data range (one for date and one for time).
Since both date and time figure in to what point in time is latest, the date and time components of both the value to be looked up and the values that will be searched must be combined somehow.
This can be achieved by simply adding the dates and times together. This does nothing more than what Excel does: an Excel date/time value has an integer part (the number of days since 1/1/1900) and a decimal part (the fraction of 24 hours that a particular time represents).
What is neat here is that the adding up of the dates and times - and the lookup of the particular date and time - can be done all at once, on the fly.
Take a look at the MATCH: The cells that contain the date and time to be looked up - A9 and A10 - are added together, and then this sum is matched against the sum of the date column (A2:A5) and the time column (B2:B5) - an operation that is possible of Excel's array arithmetic capabilities. The match returns a value of 2, indicating correctly that the date and time that fill your requirements are in row 2 of the data table.
DATE/TIME MATCH: = MATCH( A9+A10, A2:A5 + B2:B5, 1 ) --> 2
The 1 that is the final argument to the MATCH function is an instruction that the match results be calculated to be less than or equal to the value to be looked. It is the default value and is often omitted, or replaced with another value (for example, using a value of 0 will produce an exact match, if there is one).
(For readability, I've removed the dollar signs that are in the full formula; these anchor a range so that it remains the same even if the formula is copied to another location.)
Having figured out the row to look in, the rest of the formula is straightforward. The INDEX function returns the value in a data range that is at the intersection of a specified row and column. So, for the date in question, the formula reduces to:
DATE FETCH: = INDEX( A2:B5, 2, 1) --> 13-06-2013
In other words, INDEX is to return the value in the second row and first column of the data range A2:B5.
The formula for the time proceeds in exactly the same fashion, with the only difference that the value is returned from the second column of the data range.

Related

Recursive Function & Looping In Excel

I am looking for some guidance in looping through a function in Excel within a table without running into a circular reference error. I've spent quite some time trying out COUNTIF, MATCH, Essentially, I need to create a function/formula for the "Desired Date" column so that it takes value from the "Original Date" column and changes the value based on the following parameter:
If a date in the Original Date column does not exist within the previous values of the Desired Date column, it will list the exact date. I've already solved this part with IF and COUNTIF functions.
If a date in the Original Date column already exits within the previous values of the "Desired Date" column, it will add +1 day(s) until all the values within the Desired Date column have unique dates.
Here's what I would like the function to do:
Row 1 contains the original date value as 8/1, since no other values exist in the desired row column, it will return 8/1.
Row 2 contains the original date value as 8/1, but since row 1 of the desired date value already contains value 8/1, it will add +1 day so it becomes 8/2.
Row 3 contains the original date value as 8/1, but since row 1 & row 2 of the desired date contain the value, it will add +2 days, so it becomes 8/3.
Row 6 contains the original date value as 8/3, but since row 3 of the desired date contain the value, it will add +1 day so it becomes 8/4.
If at any given point a date within the original date changes, the values in desired dates should change accordingly by adding a variable amount of days until all values within the Desired Dates column are unique.
Row
Original Dates
Desired Dates
1
8/1/2021
8/1/2021
2
8/1/2021
8/2/2021
3
8/1/2021
8/3/2021
4
8/12/2021
8/12/2021
5
8/12/2021
8/13/2021
6
8/3/2021
8/4/2021
7
8/4/2021
8/5/2021
8
8/3/2021
8/6/2021
9
8/13/2021
8/14/2021
I've spent well over 9 hours on this issue so any help at this point would be very much appreciated. I wouldn't mind using VBA but a function would be preferred for compatibility purposes.
Thank You!
One approach might be to generate dates starting with the date in the first column but ignoring any dates that have already been used (countif>0), then pick the lowest of these:
=LET(maxdate,$D$2,
startdate,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
MIN(IF(COUNTIF(E$1:E1,seq),maxdate,seq)))
or slightly shorter
=LET(maxdate,$D$2,
startdate,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
MIN(IF(COUNTIF(E$1:E1,seq)=0,seq)))
If you don't have Excel 365, you can use Row instead of Sequence:
=MIN(IF(COUNTIF(E$1:E1,ROW(INDEX(A:A,B2):INDEX(A:A,$D$2)))=0,ROW(INDEX(A:A,B2):INDEX(A:A,$D$2))))
entered as an array formula using CtrlShiftEnter
EDIT
If you wanted to concatenate as in your comment, you wouldn't be able to use Min (because the values wouldn't be numeric) but you could use index/match to find the first available date for a particular person:
=LET(maxdate,$D$2,
startdate,A2,
name,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
seqName,seq&name,
INDEX(seqName,MATCH(0,COUNTIF(H$1:H1,seqName),0)))
If you wanted to make the dates appear as a date rather than a number, you could wrap them in Text:
=LET(maxdate,$D$2,
startdate,A2,
name,B2,
seq,SEQUENCE(maxdate-startdate,1,startdate),
seqName,TEXT(seq,"mm/dd/yy")&name,
INDEX(seqName,MATCH(0,COUNTIF(H$1:H1,seqName),0)))

Averaging a Dynamic range in Excel

I have a list of values that looks like this. Every 30min the top row in my data is shifted down and a new latest value is inserted. I'd like to be able to take the average of all the values in the model column from 18:30 to the top most cell each day (so just the latest cell that has an 18:30 value to the top most cell)
Any help would be greatly appreciated
I've been able to find the row that contains the date I need using this:
=MATCH(DATE(YEAR(TODAY()),MONTH(TODAY()),DAY(TODAY()-1))+TIME(18,30,0),AF47:AF4595,0)
So now I just need to able to average from row 1 to the output of that formula. I've tried Index(NamedRange,1:3,0) but that didn't work
=INDEX(AF:AF,1):INDEX(AF:AF,MATCH(DATE(YEAR(TODAY()),MONTH(TODAY()),DAY(TODAY()-1))+TIME(18,30,0),AF47:AF4595,0))
Although I would change your formula just to shorten it...your formula is more readable. I would change your formula to:
MATCH(INT(TODAY())-1+TIME(18,30,0),AF:AF,0)
I was assuming your data was all in AF based on your formula. Adjust AF to match the column of your needs.
Since INDEX returns a cell address, you just need to wrap the range defined by the two indexes in an AVERAGE function:
=AVERAGE(INDEX(AF:AF,1):INDEX(AF:AF,MATCH(DATE(YEAR(TODAY()),MONTH(TODAY()),DAY(TODAY()-1))+TIME(18,30,0),AF47:AF4595,0)))
This is pretty ugly and a roundabout way of doing it, but you can first identify the last row you care about using sumproduct() and some sneakiness. And then pump that into your =Average() formula using Indirect:
=AVERAGE(INDIRECT("B1:B" & SUMPRODUCT((HOUR(A:A)=18)*(MINUTE(A:A)=30)*ROW(A:A))))
It's going to be SLOW though hitting up all of A:A so maybe narrow that range down like A1:A1000 or whatever row is likely to be the max possible row to hold that 18:30 time.
Here is another way using AVERAGEIF:
=IF(NOW()-TODAY()<5.5/24,AVERAGEIF(A:A,">" & (TODAY()-5.5/24),B:B),AVERAGEIF(A:A,">" & (TODAY()+18.5/24),B:B))
It first checks if the current time is before 18:30 then calculates the average as described (from the last 18:30 to now)
An AVERAGEIF/AVERAGEIFS can solve your problem but I see at least three problematic areas.
The 18:30:00 time you want to stop at may or may not be in the same day as the day in the top of the Prediction Area column. This means that you cannot construct a limiting date time from the day at the top of column AF and add TIME(18, 30, 0). You might need to subtract a day if the top of column AF is after midnight and before 18:30:00. A TRUE is considered 1 in a worksheet formula and FALSE is considered zero so taking the date at the top of column AF and subtracting
'Is the time of the datetime in AF47 less than 18:30:00?
(MOD(AF47, 1)<TIME(18, 30, 0))
will make the deciding date today or yesterday depending on the time in AF47.
Your program is inserting Prediction Area datetimes and Model numbers at the top of the list. Depending on the method, this can disrupt conventional formula range addressing, even when using absolute row references. While INDIRECT can be used to 'lock' a cell address by converting from a text string, INDEX is a more efficient method.
'cell address with 'absolute' row (will change with inserted rows)
AF$47
'INDIRECT method (will not change with inserted rows)
INDIRECT("AF47")
'better INDEX method (will not change with inserted rows)
INDEX(AF:AF, 47)
'range of datetimes in column AF
INDEX(AF:AF, 47):INDEX(AF:AF, 95)
Time values typically resolve to pseudo-irrational numbers (aka *repeating decimals') that cannot be relied upon in Excel's 15 significant digit floating point mathematics. For this reason you should use the 00:30:00 interval to ensure true comparity by avoiding >= and <= in favor of > and < against a time value offset by a second. IOW, 18:30:00 is not equal to either 18:29:59.999 or 18:30:00.001.
So if your datetimes (e.g. 04/25/2019 15:00) start in AF47 and are incremented every thirty minutes then the furthest cell you need to examine is AF95 (47 + 24*2).
With Prediction Area in AF46 and and Model in AG46 this is my effort.
' |<----------AG47:AG95---------->| |<----------AF47:AF95---------->| |<----AF47---->| |<----AF47---->|
=AVERAGEIFS(INDEX(AG:AG, 47):INDEX(AG:AG, 95), INDEX(AF:AF, 47):INDEX(AF:AF, 95), ">"&INT(INDEX(AF:AF, 47))+TIME(18, 29, 59)-(MOD(INDEX(AF:AF, 47), 1)<TIME(18, 30, 1)))
Truth be told, the AVERAGEIFS function does suffer significantly by using full column references so if there are no rogue values that could produce false positives above or below the ranges referenced, full column references could be used for the average_range and criteria1_range cell range references. Full column references would not be affected by row/data insertion.

Finding the last occupied cell using a formulae

This formulae "works", but it seems a bit long winded. Can anyone suggest an "easier" formulae. It returns the value in the 5th Column to a date in the 1st column which is called from a separate (and discrete) worksheet. If there is no data in the 5th column (because we haven't reached or passed that date), then the latest available data is called ($A$20, is the "calling date, on a current worksheet):-
IF(VLOOKUP($A$20,'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5)="",VLOOKUP(HLOOKUP(A20,'[FTSE100.xlsx]Meteor Step
Down Plans'!$A$18:$A$2628,MATCH(TRUE,INDEX(ISBLANK('[FTSE100.xlsx]Meteor
Step Down Plans'!$E$18:$E$2828),0,0),0)-1),'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5),VLOOKUP($A$20,'[FTSE100.xlsx]Meteor Step Down
Plans'!$A$18:$E$2828,5))
The formula is in a different workbook to the data. The formula is used to determine the last value in an array, the first column of which is a date range (01/01/2000 to 31/12/2027....say) The required data is in column 5. Entries may be up to date (i.e. the last entry was made today, therefore it will pickup todays value. The last entry may have been several days (weeks) ago, therefore it will pick up the last value in the designated column (column 5). I don't see why it can't go into a named range, as the array size is fixed. Does that help?
Thanks Ron, nearly there. That works beautifully for "missing" dates in the array. i.e. when Saturday and Sunday dates are missing, it finds the value (in column 5) of the previous Friday. However (and there is usually a "however"), if $A$20 is a date in advance of the date of the last data in the array i.e. column 5 is blank at that date, your formulae returns 0 (zero), instead of the data as at the last date that data has been entered. i.e. enter 02/04/2018 and your formulae returns 0, not the data at the last date available 28/02/2018. Is that a little more clear?? (Thank you anyway, for spending the time - I'm still trying to work out how your formulae works as it does. Is the "/" significant (other than being a "divide by" symbol, if so it's something I've never come across before? Regards...........Mike. P.S. The dates in the array (Column 1) are all in from 2016 to 2027 (excluding weekend and bank holidays), and are arranged in ascending order i.e. from 01/01/2016 to 31/12/2027
Ron - Sorry mate, buy I can't see a "second" formulae???
If I understand what you want to do correctly, (and that is hard to do since you give NO examples of your data, actual output or desired output), try:
=LOOKUP(2,1/((myDate>=A:A)*(LEN(A:A)>0)),E:E)
If it is the case that you have dates in column A and no entries in Column E, then you might have to do something like:
=LOOKUP(2,1/((myDate>=A:A)*(LEN(A:A)>0)*(LEN(E:E)>0)),E:E)
Of course, you will have to modify the cell references and named range to refer to the proper workbooks and cell.
Possibly something like:
=LOOKUP(2,1/(($A$20>='[FTSE100.xlsx]Meteor Step Down Plans'!$A$18:$E$2828)*(LEN('[FTSE100.xlsx]Meteor Step Down Plans'!$A$18:$E$2828)>0)),'[FTSE100.xlsx]Meteor Step Down Plans'!$E$18:$E$2828)
This should return the item from Column E that is either at or above the same row as myDate in Column A. If myDate does not exist in column A, it will match the nearest earlier date in Column A and return from that row in Column E.
In the second version of the formula, it also checks that there is an entry in Column E matching the column A date, and, if not, it will look above.

Excel - automatically generate list of dates, given multiple date ranges in one column

I better show you. This is how my list looks like:
And this is how I want it to be:
Basically, in the first picture I have different date ranges, for each date range I have a those two metrics, Sessions and Users and the final result should be a sort of explosion of all date ranges into single dates, considering that certain dates can be included in more than 1 date ranges (e.g. date 2017-08-12) is included in both first and second row.
And last but no least, the end date shouldn´t be counted.
Can someone help me out?
Thanks a million
A.
This is the outline of a solution:
Split each from/to date in your input table into its 2 constituent dates. You will need to use the string functions (LEFT, RIGHT and MID) to extract the numbers for the year, month and day values. These will still be strings of characters, so use the VALUE function to convert them to actual numbers and then use the DATE function to assemble them into a proper date value in Excel. (You may need to format your results using a date format, as Excel stores its dates as number of days since 01/01/1900, so 11/08/2017 is held in Excel as 42958.) Add as many helper columns as you need to your input table to achieve this.
Subtract 1 from each end date, this corrects the dates ranges so that the end date is included.
The first start date and the last end date define the range of output dates. So start your output table with the first date and in the cell below use a formula to add 1 to this date and copy the formula downwards until you get to your last possible output date.
To get the results for each possible output date, you need to find
which date ranges it belongs to. It belongs to a date range if it is
greater than or equal to the range's start date and less than or
equal to the end date. However, rather than comparing each output
date with individual start and end dates it is possible to compare
each output date with all the start and all the end dates at once. An expression such as A10>=E2:E7 generates an array of 6 elements with values
TRUE and FALSE according to whether A10 is greater than or equal to
E2, E3, E4, E5, E6 and E7 respectively. So, you can use this approach to generate an array of TRUE/FALSEvalues showing whether a particular output date is greater than or equal to (ie on or after) each range's start date. Similarly, you can get an array showing whether the same output date is less than or equal to (ie on or before) each range's end date.
The versatile SUMPRODUCT function can now be used to combine the arrays and the relevant sessions/users values from the input table to get the relevant values for the output date. For example, if the start dates are in E2:E7, the end dates in F2:F7, the sessions in B2:B7 and the output date in A10 then a sutable formula for determining the number of sessions to attribute to the output date would be =SUMPRODUCT(($A10>=$E$2:$E$7)*($A10<=$F$2:$F$7)*(B$2:B$7)). This formula could be copied to give results for all output dates and, assuming the input data for users is in C2:C7, it will also give the results for users if copied into the column adjacent to the sessions results. In this formula, the TRUE and FALSE values are effectively converted to 1 and 0, respectively.
A few points: (i) if you don't know how dates work in Excel then find out, it makes tasks such calculating the number of days between two dates or the date n days before/after a particular date extremely easy using simple arithmetic; (ii) don't confuse strings of text which look like dates with dates that can be manipulated arithmetically in Excel; (iii) I believe there are some errors in your example - 16/08/2017 is a date in two of your input ranges and should have results of (2,2) not (1,1) and 17/08/2017 is similarly in error.
I have used this approach in the illustration below and, to test its robustness, I have added an extra row of input data which has sessions different from users and which yields one date (19/08/2017) which does not match to any input range.
The output date range was generated as follows:
Cell A10: use formula =E2
Cell A11: use formula =1+A2
Cells A12, A13, ... copy formula in cell A11

SUMIFS in Excel with cell reference

I'm trying to sum the values in sheet GLTB column D where the value in column A starts with 2.21 and the value in column E is equal to the date in the cell A1. I tried this formula:
=SUMIFS(GLTB!$D$3:$D$26522,GLTB!$A$3:$A$26522,"2.21*",GLTB!$E$3:$E$26522,GLTB!$A$1)*-1
The problems:
The date in A1 doesn't appear anywhere else on the GLTB sheet, so I should get 0 for a sum, but I don't. I get some number that doesn't correspond to anything I can find.
I can make all the values in column D where column A starts with 2.21 equal to 0 (or any other number) and it has no effect on the result of the formula.
I tried this formula based on answers to other questions:
=SUMIFS(GLTB!$D$3:$D$26522,GLTB!$A$3:$A$26522,"2.21*",GLTB!$E$3:$E$26522,GLTB!"="&$A$1)*-1
This just changes the last criterion reference. However, Excel gives me a formula error response.
Any ideas?
This should get you a little closer:
=SUMIFS(GLTB!$D$3:$D$26522,GLTB!$A$3:$A$26522,">=2/21/16",GLTB!$E$3:$E$26522,GLTB!$A$1)*-1
This assumes that column A contains date values which are formatted as string. If these values are not date values, then please give some example of what cell contents in column A.
Note: I'm not clear on why you're searching for "2.21*" so I used the >= operator. That can be changed, or we could add additional criteria to the SumIfs based on your needs.
Other things to be careful of:
Ensure that column E and cell A1 both contain the same type of data (either date formatted as string, or string data representing dates. If you have inconsistent data types, the equivalence test in your Criteria2 (GLTB!$E$3:$E$26522,GLTB!$A$1) will not return the desired results.
To start with, you should format your data as table. To do this, use "Start > Format as table". This will also give you the option of giving your table a name, e.g. data. Basically this makes performing the following steps easier.
From then on, you don't need to reference with GLTB!$A3:$A26522anymore, but can use data[ColumnA].
I'm assuming you have a column ValueA with something in there that might start with 2.21, then ValueD which you want to sum and DateE which should be equal to a certain date.
The formula you are looking for is not SUMIF, but the much better SUMPRODUCT, as this allows you to check multiple conditions.
The final formula will look like this:
=SUMPRODUCT((data[DateE]=A1)*(LEFT(data[ValueA],4)="2.21")*data[ValueD])
Now what does this do. SUMPRODUCT first builds a product and then sums that up. Let's assume the following values:
A1 = 2016-03-01
DateE = 2016-03-01
ValueA = 2.213454
ValueD = 3
The formula will then do the following:
(2016-03-01=2016-03-01) is 1
("2.21" = "2.21) is 1
3 is 3
1*1*3 = 3
Now if you change the date in A1, the value of your SUMPRODUCT cell should change accordingly.
As a starter I recommend using Tables - it's much easier to read and maintain your data: Insert-->Table.
e.g.
Here I have "Table1", with the Date column formatted as a Short Date.
Name Date Quantity
Alpha 17-Mar-16 1
Beta 15-Feb-16 2
Charlie 11-Mar-16 3
Dog 11-Feb-16 4
Echo 9-Feb-16 4
Foo 6-Jan-16 5
Then in a separate row/cell, you can input a formula to sum the quantity column where the data is from 1st Feb onwards.
Here I've used a different date format, but Excel is fine with it.
Feb Onwards Total: 14 =SUMIFS(Table1[Quantity],Table1[Date],">=01-Feb-16")
Feb Only Total: 10 =SUMIFS(Table1[Quantity],Table1[Date],">=01-Feb-16", Table1[Date],"<29-Feb-16")
Try something like this:
=SUMPRODUCT((INT(GLTB!$E$3:$E$26522)=INT(GLTB!$A$1))*(ROUNDDOWN(GLTB!$A$3:$A$26522,2)=2.21)*(GLTB!$D$3:$D$26522))
If this Returns and error, then one of two things:
your dates are not true dates but text that look like dates.
your have errors in your cells in some of the columns.

Resources