So I did look through a couple of existing answers, but they were all in some programing language (ie, RUBY, PHP, etc). I also managed to figure out a way to do what I want but some of my formulas felt either hard coded or verbose. So my question is, is there a cleaner way to write my formulas to achieve my goal.
What I am starting with is a simple line to calculate cost of electricity usage. It look like:
+─────────────+────────+───────+───────+─────────+──────────+───────────+───────────+────────+──────────+───────────+───────────+──────────+──────────────+─────────────+
| | | | | | KW used | | | | Rate | | | Usage | Delivery | Total Cost |
| Date | Start | Stop | KW/H | Season | On-Peak | Mid-Peak | Off-Peak | Total | On-Peak | Mid-Peak | Off-Peak | Cost | Cost | |
+─────────────+────────+───────+───────+─────────+──────────+───────────+───────────+────────+──────────+───────────+───────────+──────────+──────────────+─────────────+
| 2022/12/17 | 05:00 | 22:00 | 1.44 | Winter | 0 | 0 | 24.48 | 24.48 | 0.17 | 0.113 | 0.082 | 2.00736 | 1.141296768 | 3.15 |
+─────────────+────────+───────+───────+─────────+──────────+───────────+───────────+────────+──────────+───────────+───────────+──────────+──────────────+─────────────+
The first 4 columns are user entry fields and correspond to columns B through E. The remainder of the columns F through P are all formulas.
My seasonal time bands are contained in the following table
+─────────+──────────────+─────────────+───────────+──────────+──────────+──────────+
| Season | Start | Stop | Time | Start | Stop | Rate |
| | | | Period | (HH:mm) | (HH:mm) | ($/Kwh) |
+─────────+──────────────+─────────────+───────────+──────────+──────────+──────────+
| Summer | May 01 | October 31 | Off-Peak | 00:00 | 07:00 | 0.082 |
| | | | Mid-Peak | 07:00 | 11:00 | 0.113 |
| | | | On-Peak | 11:00 | 17:00 | 0.17 |
| | | | Mid-Peak | 17:00 | 19:00 | 0.113 |
| | | | Off-Peak | 19:00 | 24:00 | 0.082 |
+─────────+──────────────+─────────────+───────────+──────────+──────────+──────────+
| Winter | November 01 | April 30 | Off-Peak | 00:00 | 07:00 | 0.082 |
| | | | On-Peak | 07:00 | 11:00 | 0.17 |
| | | | Mid-Peak | 11:00 | 17:00 | 0.113 |
| | | | On-Peak | 17:00 | 19:00 | 0.17 |
| | | | Off-Peak | 19:00 | 24:00 | 0.082 |
+─────────+──────────────+─────────────+───────────+──────────+──────────+──────────+
Note: weekends and holidays are Off-Peak
To aid with formula reading (or so I thought) I used the following named ranges:
Season_1 =$B$75 ("Summer")
Season_1_Start =DATE(YEAR(TODAY()),5,1) ("May 01")
Season_1_End =DATE(YEAR(TODAY()),10,31) ("Oct 31")
Season_1_TimeRates =$E$75:$H$79 ("Off-Peak" to 0.82)
Season_2 =$B$80 ("Winter")
Season_2_Start =DATE(YEAR(TODAY()),11,1) ("Nov 01")
Season_2_End =DATE(YEAR(TODAY()),4,30) ("Apr 30")
Season_2_TimeRates =$E$80:$H$84 ("Off-Peak" to 0.82)
TimeRates =IF($F3="Summer",Season_1_TimeRates,Season_2_TimeRates)
Step 1
Determining the season in F4
I used the following formula in F4.
=IF(AND($B3>=DATE(YEAR($B3),MONTH(Season_1_Start),DAY(Season_1_Start)),$B3<=DATE(YEAR($B3),MONTH(Season_1_End),DAY(Season_1_End))),Season_1,Season_2)
It seamed reasonable and substituted the year of the actual entry for making date comparison. I took the approach of if its not within the range for summer, then by default it has to be winter. Part of me is thinking I should check the winter date check. If both date checks fail then toss up a check date statement or the like.
Step 2
Determine how many hours are in each category according to the table and place results in G through I. This is where things go a little ugly for me. After chasing my tail in circle for a little bit I said screw it and plunged in with some hard coding and got something that worked but looked rather ugly and lengthy to me
I started out by figuring out that each time range check had 6 possible outcomes. I boiled those outcomes down to 2 possible results: 0 or Formula.
SB = Start Before
SI = Start Inside
SA = Start After
FB = Finish Before
FI = Finish Inside
FA = Finish After
So the results were either 0 because the time range in C and D are outside of the Time range of the table. Or its some form of Finish - Start.
I couldn't figure out how to make it count the hours in the range using the title (ie On-Peak) because there were sometimes more than one entry depending on the season in F. So what I did as a working step was to create a formula that would count the hours for each of the 5 time ranges instead of the names of the time range:
To get the hours I used the following formulas for each row:
=IF(OR($D3<=INDEX(TimeRates,1,2),$C3>=INDEX(TimeRates,1,3)),0,IF($D3<=INDEX(TimeRates,1,3),$D3,INDEX(TimeRates,1,3))-IF($C3<=INDEX(TimeRates,1,2),INDEX(TimeRates,1,2),$C3))*24
=IF(OR($D3<=INDEX(TimeRates,2,2),$C3>=INDEX(TimeRates,2,3)),0,IF($D3<=INDEX(TimeRates,2,3),$D3,INDEX(TimeRates,2,3))-IF($C3<=INDEX(TimeRates,2,2),INDEX(TimeRates,2,2),$C3))*24
=IF(OR($D3<=INDEX(TimeRates,3,2),$C3>=INDEX(TimeRates,3,3)),0,IF($D3<=INDEX(TimeRates,3,3),$D3,INDEX(TimeRates,3,3))-IF($C3<=INDEX(TimeRates,3,2),INDEX(TimeRates,3,2),$C3))*24
=IF(OR($D3<=INDEX(TimeRates,4,2),$C3>=INDEX(TimeRates,4,3)),0,IF($D3<=INDEX(TimeRates,4,3),$D3,INDEX(TimeRates,4,3))-IF($C3<=INDEX(TimeRates,4,2),INDEX(TimeRates,4,2),$C3))*24
=IF(OR($D3<=INDEX(TimeRates,5,2),$C3>=INDEX(TimeRates,5,3)),0,IF($D3<=INDEX(TimeRates,5,3),$D3,INDEX(TimeRates,5,3))-IF($C3<=INDEX(TimeRates,5,2),INDEX(TimeRates,5,2),$C3))*24
I wound up hard coding the entries because ultimately these are going to wind up in the formula for G3 through I3. Otherwise I could have used the Range # column as index points.
So the next problem I had was adding ranges with the same name together. Could have used SUMIF if I was keeping the table, but in my head I could not as A) I was not keeping the table, B) This would eventually need to be in a row that could be copied down.
So I looked at what needed to be done for each season and it was not bad...IF the formula was short.
So basically need an IF statement looking for summer and follow the addition of appropriate seasonal ranges for each range type. Seems simple enough but it gave me the following formulas for G3 through I3:
=$E3*IF(OR(WEEKDAY($B3)={1,7}),0,IF($F3="Summer",IF(OR($D3<=INDEX(TimeRates,3,2),$C3>=INDEX(TimeRates,3,3)),0,IF($D3<=INDEX(TimeRates,3,3),$D3,INDEX(TimeRates,3,3))-IF($C3<=INDEX(TimeRates,3,2),INDEX(TimeRates,3,2),$C3)),IF(OR($D3<=INDEX(TimeRates,2,2),$C3>=INDEX(TimeRates,2,3)),0,IF($D3<=INDEX(TimeRates,2,3),$D3,INDEX(TimeRates,2,3))-IF($C3<=INDEX(TimeRates,2,2),INDEX(TimeRates,2,2),$C3))+IF(OR($D3<=INDEX(TimeRates,4,2),$C3>=INDEX(TimeRates,4,3)),0,IF($D3<=INDEX(TimeRates,4,3),$D3,INDEX(TimeRates,4,3))-IF($C3<=INDEX(TimeRates,4,2),INDEX(TimeRates,4,2),$C3))))*24
=$E3*IF(OR(WEEKDAY($B3)={1,7}),0,IF($F3="Summer",IF(OR($D3<=INDEX(TimeRates,2,2),$C3>=INDEX(TimeRates,2,3)),0,IF($D3<=INDEX(TimeRates,2,3),$D3,INDEX(TimeRates,2,3))-IF($C3<=INDEX(TimeRates,2,2),INDEX(TimeRates,2,2),$C3))+IF(OR($D3<=INDEX(TimeRates,4,2),$C3>=INDEX(TimeRates,4,3)),0,IF($D3<=INDEX(TimeRates,4,3),$D3,INDEX(TimeRates,4,3))-IF($C3<=INDEX(TimeRates,4,2),INDEX(TimeRates,4,2),$C3)),IF(OR($D3<=INDEX(TimeRates,3,2),$C3>=INDEX(TimeRates,3,3)),0,IF($D3<=INDEX(TimeRates,3,3),$D3,INDEX(TimeRates,3,3))-IF($C3<=INDEX(TimeRates,3,2),INDEX(TimeRates,3,2),$C3))))*24
=$E3*IF(OR(WEEKDAY($B3)={1,7}),$D3-$C3,IF(OR($D3<=INDEX(TimeRates,1,2),$C3>=INDEX(TimeRates,1,3)),0,IF($D3<=INDEX(TimeRates,1,3),$D3,INDEX(TimeRates,1,3))-IF($C3<=INDEX(TimeRates,1,2),INDEX(TimeRates,1,2),$C3))+IF(OR($D3<=INDEX(TimeRates,5,2),$C3>=INDEX(TimeRates,5,3)),0,IF($D3<=INDEX(TimeRates,5,3),$D3,INDEX(TimeRates,5,3))-IF($C3<=INDEX(TimeRates,5,2),INDEX(TimeRates,5,2),$C3)))*24
So the question is, is there way to use formulas that would allow for the tidying up of what is currently in place for cells G3 to I3 (last 3 formulas in this question) that can be copied downward?
UPDATE as requested
I am working on the table on the top, below it is my building block area for thoughts. You may recognize some of the shots above from it.
Using Excel 2013
I've spent pretty much all day trying to figure this out. I've read so many threads on here and on various other sites. This is what I'm trying to do:
I've got the total sales output. It's large and the number of items on it varies depending on the time frame it's looked at. There is a major lack in the system where I cannot get the figures by region. That information is not stored in the system. The records only store the customer's name, the product information, number of units, price, and purchase date. I want to get the total number of each item sold by region so that I can compare item popularity across regions.
There are only about 50 customers, so it is feasible for me to create a separate sheet assigning a region to the customers.
So, I have three sheets:
Sheet 1: Sales
+-----------------------------------------------------+
|Customer Name | Product | Amount | Price | Date |
-------------------------------------------------------
| Joe's Fish | RT-01 | 7 | 5.45 | 2020/5/20 |
-------------------------------------------------------
| Joe's Fish | CB-23 | 17 | 0.55 | 2020/5/20 |
-------------------------------------------------------
| Mack's Bugs | RT-01 | 4 | 4.45 | 2020/4/20 |
-------------------------------------------------------
| Joe's Fish | VX-28 | 1 | 1.20 | 2020/5/13 |
-------------------------------------------------------
| Karen's \/ | RT-01 | 9 | 3.45 | 2020/3/20 |
+-----------------------------------------------------+
Sheet 2: Regions
+----------------------+
| Customer | Region |
------------------------
| Joe's Fish | NA |
------------------------
| Mack's Bugs | NA |
------------------------
| Karen's \/ | EU |
+----------------------+
And my results are going in Sheet 3:
+----------------------+
| | NA | EU |
------------------------
| RT-01 | 11 | 9 |
+----------------------+
So looking at the data I made up for this question, I want to compare the number of RW-01's sold in North America to those sold in Europe. I can do it if I add an INDEX MATCH column to the end of the sales sheet, but I would have to do that every time I update the sales information.
Is there some way to do a SUMIFS like:
SUMIFS(Sheet1!$D:$D,Sheet1!$A:$A,INDEX(Sheet2!$B:$B,MATCH(Sheet1!#Current A#,Sheet2!$A:$A))=Sheet3!$B2,Sheet1!$B:$B,Sheet3!$A3)
?
I think it's difficult to do it with a SUMIFS because the columns you're matching have to be ranges, but you can certainly do it with a SUMPRODUCT and COUNTIFS:
=SUMPRODUCT(Sheet1!$C$2:$C$10*(Sheet1!$B$2:$B$10=$A2)*COUNTIFS(Sheet2!$A$2:$A$5,Sheet1!$A$2:$A$10,Sheet2!$B$2:$B$5,B$1))
I don't recommend using full-column references because it could be slow.
BTW I was assuming that there were no duplicates in Sheet2 for a particular combination of customer and region - if there were, you could use
=SUMPRODUCT(Sheet1!$C$2:$C$10*(Sheet1!$B$2:$B$10=$A2)*
(COUNTIFS(Sheet2!$A$2:$A$5,Sheet1!$A$2:$A$10,Sheet2!$B$2:$B$5,B$1)>0))
EDIT
It is worth using a dynamic version of the formula, though it is not elegant:
=SUM(Sheet1!$C2:INDEX(Sheet1!$C:$C,MATCH(2,1/(Sheet1!$C:$C<>"")))*(Sheet1!$B2:INDEX(Sheet1!$B:$B,MATCH(2,1/(Sheet1!$B:$B<>"")))=$A2)*
(COUNTIFS(Sheet2!$A$2:INDEX(Sheet2!$A:$A,MATCH(2,1/(Sheet2!$A:$A<>""))),Sheet1!$A2:INDEX(Sheet1!$A:$A,MATCH(2,1/(Sheet1!$A:$A<>""))),Sheet2!$B$2:INDEX(Sheet2!$B:$B,MATCH(2,1/(Sheet2!$B:$B<>""))),B$1)>0))
As you would need to make the match in memory I don't think it's feasible in Excel, you'll have to use a vba dictionary.
On the other hand, if the number of columns is fixed in your sales sheet, you can just format as table and add your index match in F.
When updating the sales data delete all lines as of line 3 and copy paste the update value. Excel will automatically apply the index match on all rows.
I'm sure i have seen this done with a short formula but i am struggling to remember how to do it.
I am trying to find where a date falls in an interval and sum another column, from that point in the interval, to the end of all specified date intervals.
So, in the image below the intervals are in columns D and E and the date to find is in cell F1 i.e. 12/12/2016.
I want to find where 12/12/2016 falls within the ranges and sum column F accordingly i.e. 12/12/2016 - 13/12/2016 (2 days) and then all intervals after will be 2 + 6+2+1+3 = 14. I am returning this result in cell J14.
I have used the idea of histograms to calculate this currently, but the formula is large and unwieldy, and i just know i have seen a similar question, somewhere on SO but can't find it, that does this with SUMPRODUCT and OFFSET only. I guess FREQUENCY could also be used.
So what i have currently is:
=SUMPRODUCT(OFFSET(F6,MATCH(TRUE,OFFSET(E6,0,0,COUNT(E6:E1048576),)>F1,0)-1,0,COUNTA(F6:F1048576),))-(F1-OFFSET(D6,MATCH(TRUE,OFFSET(E6,0,0,COUNT(E6:E1048576),)>F1,0)-1,,,))
Where, if i broke it down into stages, i find which bucket (range) has the target value:
={MATCH(TRUE,OFFSET(E6,0,0,COUNT(E6:E1048576),)>F1,0)}
I calculate the distance into the range with:
=F1-OFFSET(D6,H13-1,,,)
And i sum from this point until the end of the range with:
=SUMPRODUCT(OFFSET(F6,H13-1,0,COUNTA(F6:F1048576),))-I13
So, can anyone help me with a shorter more efficient formula please?
Data:
| Start of measurement | 12/12/2016 | |
|----------------------|------------|----------------|
| | | |
| | | |
| | | |
| From | To | Number of days |
| 13/11/2016 | 17/11/2016 | 5 |
| 10/12/2016 | 13/12/2016 | 4 |
| 03/02/2017 | 08/02/2017 | 6 |
| 06/12/2017 | 07/12/2017 | 2 |
| 09/12/2017 | 09/12/2017 | 1 |
| 12/12/2017 | 14/12/2017 | 3 |
This should work for you:
=SUMIF(E6:E11,">="&F1,F6:F11)-F1+INDEX(D6:D11,MATCH(F1,D6:D11))
How about this?
=SUMIFS(F6:F11,D6:D11,">="&F1)+MINIFS(E6:E11,E6:E11,">="&F1)-F1+1
The SUMIFS() gives the 6+2+1+3 part and the MINIFS() - F1 + 1 gives the 2 part.
Note that the ___IFS() functions are more recent and not available in older versions of Excel.