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 am currently working in Excel but I am willing to consider solutions in (free) database software. The data I have is organized by time period, one worksheet for each period. The worksheets all have the same column structure.
Here is an example of the data from the 2017-Q1 worksheet:
| Time Period | Product ID | Prod. Category ID | Product Scale |
| 2017 - Q1 | 0012345678 | 012345 | 3 |
| 2017 - Q1 | 0023456789 | 012345 | 1 |
| 2017 - Q1 | 0033333588 | 022235 | 3 |
| 2017 - Q1 | 0123333333 | 022235 | 1 |
Here is an example of the data from the 2017-Q2 worksheet:
| Time Period | Product ID | Prod. Category ID | Product Scale |
| 2017 - Q2 | 0012345678 | 012345 | 5 |
| 2017 - Q2 | 0033333588 | 022235 | 7 |
| 2017 - Q2 | 0123333333 | 025444 | 5 |
| 2017 - Q2 | 0145555578 | 025444 | 1 |
The things that I am particularly focused on are:
Product ID 0023456789 does not appear in 2017-Q2, so the corresponding column in the master worksheet should show something (it could be blank, it could be NULL, it could be N/A, it doesn't matter as long as it is always the same.) The same thing needs to happen when a Product ID first appears in a later time period, the time periods before that should have the same N/A (or NULL, or blank, or whatever) This means that in order to form the master worksheet, I need to make a consolidated list of all of the Product IDs from all of the time periods, since not all of the Product IDs are present in every time period.
Product ID 0123333333 changed Prod. Category ID, so I need to always pull at least the Prod. Category ID column and the Product Scale column for each time period, just to be sure if it has changed or not.
I want to generate a master worksheet as follows (abbreviating column names just for space constraints here in this website):
| Product ID | 2017-Q1PCID | 2017-Q1 PS | 2017-Q2 PCID | 2017-Q2 PS |
| 0012345678 | 012345 | 3 | 012345 | 5 |
| 0023456789 | 012345 | 1 | N/A | N/A |
| 0033333588 | 022235 | 3 | 022235 | 7 |
| 0123333333 | 022235 | 1 | 025444 | 5 |
| 0145555578 | N/A | N/A | 025444 | 1 |
I have 12 different time period worksheets, so the master worksheet would need to first make a master list of unique Product IDs and then have 24 additional columns, because there are 2 columns for each time period (one column for the Product Category ID and another for the Product Scale ID, for that time period.) Furthermore, I should mention that each time period worksheet has 8,000-12,000 Product ID records, so ideally the solution should be able to handle thousands of rows fairly quickly.
TLDR : use index() match() .
Assuming the table 1 is located at "Sheet1" and the "Product ID" in the last table is located in cell A1, put this in B2 :
=IFERROR(INDEX('2017-Q1'!C:C,MATCH(A2,'2017-Q1'!B:B,0)),"")
and in C2 :
=IFERROR(INDEX('2017-Q1'!D:D,MATCH(A2,'2017-Q1'!B:B,0)),"")
and drag downwards.
Idea : 'load' the answer if the Product ID is matched in the source sheet, and put blank if no Product ID match is found.
Hope it helps. (: