Divide time column in time spans based on several columns - vba

So far I have managed fine using Excel's formulas, so I might not need VBA to solve this problem.
I want to create time spans in column V based on the times in column O. The time spans are: 00-05, 05-07, 07-09, 09-15, 15-18 and 18-00. Thus far I have been using the formula (example for row 25):
=IF([#Old]="","",IF([#Old]*24<5,"00-05",IF([#Old]*24<7,"05-07",IF([#Old]*24<9,"07-09",IF([#Old]*24<15,"09-15",IF([#Old]*24<18,"15-18","18-00"))))))
But I want the time spans to be conditional on column M as well, so that fx the time spans for rows 41 to 42 should still be 05-07, because they are in the batch that started in 05-07 (row 31). I have uploaded what the result should look like in the picture below. I also have a column that counts the start and end of the batch (from 1 and upwards). This might help to solve the issue, but I'm not sure how to do the expand the conditional if-statement.

Try this (this works from cell F2, since other rows are being checked - M1 and R1 in this case, which have no simple reference in a teble-ish way):
=IF([#batch]<>M1,IF([#Old]="","",IF([#Old]*24<5,"00-05",IF([#Old]*24<7,"05-07",IF([#Old]*24<9,"07-09",IF([#Old]*24<15,"09-15",IF([#Old]*24<18,"15-18","18-00")))))),V1)
Basically I added an extra if to check if it is a new batch.
IF([#batch]<>M1,(do the long calculation), (use the same value as above))

Related

Complex IF. formula in Excel

I checked various posts on IF formulas but I cannot find a way to receive the correct result in my report. I manage deliveries and I would like to calculate the delay days basing on the data from delivery report. The trick is that the delay will depend on the status of delivery, as in each case I have to consider a different date and column in Excel. These are the data:
Status of delivery:
Confirmed
Unloaded
Unloading
Not confirmed
Started
In route
Pick-up pending
Prepared
This delivery status is updated in C column in my Raw Data report. For each, I will have to calculate the delay in a different way therefore I figured that IF formula could be of use.
Below you can see the columns that contain the relevant dates for the calculations:
Status of delivery and reference date:
Confirmed - D
Unloaded - D
Unloading - D
Not confirmed - S
Started - D
In route - S
Pick-up pending - E
Prepared - S
I made this formula as below, sadly, only the first record is calculated correctly, the rest of the delays is "null".
=IF(C2="Confirmed";(TODAY()-D2);IF(C2="Unloaded";(TODAY()-D2);IF(C2="Unloading";(TODAY()-D2);IF(C2="Not confirmed";(TODAY()-S2);IF(C2="Started";(TODAY()-D2);IF(C2="In route";(TODAY()-S2);IF(C2="Pick-up pending";(TODAY()-E2);IF(C2="Prepared";(TODAY()-S2);"null"))))))))
Do you happen to have any idea where am I making the error which I don´t see? I will be grateful for any help. If it´s also relevant, I am using Excel 2016.
Breaking it down so the long line becomes readable.
=IF(C2="Confirmed";
(TODAY()-D2);
IF(C2="Unloaded";
(TODAY()-D2);
IF(C2="Unloading";
(TODAY()-D2);
IF(C2="Not confirmed";
(TODAY()-S2);
IF(C2="Started";
(TODAY()-D2);
IF(C2="In route";
(TODAY()-S2);
IF(C2="Pick-up pending";
(TODAY()-E2);
IF(C2="Prepared";
(TODAY()-S2);
"null"
)
)
)
)
)
)
)
)
At first glance, what I'm looking at is basically a vertical lookup schedule here.
So, I created these two colums. One is the text status we're looking for.
The other is the calculated date.
Single date VLOOKUp
Assuming D2, S2 and E2 are fixed fields I made the formula =TODAY() - $D$2
Then it's a simple matter of doing the VLOOKUP in the correct field.
Because we're working with a date type field we need to convert the number to text to get a meaning full date. (I used JJ in the screenshot for years because I have a dutch locale)
Then we also need to handle when VLOOKUP can't find anything, for that we use IFERROR.
=IFERROR(TEXT(VLOOKUP(F6;$A$2:$B$9;2);"MM-DD-YY");"NULL")
And now you have an easy to expand lookup table you can put anywhere, hide on a worker tab, etc.. where you can calculate your values, where you can add and remove values.
Many rows, many dates
But, say you have many rows with different statusses and dates, and you wish to know the number of days it'll take. Then this vertical lookup doesn't look so useful because it can only be used for one row.
We can still leverage VLOOKUP to make our life a bit easier
Assuming there are dates in colums D, E and S
=IFERROR(DATEDIF(TODAY();INDIRECT(ADDRESS(ROW();VLOOKUP(F2;$A$2:$B$9;2;FALSE)));"d");"NULL")
We use VLOOKUP to see which column we need to look in. We use a number here for column, not a letter.
We then use ADDRESS to get an excel address reference for the current ROW(), and the column we found via vlookup
We funnel that through INDIRECT so we can get the value from that targeted cell.
Then we get a DATEDIFference in days from offset today.
We wrap it all in an IFERROR to keep things clean.
You could use an INDEX($D2:$S2;0;VLOOKUP($F2;$A$2:$B$9;2;FALSE)) to get the same effect, as pointed out by Dirk Reichel but you have to mindful then that the index used is from the start of the matrix range. So here the matrix starts on row D. So D2 is index 1 instead of 4 it is with my original method, so you'd need to adjust the lookup table accordingly.

Excel formula not working as expected

I have a sheet that shows max values spent anywhere. So I need to find most expensive place and return it's name. Like this:
Whole sheet.
Function.
Function in text:
=IFS((A6=MAX(D2:D31)),(INDEX(C2:C31,MATCH(A6,D2:D31,0))),(A6=MAX(H2:H31)),(INDEX(G2:G31,MATCH(A6,H2:H31,0))),(A6=MAX(K2:K31)),(INDEX(K2:K31,MATCH(A6,L2:L31,0))))
Basically I need to find a word left to value, matching A6 cell.
Thanks in advance.
Ok.. Overcomplicated!
Firstly, why the three rows? it's a lot easier if you just have one long row with all the data (tell me if you actually need 3 I'll change my solution)
=LOOKUP(MAX(D2:D31);D2:D31;C2:C31)
The MAX formula will lookup the biggest value in the list, the Lookup formula will then match it to the name.
Please note: If more than one object has the maximum price, it will only return the first one. The only way I can think of to bypass that would be to build a macro.
EDIT:
Alright.. Multi Column solution is ugly and requires extra columns that you can just hide.
As you can see you'll need 2 new columns that will find the highest for each row, 2 new columns that will find the value for each of these "highest" (in this case tree and blueberries) and then your visible answer will simply be an if statement finding out which one is bigger and giving the final verdict. This can be expanded with an infinite number of columns but increases complexity.
Here are the formulas:
MAX(H2:H31)
LOOKUP(A5;H2:H31;G2:G31)
MAX(L2:L31)
LOOKUP(C5;L2:L6;K2:K6)
IF(A5>C5;B5;D5)

Writing a VBA makro to sum a nested bill of materials

Hi I have looked around extensively on the web but have not been able to find a way to calculate a nested table of totals.
My data is pictured below.
What I am looking for is a way to add up all of the sub items of an item and put that total in the cost of the original item.
so for instance the total of line 6 will be the sum of lines 7,8,9, and 10. but the total of line 2 will be the totals of lines 5,6,11, and 12 each of which needs to be seperatly subtotalled.
I have tried excels subtotal function, but it is clumsy and not a generalised solution. I may need to add or subtract components over time and have the totals calculated again.
I have tried a few if then and for loop combinations, as well as an attempt at a function that calls itsself, with very limited success.
I think I have a block in how to approach this, as well as some programming knowledge gaps, like can a function call its self, and if it does, will it automatically create an independant set of function instance variables, or will the new call overwrite the old instances variables.
Any help with methodology and knowledge would be great.
Thanks
Does this formula work for you? In a new column, say E, starting in E3 and copied down:
=SUM(IF(LEFT(B3:B$999,LEN(B3))=B3,D3:D$999,0))
Here 999 is a dummy last row --- change it to suit your situation.
Columns B and D are assumed to hold Outline and Bom Cost, respectively. The logic is: sum up all rows below (and including) the current row if and only if Outline starts like the current row's Outline. So if Outline in the current row is 1.2.3 it sums up all Bom Costs found below where Outline start with 1.2.3 (1.2.3.1, 1.2.3.2, 1.2.3.2.1, etc.).
This formula assumes that the outline is properly ordered.
It is also assumed that the Outline values are text. If they are not, the formula above will fail when Outline is a whole number (1, 2, ...). This longer formula converts whole numbers to text and should work:
=SUM(IF(LEFT(B3:B$999,LEN(B3))=IF(LEN(SUBSTITUTE(B3,".",""))<LEN(B3),B3,TEXT(B3,"0")),D3:D$999,0))
Hope this helps.

Searching column for consecutive values and returning three different values to other cells

I have a series of columns. One contains a time stamp for a data point, the next is the data point, the one following that is a conversion from decimal to binary for that data point, and the remaining columns are that binary string split into each bit. Each column has a title: "No Engine Speed", "Engine Derate", and so on.
Here's what I'd like to do, but don't have the skill with VBA/Excel to do. I'm trying to take all that information and put it into something that's more friendly to a reader.
So, for example this:
would get me this:
The description comes from the column titles, and the time range start/end would come from the first column. The error codes I'll get with an Excel IF function or some kind of VLOOKUP function based on the contents of the description column. What I need is a VBA code or set of Excel functions that will populate those description and time stamp columns for me based on the contents of those bit columns.
How I envisioning it working is as follows: each bit column is searched through, if a 1 is found and the four cells more more below it are also found to be 1s the date stamp of the first 1 and final 1 populate the Start/End times in the more readable report I'm creating. In addition to this, the column header is copied to the description field.
The reason I want to only get the time stamps if there are five or more 1s consecutively is that I want some time to pass before the state is considered to be an 'event'. A second condition I'd like to meet would be that the time stamps are reasonably close together (say, within 2 minutes of each other). This is why even though there is a '1' event in the picture I linked for "16-May-15 21:52:47" I excluded it from the second image I linked.
The numbers next to the time stamps (and the timestamps themselves) will change depending on when the user opens the workbook. Those columns are the result of a query to a database and change based on what the previous shift's start and end time were. As a side note, when copying the time stamps I know that you need to paste the cell value and not just a regular paste, otherwise you wind up copying a query array to the database. I don't know if that has any bearing on a coding solution but I thought it was worth mentioning.
I considered trying to use some type of VLOOKUP function, but what I found doesn't quite do what I want because it doesn't check if there's five events or more in succession. Any guidance or direction you all can provide would be greatly appreciated. I feel like I have an idea of how to do this but I'm new to VBA and my Excel abilities are not up to the task just yet, and my Googling isn't turning up what I need.
I hope I was clear in my explanation of what I'm trying to do, feel free to ask questions if I wasn't.
Thanks,
Dan
EDIT 1:
As Grade 'Eh' Bacon suggested, I asked an additional question related to this one that resulted in a solution better suited to my needs. It can be found here.
Since you don't seem to have a problem using helper columns, this can be done in a fairly straightforward way, given that your data is already sorted by date.
RAW DATA TAB
Add a new column (we'll call it column X) which checks to see if your cell is the first cell which starts a string of 5 date stamps, all of which being, as you say, 2 minutes apart [starting in X2, ending at an assumed X100 assuming the datestamp is column A, and the reference code in decimal is column B]:
=COUNTIFS(A2:A$100,">=" & A2 - TIMEVALUE("00:02:00"),B2:B$100,B2)
This counts how many cells below the current cell are no more than 2 minutes later, including itself, and also have the same code in column B. We will use this to check whether that cell starts a new string of 5 + identical, near-in-time, codes.
In Column Y, starting at Y2, put:
=IF(AND(OR(B2<>B1,A2 - TIMEVALUE("00:02:00")>A1),X2 >= 5), TRUE)
This will first check if either (1) the code in the current cell doesn't match the code in the previous cell; OR (2) the time of the current row is at least 2 minutes later than the last line (either way, this is a new cycle). Then we check for the AND condition of whether the current row in column X shows a match of at least 5 cells below with the same code in the same time cycle. If TRUE, then it will return TRUE. Otherwise, it will return FALSE.
Then the code in column Z returns the number of the nth "hit code" we're on for that row. ie: whether this is the 1st, 2nd, nth time that a string of 5 codes has been hit [starting in Z2; hardcode Z1 as "0", or do some other special case so the first one won't add the title of the cell above, resulting in a #VALUE! error]:
=IF(Y2,Z1+1,Z1)
This will turn Z into an ascending list of positions, repeating values whenever a NEW code has failed to be created. Now we need to grab the description of the code that this row represents.
Assume you have an ordered list of all your codes, where column 1 would be equivilent to "1000000...", column 2 would be equivilent to "01000000.." etc. Name that single-row column (or, single column row) as a Range, which I will call Code_Index.
In column AA, starting at AA2, put the following:
=INDEX(Code_Index,SEARCH("1",C2))
This checks at which character "1" appears in column C at that row, and that becomes the position we want to pull the description from (which we have placed in the named range Code_Index).
Finally, we need to add a row which checks to see when a specific block of 5+ codes ends. Say, AB:AB (I forgot about this initially, hence its a little out of order initially). In AB2 and copied down, you will check to see whether there are at least 5 rows in a row of the same thing, within the 2 minute block, and also whether the next row is the same thing, within a new 2 minute block.
=IF(AND(COUNTIFS(B$1:B2,B2,A$1:A2,">"A2 - TIMEVALUE("00:02:00")>=5,OR(B3<>B2, A3 + TIMEVALUE("00:02:00")>= A2)),MAX(Z$1:Z1),"")
RESULTS PAGE
Now assume that's all on Sheet1, and you want your 'clean' results on Sheet2.
In sheet 2, have column A be an index, which simply starts at 1 on A2 & adds 1 each row afterwards. Column B will be another 'helper' column, column C will pull the description, column D will pull the start time, and column E will pull the end time.
In column B, put the following formula, which will check which 'new' index we're on (from column Z on the last tab). Starting at B2,
=MATCH(A2,Sheet1!Z:Z,0)
This will find the first row from the raw data tab which matches the current index number on A1. Then simply use this in an index formula in each of the next 3 columns, to pull the description, start time, and end time.
In C2 (pulling the description from AA on the last tab):
=INDEX(Sheet1!AA:AA,B2)
In D2 (pulling the start time from A on the last tab)
=INDEX(Sheet1!A:A,B2)
In E2 (pulling the end time from A on the last tab, *based on the row number from the column AB index)
=INDEX(Sheet1!A:A,MATCH(A2,Sheet1!AB:AB,0))
Let me know if I've misconstrued how you want your "2 minute time blocks" set up; do some rigorous testing to make sure it acts the way you expect.

Excel: SUMing values that fall in a range (Extending SUMIFS to use ranges of Criteria)

First post - please be gentle.
I have an interesting problem where I'm trying to convert a flat data table into a cumulative total based on two ranges (to create cumulative graphs of progress). Something that should be really easy to do.
I've managed to collate the data into a summary table (effectively a pivot table but for layout and charting purposes I cant use an actual pivot table).
(I'm too new to post images - sorry its not embedded)
Screenshot
In this screenshot I'm trying to show the 3 columns on the left as a Flat data table.
Columns A & B are text values that can be 'any' text (so I cant use wild cards).
Column C is the value I'd like to SUM.
Currently I'm using an SUMIFS statement to find the sum of the "Hours" when the "Week" label matches the values in "column A" and the "Department" label matches the value in "Column B".
I would like to change this equation to find the cumulative value for each week (so in this example cell G6 would be 14 - i.e. 4 from week 1 and 10 from week 2.)
I would like to try and avoid duplicating the entire table just to find the cumulative
All I really need to be able to do in this example is replace the equation in F5:
=SUMIFS($C$2:$C$15,$B$2:$B$15,$E5,$A$2:$A$15,F$4)
with
=SUMIFS($C$2:$C$15,$B$2:$B$15,$E5,$A$2:$A$15,$F$4:F$4)
eg Sum the hours of all the weeks that have come before. Again - i cant use wild cards and I cant use pivot tables.
I imagine I need to use some Array formulae but I cant find any online resources to help me.
Any help would be appreciated.
Your formula works in Cell F5, but in G5 just make it add F5.
F5 =SUMIFS($C:$C,$B:$B,$E5,$A:$A,F$4)
G5 =SUMIFS($C:$C,$B:$B,$E5,$A:$A,G$4)+F5
H5 =SUMIFS($C:$C,$B:$B,$E5,$A:$A,H$4)+G5
I5 =SUMIFS($C:$C,$B:$B,$E5,$A:$A,I$4)+H5
Also use the entire column reference A:A if you dont know the total number of rows.
If you cant do that you could make your read data into a table and then instead of the sum_range being some defined locations, you can use Table1[Week] = Column A instead.
Hope this helps
-Scheballs