Dynamic starting point of OFFSET and SUM formula - excel

I have the following Excel spreadsheet:
A B C D E F G
1 Year 2015 2016 2017 2018 2019 2020
2 Revenue 5.000 4.000 6.000
3 Years to go back: 2
4 Sum of Periods: 10.000
In Row 1 you can find the years 2015 til 2020 and in Row 2 the corresponding revenue of each year.
In Cell C3 the user should input the number of years to go back and sum up the revenues. For example if the user puts in a 2 Excel goes back 2 years and sums up the revenue of 2017 and 2016 which is 10.000 in the case above. For this I used the following formula:
=SUM(OFFSET($E$2,0,-C3):$E$2)
This formula and the described calculation above work perfectly so far.
However, in 2018 I will have to adjust the starting point of Cell $E$2 in the formula above to Cell $F$2. Ohterwise the year 2018 will be excluded from the calculation.
=SUM(OFFSET($F$2,0,-C3):$F$2)
My question is now how can I avoid this permanent re-adjustment every year?
--> I think the solution should be a formula that identifies the first "non empty" cell within in a Row and then starts counting back the years from this cell. Somehow a combination of the SUM, OFFSET, ROW & COLUMN formula.

You may use this formula:
=SUM(INDIRECT("R2C" & (MATCH(YEAR(TODAY()),$1:$1,0) - $C$3 + 1) & ":R2C" & MATCH(YEAR(TODAY()),$1:$1,0), FALSE))
But be aware I'm assume the current year - $C$3 is within your data range.
Brief explain:
YEAR(TODAY()) - it will return the year of current date, then you don't need to re-adjust every year
MATCH(lookup_value, lookup_array, match_type) - it will find the value matched in first row, and return the index of cell
INDIRECT() - Form the result of match to a R1C1 notation, and convert the text to excel range

A simpler formula could be to use the 4th parameter of OFFSET to set the width and to calculate the starting point of the OFFSET using YEAR(TODAY()0-2016
=SUM(OFFSET($B$2,0,YEAR(TODAY())-$C$1,1,$B$3))

NON VOLATILE OPTION
Well non volatile if it were not for the TODAY() function. Replace TODAY() with a cell containing the starting year as a date. or replace Year(Today()) with a cell reference just containing the year (integer) and then it will be a non volatile option.
=SUM(INDEX($1:$1,MATCH(YEAR(TODAY()),$1:$1,0)):INDEX($1:$1,MATCH(YEAR(TODAY()),$1:$1,0)-($C$3-1))
Volatile functions recalculate every time something on the spreadsheet changes.
Non volatile functions only recalculate when something affecting them changes.
The index function returns the cell address with in the range its looking. for a 2D range you need to give row and column reference. For a 1D range, you only need to give find the position within the range.
Match finds a value within a given range.

Related

How to create different date ranges based on criteria?

I have a table with two active columns. In Column A I have all the dates between, let`s say, January 1, 2012 to December 31, 2019. In column B I have a corresponding name. For instance:
[
etc.
I want to create ranges based on criteria, like:
The trick is, this should be done by calendar year, which means that during the 8-year period, I should have 8 set of 3 columns (from / to / name), one for each calendar year. If one range covers two years (let's say, November 1, 2012 to February 1st, 2013), the last row of 2012 should read
2012-11-01 to 2012-12-31
while the first row of 2013 will read
2013-01-01 to 2013-02-01
I managed to separate the ranges, but for some reason I am not able to go further and do that for each calendar year. Is there a way to do that?
Let's assume you want to place your 8 set of 3 columns starting from column G and that your list in the range D:F has headers in row 1 and data from row 2 on. In cell G1 write down your first year (2012), in cell H1 "From", in cell I1 "To" and in cell J1 "Name".
Now in cell H2 write this formula:
=IF(IF(OR(IF(AND($E2>=DATE(G$1,1,1),$D2<=DATE(G$1,12,31)),1,0),IF(AND($D2>=DATE(G$1,1,1),$E2<=DATE(G$1,12,31)),1,0)),1,0),MAX($D2,DATE(G$1,1,1)),"")
In cell I2 write this formula:
=IF(IF(OR(IF(AND($E2>=DATE(G$1,1,1),$D2<=DATE(G$1,12,31)),1,0),IF(AND($D2>=DATE(G$1,1,1),$E2<=DATE(G$1,12,31)),1,0)),1,0),MIN($E2,DATE(G$1,12,31)),"")
In cell J2 write this formula:
=IF(AND(H2<>"",I2<>""),F2,"")
Drag the 3 of them all the way down accordingly to your need. You can then copy the G:J range and paste any time you need next to itself; just change the year in the top left cell and it should do the trick.
Report any question you have or bug you have encountered. If, according to your judgment, this answer (or any other) is the best solution to your problem you have the privilege to accept it (link).

Counting lowest values from multiple columns

I have a table and I need to count expiration for a year but I have two columns and I need to count the lowest value from them. What function would help with this. Here is a small Example
Name Expiration date Break date
Nr.1 31-Aug-2019 28-Feb-2023
Nr 2 18-Oct-2018
Nr 3 30-Sep-2018 21-Jun-2017
Nr. 4 1-Jan-2018
AS you can see there will be here:
2017 2018 2019 2020
1 2 1 0
You could use an extra "helper" column which takes the minimum between the expiration date and break date. (Accounting for the possibility of the Break date being empty)
Then your equation to find the totals for each year would just be a simple COUNTIF on that new column.
Slightly shorter version of a formula for the helper column:
=YEAR(IF(COUNT(B2:C2)=2,MIN(B2:C2),B2+C2))
with the difference that this will return a year (other than 1900) if there is a blank in the Expiration date column that is next to a populated cell in the Break date column.
For the actual counts I would choose a technique that has been deemed off topic for SO.
Solution with no helper column
Formula:
=SUMPRODUCT(--((($B:$B<$C:$C)+($C:$C=""))*($B:$B<>"")*(YEAR($B:$B)=E$1))+((($C:$C<$B:$B)+($B:$B=""))*($C:$C<>"")*(YEAR($C:$C)=E$1)))
Assumptions:
Data in columns A:C, with Expiration Date in B and Break Date in C
Year (2017,2018,2019,2010) in E1:H1
The formula can be dragged horizontally from E2 to H2.
Formula Logic (pseudo-code):
IF(OR(AND(OR(B<C,C=""),B<>"",YEAR(B)=X),AND(OR(C<B,B=""),C<>"",YEAR(C)=X))) THEN TRUE
Alternate Solution Using Table
Because the headers break the original formula, you'll need to make the column references more specific to where the data actually is. A table is the easiest way to do that.
=SUMPRODUCT(--(((Table1[Expiration Date]<Table1[Break Date])+(Table1[Break Date]=""))*(Table1[Expiration Date]<>"")*(YEAR(Table1[Expiration Date])=$E1))+(((Table1[Break Date]<Table1[Expiration Date])+(Table1[Expiration Date]=""))*(Table1[Break Date]<>"")*(YEAR(Table1[Break Date])=$E1)))
Tables don't play nice with formulas dragged horizontally, so I put the years in a column:
=SUM(IF(YEAR(IF($B$2:$B$5
Note: This is an array formula, you must paste it in the cell, then hit ctrl+shift+enter and then you can copy and paste it across your table.
The cell works if your data is in A1:C5 and you have the years you want to test across E1:H10. You could then paste the above formula in E2, and then paste accross your table.
The array formula does the following:
The first IF statement checks to see which value is lower, ColB or ColC.
The embedded IF statements then check to make sure the values are not 0. If they are 0 they return the other column, if they are not 0, they return its own non-0 value.
The YEAR function extracts the year from each date.
The last IF function preformed (but the first written in the function) tests the year against the cell above the sum. If the year matches, it returns 1, if false, 0
The SUM statement simply sums all the true values

In Excel how to count between date1 and date2 that have cells in row that contain text?

I need to choose cells in one column that are between two dates, and then based on the rows that contain those dates, choose cells in another row that also contains content.
I didn't use ISBLANK because it counts a formula yet an empty cell as a not-blank. Instead check if there is content by "*".
Here is what I came up with, but instead of returning the number of cells, instead this returns TRUE (which obviously isn't what I want).
In the formula below I am assuming:
C:C is the whole column containing DATES.
E:E is the whole column containing CONTENT.
The date range in this case is January 1, 2018 to January 31, 2018.
"*" means is there is content in the cell
=IF(AND(COUNTIFS(C:C,">="&"2018-1-1",C:C,"<="&"2018-1-31"),COUNTIF(E:E,"*"))=0,"",AND(COUNTIFS(C:C,">="&"2018-1-1",C:C,"<="&"2018-1-31"),COUNTIF(E:E,"*")))
My goal is to:
count the numbers of the cells in column E that are between the dates in column C
if the whole formula is 0, then return a blank.
See this picture of a sample excel sheet to make my intent clear:
How can I get my formula working so it does as needed?
SOLUTION
Hi all, so thanks to #girlvsdata, we have a working solution. I had to do a couple edits to her code to work for my uses, but her formula overall works perfect. Here is the solution:
To choose all cells in column E that are not blank, in between the date range of all of January (unknown end date) based on the adjacent C column if that is your date column, then the solution is:
=IF(COUNTIFS(C:C,">="&"2018-1-1",C:C,"<="&EOMONTH("2018-1-1",0),E:E,"*")=0,"",COUNTIFS(C:C,">="&"2018-1-1",C:C,"<="&EOMONTH("2018-1-1",0),E:E,"*"))
Note that "2018-1-1" is January 1 2018, and EOMONTH("2018-1-1",0) is the last valid day of January in the year 2018 (in this case, 31, but if it is different another year (e.g. for February this works for leap years too) then it will be that last day). Also it eliminates the need to calculate which is the last day or every month, as well as months that have changing end dates dependent on the year (e.g. Feb). This is important to eliminate a margin of error.
The only thing you have to do to change the month is only change e.g. -1- (Jan) to -2- for Feb, or change the year for other years. With this formula you can ignore the day part.
If the answer is 0 (no cells have any content in between the range), then the cell is blank instead of 0. (GOod for when you want to create a sheet checking future dates for future reference when more rows are added to the sheet.
It also works across different sheets, just use, say your other sheet is called "Tracker" then use Tracker!C:C and Tracker!E:E. Hope it helps!
Thank you all! :D
(Please note: My local date format is day, then month)
With the data laid out as in your example above:
A B
1 Dates |Content
------------+-------
2 1/01/2018 |
3 2/01/2018 |123456
4 3/01/2018 |
5 4/01/2018 |12398
6 5/01/2018 |484
7 6/01/2018 |1538
8 7/01/2018 |
9 8/01/2018 |
10 9/01/2018 |
11 10/01/2018 |14648
12 11/01/2018 |
13 12/01/2018 |145615
14 13/01/2018 |
And with the date range in cells D2 and E2:
Date Start Date End
2/01/2018 7/01/2018
This formula returns the count:
=COUNTIFS(A:A,">="&D2,A:A,"<="&E2,B:B,">0")
This will depend on whether your numbers in Column B are formatted as text or number. If they are formatted as numbers, the above formula will work. If they are formatted as text, replace the last section ">0" with "*".
This formula adds the conditional part of your question:
=IF(COUNTIFS(A:A,">="&D2,A:A,"<="&E2,B:B,">0")=0,"",COUNTIFS(A:A,">="&D2,A:A,"<="&E2,B:B,">0"))
(If the formula returns 0, show blank)

excel nearest due date

I have a row with dates and below it I have an empty row where I can type a "C" on any number of cells wanted or needed to get the dates above it, but I only get the first C, so what I am trying to do is actually ignore every "C" that I have wrote that correspond to past dates from today and only give me the closer one or next one from today.
For example: lets say that today is July 1 2018, so I have row 1 with a series of dates like A1=June 30 2018, B1= July 1 2018, C1=July 2 2018, D1=July 3 2018, etc and in row2 I have typed C on A2, C2 and E2 so with HLOOKUP it returnsJune 30 2018`, but I dont want that since that date is now in the past, I want to get the next and more close date after the present day so it should be C2 that is July 2 2018, and so on since the today formula will update as the days pass.
This is to get the next checking date on a project cronogram so all the dates are defined but the result as for each task should be automatically updating to stay relevant for the scehdule, so past dates just dont make any sence to be the results showed on the gantt table diagram, and yes I know it is easy as just to be deleating the "C" that correspond to past dates, but then what is the point of excel then?
I'll go out on a limb here.... you want to find the first C in row 2 after todays date which is in row 1.
MATCH will tell you which column todays date is in: MATCH(TODAY(),$1:$1,0) returns 3 as 2nd July is in C1.
INDEX will return a reference to the cell below todays date when used in conjunction with MATCH: INDEX($2:$2,,MATCH(TODAY(),$1:$1,0))
COUNTA will tell you the last column that's populated with dates in row 1: COUNTA($1:$1) returns 9 in my case as I've put dates from A1:I1.
Use INDEX again to return a reference to the last cell in row 2. INDEX($2:$2,,COUNTA($1:$1))
Stick both INDEX's together to get a range reference from todays date to the end of you data: INDEX($2:$2,,MATCH(TODAY(),$1:$1,0)):INDEX($2:$2,,COUNTA($1:$1)) - this returns an error as it's returning the reference to multiple cells.
Now find the first C in the referenced range: MATCH("C",INDEX($2:$2,,MATCH(TODAY(),$1:$1,0)):INDEX($2:$2,,COUNTA($1:$1)),0) returns 1 as I've got a C in 2nd July.
Add the column that todays date is on to the column that was returned (and minus 1 for the hell of it). SUM(-1,MATCH(TODAY(),$1:$1,0),MATCH("C",INDEX($2:$2,,MATCH(TODAY(),$1:$1,0)):INDEX($2:$2,,COUNTA($1:$1)),0)) returns the column number of the first C on or after todays date.
Use that number to return a reference to the date in row 1: =INDEX($1:$1,,SUM(-1,MATCH(TODAY(),$1:$1,0),MATCH("C",INDEX($2:$2,,MATCH(TODAY(),$1:$1,0)):INDEX($2:$2,,COUNTA($1:$1)),0))).
So your final formula is:
=INDEX($1:$1,,SUM(-1,MATCH(TODAY(),$1:$1,0),MATCH("C",INDEX($2:$2,,MATCH(TODAY(),$1:$1,0)):INDEX($2:$2,,COUNTA($1:$1)),0)))
Bit long, and I'm sure it can be done in a much shorter formula.
Edit: I also agree with Rawrplus - you could've explained it a bit better.

defining variables in excel formulas?

i have a simple table data like:
date | Jenna | Tom | Robin
01/01/12 2 5 8
02/01/12 3 4 7
(date columns starts from the first day of the year and goes all the way down to he next year.)
I have a formula getting the min. and max. values (for example for Jenna) for the month January.
I have to change the row numbers every month to get the right result.
Is it possible for me to define variables in two cells and use them in that formula without using VBA.
For example;
I will put two values in H1 and H2 cells, which are 28 and 58 respectively. And i will define E1 as start and E2 as end. And write down this formula:
=min(Cstart:Cend)
=max(Cstart:Cend)
=average(Cstart:Cend)
The first formula means to get the min value between the C28 and C58.
That way i will not have to change every formula manually on the page. I will just change the values of 2 cells and that will be enough.
I hope, I have explained.
Sure. You have to use the INDIRECT() function. INDIRECT transforms a string to a range reference.
=MIN(INDIRECT("C" & $H$1 &":C" & $H$2))

Resources