Array formula with if conditions and substraction - excel

I am searching for a formula solution that would summarize hours based on two conditions (date - column a, activity - column b). More precise, I want to summarize hours of sleep each day with array formula that would include whole column range.
The data looks like this:
When I define exact range the formula works.
{=IF(A2:A10=I$6;IF(B2:B10="Sleep";(D2:D10)-(C2:C10);0);0)}
But when I try to include whole column it returns 0.
{=IF(A:A=I$6;IF(B:B="Sleep";(D:D)-(C:C);0);0)}
Thank you!

You can use the entire column using an IF statement inside SUM or SUMPRODUCT. It ensures the time differences is only carried out on valid rows of the input data:
=SUM(IF(($A:$A=F1) * ($B:$B="Sleep"), ($D:$D + ($C:$C > $D:$D) - $C:$C),0))
Then just extend the formula to the right (notice the $-notation).
Using SUM or SUMPRODUCT directly produces an error (#VALUE!), for example:
=SUM(($A:$A=F1) * ($B:$B="Sleep") * ($D:$D + ($C:$C > $D:$D) - $C:$C))
because it doesn't filter first for valid rows where the subtract doesn't produce an error.
Here is the output:
Note: You need to try for your excel version, for O365 it works, but it has to be tested for an older version.
The calculation for time differences (the parenthesis is required):
$D:$D + ($C:$C > $D:$D) - $C:$C
Ensures that when the end date represents a time from the next day as it is in row 5, it adds 1, to consider the next day. You can achieve the same using another IF (longer but may be easier to understand):
IF($D:$D > $C:$C, $D:$D - $C:$C, (1+$D:$D) - $C:$C)
Performance: Please keep in mind #JosWoolley comments below, about performance. Usually, indicating the entire column in the formula instead of a specific range, forces Excel to check all rows (current maximum: 1,048,576). No significant impact for invoking the formula just one time, but for multiple invocations, it will be a significant impact on performance or Excel can even not respond.

Take a look at this link for some little-known insight from Microsoft. Microsoft deliberately prevents the use of entire columns in some formulas that internally use arrays:
Excel Limitations
In particular, see this paragraph.

If you designate your data as an Excel table then you could use structured referencing, as in the example below
=SUMPRODUCT(((Schedule[End]+(Schedule[Start]>Schedule[End]))-Schedule[Start])*(Schedule[Activity]="Sleep")*(Schedule[Date]=I6))
but you should recognise that the organisation of your data does not permit the (by-date) analysis you require, e.g. most of the sleep attributable to Jan 22nd is properly attributable to Jan 23rd but that can't be reflected in the summary, as you have treated the end time on Jan 22nd as being 16 hours before the start time...
(cells I7:K7 have the custom number format [hh]:mm)

Related

Auto populate a table based from datas from another table

this is the another version of my first question and I hope I can best explain my problem this time.
From the Table 1, I want to auto populate Table 2 based on this conditions and criteria (below)
From the example, I basically have 3 initial criteria, ON CALL, AVAILABLE, and BREAK
Now for the conditions, I want all Agents from status ON CALL, AVAILABLE, BREAK from Table 1 to be populated on Table 2 (optional: If possible, I wanted only to show agents that HAS a duration of 4 minutes and above from each status). My problem is I always refresh TABLE 1 so I can get an updated data. My goal here is to monitor our agents their current Status and Running Duration, and from that I only need to check on the table 2 so I would see right away who has the highest running duration from each status to be called out.
I only tried MAXIFS function but my problem with it, I can only show 1 result from each status.
What I wanted is to fully populate Table 2 from the data on Table 1. If this is possible with ROW function that would be great, because what I really wanted is a clean Table, and it should only load data if the criteria is met.
Thank you
Something you may be interested in doing is utilizing HSTACK. I am not sure how you are currently obtaining the Agents name in the adjacent column to the results but this would populate both the Agent along with the Duration.
=HSTACK(INDEX(A:C,MATCH(SORT(FILTER(C:C,(C:C>=TIMEVALUE("00:04:00"))*(B:B=H2),""),1,1),C:C,0),1),TEXT(SORT(FILTER(C:C,(C:C>=TIMEVALUE("00:04:00"))*(B:B=H2),""),1,1),"[h]:mm:ss"))
This formula checks Table 1 for any Agent with the status referenced in H2 (Available) that also has a time greater than or equal to 4 mins. It then sorts the results in ascending order and populates the Agent Name that is associated with it. It is dynamic and will produce a table like the following:
Just update the formula to check for "On Call" and "BreaK" as desired for the other two.
UPDATE:
As for conditional formatting, this is utilizing the custom formula posted in the comments. If the formatting of the times are of [h]:mm:ss then you would be looking to do something like this. Notice the 2 cells are highlighted for being between 4 mins and 5 mins.
This is an array solution that spill all the results at once. We use a user LAMBDA function GET to avoid repetition of the same calculation using as input parameter the status (s). The formula works for durations in time format or in text format with a minor modification. On cell E2 put the following formula for durations in time format:
=LET(GET, LAMBDA(s, FILTER(HSTACK(A:A, C:C), (B:B=s)
* IFERROR(C:C >= TIME(0,4,0), FALSE))),
IFERROR(HSTACK(GET("ON CALL"), GET("Available"), GET("Break")),""))
Here is the output:
For durations as text in hh:mm:ss format just replace: C:C >= TIME(0,4,0) with TIMEVALUE(C:C) >= TIME(0,4,0).
The GET function is reused to generate the result for each status. The last IFERROR call is used to remove #N/A values generated by HSTACK when the column doesn't have the maximum number of rows of the output.
The first IFERROR is used to treat the case when the value is not numeric, such has the header. This is because we are using the entire column as input range. Using entire columns produce more concise formulas with less maintenance effort, but it is less efficient, unless you have a good reason to have an open range. If you want to use a specific range instead for the data of the table, then you can remove it and update the ranges accordingly.

Excel advanced vlookups for a schedule comparison

I wondering if anyone will be able to help me sort the formula below out:
=IFERROR((VLOOKUP($D96,August!$C:$P,F$78,FALSE))-(VLOOKUP($D96,July!$C:$O,(F$78+1),FALSE)),IF(U96="NEW PART",(VLOOKUP($D96,July!$C:$O,(F$78+1),FALSE)),IF(V96="NEW PART",(VLOOKUP($D96,August!$C:$O,(F$78),FALSE)),"")))
Originally the formula was
=IFERROR((VLOOKUP($D95,August!$C:$P,F$78,FALSE))-(VLOOKUP($D95,July!$C:$O,(F$78+1),FALSE)),"BLANK")
However rather than returning "BLANK" if either sheet does not include that part number I would like the formula to return the figure on the one sheet they appear on. Columns U and V highlight weather the product number is on each sheet. These figures would be + figures if they appear in august and minus figures if they appear in July.
Link/screenshot refer:
In short - replace final 'FALSE' with an additional iferror(Aug,-July)
(see revision at end, following comments / feedback re sound applications/customizing soln as required)..
Formula - per OP request
=IFERROR(VLOOKUP(H4,B4:C14,2,FALSE)-VLOOKUP(H4,E4:F14,2,FALSE),IFERROR(VLOOKUP(H4,B4:C14,2,FALSE),-VLOOKUP(H4,E4:F14,2,FALSE)))
Improvised version
(pre-requisite: Office 365 compatible version of Excel)
=LET(A,INDEX(C4:C14,MATCH(H4#,B4:B14,0)),B,INDEX(F4:F14,MATCH(H4#,E4:E14,0)),IFERROR(A-B,IFERROR(A,-B)))
Motive
Arguments in favour of this version include:
OP version: 127 chars (vs 104) i.e. ~20-25% length reduction on this basis
Audit/review - arguably easier given let function
Flexibility: unless you plan to take advantage of vlookup 'approximate matching' (using True flag instead of False), Index more robust in that it can handle forward and backward references in relation to the indexed column (i.e. with vlookup, index has to lie to left of the column comprising the cell to be returned)
The usual benefits assoc. with 'spill' ranges (i.e. potential for 'dynamic' range feature and automatic calc. from single cell entry)
REVISION:
The following screenshot should shed some light on references/ranges you may wish to alter for 1st formula in present response to operate as you intend within your workbook (corresponding ranges are colour-coded with clear visual link between each)...
So to apply in your case, you'd need to replace shaded/boxed ranges/references in my proposal with those you're using (as indicated - i.e. replace by H4 with your $D95 etc,..."
JB: replace final 'FALSE' with an additional iferror(Aug,-July)
This concept is clearly delineated within screenshot above.
OP: "I tried and just got N/A"
As link in opening line provides evidence of two alternative solns. working error-free, presume 'n/a' result of incorrect application...

Countif dates in two table columns are different

I have a bit of an issue. Why else would I be here? ;)
I have a table (table1) and in this table I have two columns that I would like to count if the dates differ (Task due date and Task complete date). What I want to do is calculate the task that are past due or delivered on time. (Yes I am aware that free templates are available, this is mainly to learn more on working with Excel)
In my calculation sheet, I want to count:
The amount of Task complete dates that are prior or equal (<=) then the Task due date
The amount of Task complete dates that are past (>) the Task due date
I think that the issue lays in in the COUNTIF statement because it seems to only accept one array (the count array) after that comes the criteria which does not seem to handle arrays.
I also tried =SUMPRODUCT(COUNTIF(Table1[Task complete date];"<=" & Table1[Task due date])) But this gives me a value of 8 (while I have two possible matches)
According to This tutorial, I should get a return value of 1 and 0 but looking at the calculation steps I get: SUMPRODUCT({1;1;2;2;2;0;0;0;0;0}) This would off course be where the value of 8 comes from.
Is there any way around this? Do I need to add in some kind of if statement or some kind of pre-check?
Here is a link to the excel document with some test data
Oh and by the way: the comma delimitter in my country is a ; and not an actual comma. That is why there are semicolumns where some of you would expect a comma.
Any help would be greatly appreciated. Thank you all in advance.
Tinus
You could add a date check to column M in your "Project tasks" table: =IF(COUNTBLANK(F4)+COUNTBLANK(K4)=0,IF([#[Task due date]]<=[#[Task complete date]],"On time","Past Due"),"").
Then you could use =COUNTIF(Table1[Date check],[#[on time/past due]]) in column K of your "Data" sheet.
P.S. If you need a translation of the given function you may check https://de.excel-translator.de/
The reason that you are getting values above 1 is that your COUNTIF is actually comparing each value in Table1[Task complete date] to each value in Table1[Task due date]. e.g. if the [Task complete date] is 1 Jan, it will count how many [Task due date] values are greater than or equal to 1 Jan, so that could be 2, for example. Then it moves to the next value in [Task complete date] and does the same.
So you would need to do:
The amount of Task complete dates that are prior or equal (<=) then the Task due date
=SUM(--(Table1[Task complete date]<=Table1[Task due date]))
The amount of Task complete dates that are past (>) the Task due date
=SUM(--(Table1[Task complete date]>Table1[Task due date]))
Additional Notes
For versions of Excel before 2019 or Excel 365, the formulas above must be entered as array formulas, so you have to enter them with CTRL+SHIFT+ENTER. For your Google Sheets version, these must also be array formulas, but you will also need some additional filtering to get it to ignore blank cells. You could do:
=ArrayFormula(SUM((K4:K24<=F4:F24)*(K4:K24>0)))
and
=ArrayFormula(SUM((K4:K24>F4:F24)*(K4:K24>0)))

Excel - Combine data from multiple tables dynamically

I would like to combine three different tables in Excel. I am struggling with the fact that the tables can vary in length.
For example:
What I would like to achieve is all the tables' data in one table without empty spaces. So first the two entries from the first table then the three entries from the second table and lastly the entry from the third table. But the amount of rows in each table can vary.
How can I do this dynamically so when the amount of entries in the tables change it can handle this? I'm using Mac with Office365. Thanks!
EDIT:
Output with Ron Rosenfeld's solution, the range of the list goes down from cell 5 - cell 103. Could this be reduced to 5 - 15?:
If you have Excel 2019 or Office 365, with the FILTERXML and TEXTJOIN functions, you can use:
=FILTERXML("<t><s>" & TEXTJOIN("</s><s>",TRUE,Table1,Table2, Table3) & "</s></t>","//s[.!=0]")
If those zero's are really blanks, you can omit [.!=0] from the xPath argument, but it won't hurt to leave it there
Edit:
With MAC versions of Office 365 that do not have the FILTERXML function, I believe the following will work:
=LET(
a,299,
x,IF(SEQUENCE(99,,0)=0,1,SEQUENCE(99,,0)*a),
y,TEXTJOIN(REPT(" ",a),TRUE,Table19,Table20,Table21),
z, TRIM(MID(y,x,a)),FILTER(z,(z<>"0")*(z<>""))
)
Note the a parameter in the above function
Because of how the splitting algorithm works, the sequence for each cell will not always start at the beginning of a string.
Hence, if there are enough letters in the various strings, the start number may eventually get offset enough to cause a split in the wrong location
One fix is to use an arbitrarily large number of space's to insert.
99 is frequently large enough, but not for this data set.
299 seems to be large enough for the data set as shown in your actual data.
I believe the minimum number should be the sum of the lengths of all the characters in the original tables (including the 0's) plus one (1). But not sure of this.
You can certainly adjust it as needed
If the number becomes too large, you could run into the 32,767 character limitation. If that happened, an error message would occur.
So, if you wanted to compute a, dynamically, you could try something like:
=LET(
a,SUM(LEN(Table19[Column1]),LEN(Table20[Column1]),LEN(Table21[Column1]))+1,
x,IF(SEQUENCE(99,,0)=0,1,SEQUENCE(99,,0)*a),
y,TEXTJOIN(REPT(" ",a),TRUE,Table19,Table20,Table21),
z, TRIM(MID(y,x,a)),FILTER(z,(z<>"0")*(z<>""))
)
but no guarantees.
Assuming the data is in A:C, and empty cell is blank (not 0).
In E1 put :
=IF(ROW()>COUNTA(A:C),"",
INDEX(A:C,
IF(ROW()<=COUNTA(A:A),ROW(),IF(ROW()<=COUNTA(A:B),ROW()-COUNTA(A:A),ROW()-COUNTA(A:B))),
IF(ROW()<=COUNTA(A:A),1,IF(ROW()<=COUNTA(A:B),2,3)))
)
Idea : use row() to guide in selection in index. counta() is used guide converting 'row()' to usable index numbers. Also make the output cell blank "" for row() > counta(a:c).
Please share if it works/not.

How do I calculate a Sum based on multiple If's in Excel?

Background is that I'm making a budget spreadsheet. I have different bills due on different days. (ie. bill due on Monday and bill due on the 10th)
I want a function that will place the appropriate amount of money going in/out in column D and the description of why the money is going in/out in column E.
Currently I have two different formulas that I created (probably incorrectly).
Formula for Column E: (Already is in the document and seems to work fine other than that fact that I cant add additional text to the cell)
=IF(DAY(C36)=7," Amy Pay","")&IF(DAY(C36)=22," Amy Pay","")&IF(DAY(C36)=8," Family Bills","")&IF(DAY(C36)=6," Dollar Shave Club","")&IF(DAY(C36)=2," Amy Cap One VISA","")&IF(DAY(C36)=3," Chase VISA","")&IF(DAY(C36)=8," Being Smart","")&IF(DAY(C36)=17," Gym","")&IF(DAY(C36)=11," Netflix","")&IF(DAY(C36)=19," Cap One MC","")&IF(DAY(C36)=29," CenturyLink","")&IF(DAY(C36)=6," Haley Cap One Visa","")&IF(DAY(C36)=10," SRP","")&IF(DAY(C36)=23, "Car Payment","")&IF(DAY(C36)=30, "Rent","")&IF((B36)="Mon"," Monday","")&IF((B36)="Fri"," Friday","")&IF((B36)="Fri"," Haley Pay","")
Formula for Column D: (not in the column yet, as it doesn't work how I want)
=IF(DAY(B40)=7,"1474.22","")&IF(DAY(B40)=22,"1474.22","")&IF(DAY(B40)=8,"-100","")&IF(DAY(B40)=6,"-9","")&IF(DAY(B40)=2,"-100","")&IF(DAY(B40)=3,"-100","")&IF(DAY(B40)=8,"-400","")&IF(DAY(B40)=17,"-20.05","")&IF(DAY(B40)=11,"-8.63","")&IF(DAY(B40)=19,"-450","")&IF(DAY(B40)=29,"-50","")&IF(DAY(B40)=6,"-150","")&IF(DAY(B40)=10,"-200","")&IF(DAY(B40)=23,"-325","")&IF(DAY(B40)=30,"-500","")&IF((A40)="Mon","-125","")&IF((A40)="Fri","-325","")&IF((A40)="Fri","400","")
http://imgur.com/IBINweh
      
The problem is that in column D, rather than providing a sum of the numbers, it lists the numbers in the column.
http://imgur.com/rPDS5h2
      
I had a suggestion to add =SUM( in front of the IF( function, but when I do, #VALUE! is what results in the field. Using this formula: (view image by changing appended text to /CVs0f1v )
=SUM(IF(DAY(B40)=7,"1474.22","")&IF(DAY(B40)=22,"1474.22","")&IF(DAY(B40)=8,"-100","")&IF(DAY(B40)=6,"-9","")&IF(DAY(B40)=2,"-100","")&IF(DAY(B40)=3,"-100","")&IF(DAY(B40)=8,"-400","")&IF(DAY(B40)=17,"-20.05","")&IF(DAY(B40)=11,"-8.63","")&IF(DAY(B40)=19,"-450","")&IF(DAY(B40)=29,"-50","")&IF(DAY(B40)=6,"-150","")&IF(DAY(B40)=10,"-200","")&IF(DAY(B40)=23,"-325","")&IF(DAY(B40)=30,"-500","")&IF((A40)="Mon","-125","")&IF((A40)="Fri","-325","")&IF((A40)="Fri","400",""))
Any ideas on how I can get all the to populate and sum appropriately?
Forgive my Non Excel Guru knowledge - trying to learn. :D
-Amy
If you take all of the options from your first working formula and change the method retrieving them, you will have a much more versatile worksheet that can easily accept new additions and schedule modifications.
    
In a couple of unused columns to the right, pit in the day-of-month and the action that occurs. I'm using columns Y & Z. You have two events occurring on the 6th so I put them together.
In a couple of other unused columns use the day-of-the-week and associated text.; I've used columns V & W. The default for Sunday is 1.
In E36 use this formula,      =TRIM(IFERROR(VLOOKUP(DAY(C36),$Y:$Z, 2, FALSE), "")&" "&IFERROR(VLOOKUP(WEEKDAY(C36),$V:$W, 2, FALSE), "")) 
Fill down as necessary.
If you want the day-of-the-week in column B, use =C36 and use a custom number format of ddd or dddd.
References:
  VLOOKUP function  WEEKDAY function
You are concatenating text strings that look like numbers. You probably want to be adding real numbers:
=SUM(IF(DAY(B40)=7,1474.22,0) + IF(DAY(B40)=22,0) + ...
although, whenever I see a formula as complex as what you have, I would consider looking for a different solution -- Vlookup comes to mind.
In addition, with a VLOOKUP table, you would have seen that you have some conflicts -- e.g: you list the same condition of B40=8 to return two different values; and the same condition of A40 = Fri, to also return two different values.

Resources