sum number of cells based on current date in excel spreadsheet - excel

I've got a spreadsheet like this:
date | 7/1 | 7/2 | 7/3 | 7/4
-----|-----|-----|-----|-----
val | 3 | 5 | 1 | 3
-----|-----|-----|-----|-----
I want to sum the val row, but only up to the current date. So if today were 7/3, the sum would be 3+5+1=9. If today were 7/4, it would be 12.
I figured this out to get the number of columns:
=YEARFRAC(B1,TODAY())*360 // B1 is the first date -- 7/1
but I can't figure out how to tell excel to do the sum:
=SUM(B2:<B+num cols above>2)
Presumably its something to do with references, and lookup, but I'm not really familiar with how those work....

You can use SUMIF:
=SUMIF(A1:E1,"<="&TODAY(),A2:E2)
Assuming your dates are in a1:e1 and your values are in a2:e2.

The OFFSET function should do the job. There's a similar question here. Without knowing the exact layout of your table, I guess your formula would look something like:
=SUM(OFFSET(B2,0,0,1,DAY(TODAY())))
Where DAY(TODAY()) returns the day in the month. This number is then used as the width of the range to SUM over in OFFSET.
I hope that was relatively clear. Good luck.

Put this VBA in a module
Option Explicit
Public Function GetTotal(StartCell As Range) As Integer
Dim i As Integer, j As Integer
i = StartCell.Row
j = StartCell.Column
If Cells(i, j) > Date Then
GetTotal = 0
Exit Function
End If
While Cells(i, j) <> DateAdd("d", 1, Date) 'values up to an including today'
GetTotal = GetTotal + Cells(i + 1, j)
j = j + 1
Wend
End Function
and then use it in a worksheet cell by inserting
=GetTotal([starting date cell])
where [starting date cell] is the cell with the date from which you want the sum. The worksheet cell's value will be the sum

There are three ways to get the sum of the values between the dates.
Using sumifs
=SUMIFS(B2:B15,A2:A15,">="&F3,A2:A15,"<="&F4)
Using sumproduct
=SUMPRODUCT((A2:A15>=F3)*(A2:A15<=F4),B2:B15)
Using offset
=SUM(OFFSET(B1,MATCH(F3,A2:A15,0),0,MATCH(F4,A2:A15,0)-MATCH(F3,A2:A15,0)+1,1))
If Date range is in A column and val range is in B column.

Related

Getting Current Date and Return as Integer?

I have a date like this (mm/yy) in row 1
A B C D E F
1/19 2/19 3/19 4/19 5/19 6/19 ...
I want the VBA to recognize today's date and match it to current column and return as integer.
Ignoring the days (only matching month and year).
For example, if today is 4/13/2019, it would be 4 (column D)
I would need this in VBA because I will be using it to define a range:
For today To x month
It appears OP was looking for a VBA solution, so here is an alternative.
I can think of a few completely different methods of accomplishing this within VBA. Your question isn't very clear of what you are wanting the end result to be, but it appears you are looking for a function that will return the column number - perhaps so you can use to pinpoint a range.
Function DateCol(ByVal InputDate As Date) As Long
Dim colDate As Date
colDate = InputDate - Day(InputDate) + 1
Dim srcRng As Range
Set srcRng = ThisWorkbook.Worksheets("Sheet1").Rows(1)
DateCol = srcRng.Find(What:=colDate, LookAt:=xlWhole).Column
End Function
You simply take an input date, subtract the days (and add 1 since the first day of the month isn't 0). Then you take this new date and use the .Find() method to locate the range that contains your date on the worksheet, and finally the .Column property to get the number you are looking for.
Here is a small sample usage:
Sub test()
' Example Usage
Cells(10, DateCol(#6/11/2019#)).Value = "Test"
End Sub
In the above test sub, the DateCol() function would have returned the value of 6 in your sample worksheet, making the result:
Cells(10, 6).Value = "Test"
Only issue is that this function doesn't contain any error handling. You will raise an error if the date is not found in .Find(), so ensure that you take this into consideration.
Also, don't forget to change this line to use the true Worksheet:
ThisWorkbook.Worksheets("Sheet1").Rows(1)
I had to redo my answer after messing with the data. this is what i ended up with.
On Row 1 I entered the dates as: 1/1/2019, 2/1/2019, 3/1/2019... and custom formatted the row to only show it as mm/yy.
With the formula below I grab the month and year from the given date and convert it into the first of the month. I am very positive there is a better way to make it but my brain is fried for the day.
=MATCH(NUMBERVALUE(TEXT(A3,"mm")&"/1/"&TEXT(A3,"yy")),$1:$1,0)
Edit: (Edit formula to make it permanent on Row 1 [$1:$1])
Assuming that the date 4/13/2019 is on Cell A3

Counting rows based on individual columns, and the sum of multiple columns

In excel, I need to count the number of rows based on criteria from values in individual columns, and from the sum of a set of multiple columns.
For example, with the attached image of data, I want to be able to count the number of rows which are "valid" (= when Column A = 1), are over 17 years old (= Column B = >17), and when the sum of columns C to G are equal to zero.
I am currently using countifs function, with individual criteria for columns C to G being zero. However, with my actual data there are many more columns than C to G so the formula becomes too large, they are taking a long time to write and very vulnerable to mistakes.
I have tried using sumproduct but this has the same problem with a long formula.
Formulas I have tried;
=COUNTIFS($A:$A, 1, $B:$B, ">17", $C:$C, 0, $D:$D,0, $E:$E,0, $F:$F,0, $G:$G,0)
=SUMPRODUCT(($A:$A=1)*($B:$B>17)*($C:$C=0)*($D:$D=0)*($E:$E=0)*($F:$F=0)*($G:$G=0))
I know I could create a new column with an If function for the sum of columns C-G first (=IF(SUM(C2:G2)=0, 1, 0)), and then include this as a criteria (new column = 1) within a countifs, but I would like to avoid creating new columns with this data.
I would like to do =COUNTIFS($A:$A, 1, $B:$B, ">17", C:G, SUM(C:G)=0), but sum within countifs is not possible.
Any ideas would be very much appreciated?
Image of data:
Sample data:
| Valid | Age | a | b | c | d | e |
|-------|-----|---|---|---|---|---|
| 1 | 18 | 0 | 0 | 0 | 0 | 0 |
| 0 | 8 | 1 | 0 | 0 | 0 | 1 |
| 0 | 48 | 0 | 1 | 0 | 0 | 1 |
| 1 | 22 | 0 | 0 | 0 | 0 | 0 |
You said that you're unhappy with your COUNTIFS formula, but here's an efficient way to still use COUNTIFS (shorter/easier than VBA) and maintain accuracy.
The formula with your example would be:
=COUNTIFS(A:A,1,B:B,">=18",C:C,,D:D,,E:E,,F:F,,G:G,)
This is likely similar what you were using, but note:
If the criteria is "=0" then no criteria need to be specified between the commas.
If the function applies to the entire column, there is no need to specify row numbers.
In fact, even if there's other values
above/below your data (like headings), they'll be ignored
(unless they
meet all the criteria in the formula, which would be unlikely.)
Want to avoid errors? Make Excel write the formula for you!
If you're concerned about making errors when adjusting the formula to your actual data, let Excel do the work for you with three steps. (First save your workbook.)
Select each column (or a cell from each column) that you want to include in your formula. (To select multiple areas, click the first one and then hold Ctrl while you click the rest.)
Copy the line below by highlighting it and hitting Ctrl+C:
?"=COUNTIFS(A:A,1,B:B,"">=18""";:For Each c In Selection.Columns:?","&Columns(c.Column).Address&",";:Next c:?")"
Hit Alt+F11 then Ctrl+GV then Enter (This immediately runs the VBA code from Step 2.)
The formula will appear on the next line. Just copy/paste into to where you want it!
Example output:
=COUNTIFS(A:A,1,B:B,">=18",$C:$C,,$F:$F,,$G:$G,,$P:$P,,$T:$T,,$AJ:$AJ,,$AC:$AC,)
Edit:
I'm not sure why you want/need to use INDIRECT but it's fine as long as you maintain the same syntax. A simplified example:
I have values in Columns A and B. I want to count rows where A=1 and B=1. My COUNTIFS formula (in D2) would be: =COUNTIFS(A:A,1,B:B,1)
The reason to use INDIRECT could be if, for example, I don't always want this to use Column B -- I want to be able to specify which column to use, in a different cell, maybe D5.
In D5 I enter the text: B:B. Then I change the formula is D2, replacing B:B with INDIRECT(D5).
Since E2 contains the text B:B, the formula is still indirectly referring to B:B, and the result of the formula does not change. If I specify a different column range in E2, the formula will look at the new range.
Important Note:
With SUMIFS, COUNTIFS and AVERAGEIFS, all ranges specified must have the same number of rows and columns as the criteria_range1 argument.
In this formula, that means they must be entire columns.
If you're just trying to refer to a column on a different worksheet, that's fine as long as you use correct syntax, such as: =COUNTIFS(A:A,1,Sheet1!D:D,1) to refer to column D on Sheet1.
If the name of the sheet is contained as text in a cell (D5), but you want the column (D:D) still hard-coded, then your INDIRECT section of the formula would be: INDIRECT(D5&"!D:D")
If the specified worksheet name has a SPACE in it, then you need to surround the name with ' apostophes, in the correct spot:
=COUNTIFS(A:A,1,INDIRECT("'" & D5&"'!D:D"),1)
...which is one of the many reasons spaces and other non-alphanumeric characters should be avoided when naming "anything".
This can easily be done with a custom function using VBA. A custom function is a self programmed function that can be used as a normal function in an Excel cell. the function is called countCorrectEntries and takes a Range as Parameter. So if your table(including header) is located in A1:G5 the function in your target cell would be =countCorrectEntries(A1:G5) What it essentialy does is, it initiallizes a variable countCorrect=0 which is going to count all rows that fullfill all conditions.
The loop:
For i = 2 To UBound(table, 1)
...
Next i
Goes through the rows and checks the conditions that look as follows:
If table(i, columnNumber) <> condition Then
conditionsMet = False
End If
It checks in row i (the iterator) if in a column e.g 1 for first does not meet a certain condition. E.g value is not equal to 1. If that is so, a boolean conditionsMet is set to False and it is not counted as correct.
For your sum problem, I propose the following condition:
'Check sum
tempSum = 0
For j = startColumn To EndColumn
tempSum = tempSum + table(i, j)
Next j
If tempSum > 0 Then
conditionsMet = False
End If
The loop within the loop goes over the columns between startColumn and endColumn e.g 3 and 7 for column C to G and sums the values in tempSum. Then it is checked if the sum is greater 0 and again the conditionsMet is set to False if so.
If after all the conditions are checked the conditionsMet is still True then CountCorrect is incremented by 1.
The following code should work for your problem. Just change the inner loop values for the correct columns and you are all set.
Cheers!
Function countCorrectEntries(Rng As Range)
Dim table As Variant
table = Rng
countCorrect = 0
For i = 2 To UBound(table, 1)
conditionsMet = True
If table(i, 1) <> 1 Then
conditionsMet = False
End If
If table(i, 2) < 18 Then
conditionsMet = False
End If
'Check sum
tempSum = 0
For j = 3 To 7
tempSum = tempSum + table(i, j)
Next j
If tempSum > 0 Then
conditionsMet = False
End If
If conditionsMet = True Then
countCorrect = countCorrect + 1
End If
Next i
countCorrectEntries = countCorrect
End Function

counting multiple instances of a number in a range

I have a range of numbers and I need to identify if the first number of each cell is repeated anywhere in the corresponding row.
For example, in row 2 below, column 2 and column 3 both start with a 3. I know that if I do =LEFT(TRIM(cell)) to get just the first number but how do I find the rows that have repeated numbers in the row so row 1 isn't marked but row 2 is?
100|600|203|700| |
202|302|301|400|600|
Use a helper column with this as an array formula:
=SUMPRODUCT(--(COLUMN($A1:$E1)<>MATCH(INT($A1:$E1/100),INT($A1:$E1/100),0)))>0
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode. If done correctly then Excel will put {} around the formula.
Consider the following UDF():
Public Function AnyDups(rng As Range) As Boolean
Dim valu() As String
Dim i As Long, L As Long
L = rng.Count
ReDim valu(1 To L)
AnyDups = False
If L = 1 Then Exit Function
i = 1
For Each r In rng
valu(i) = Left(r.Value, 1)
i = i + 1
Next r
For i = 1 To L - 1
v = valu(i)
For j = i + 1 To L
If v = valu(j) Then AnyDups = True
Next j
Next i
End Function
For example:
The code just loops through the possible combinations of left-most characters in the cells.
It should work with either text or numeric data.
One way to do it would be to use this formula as a basis:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1)),FALSE,"Row "& ROW(A1))
Depending on how you want to check your row, you can adapt it. You could either have one formula to check one cell (Lock the A1 reference and drag right) - which would allow you to know where the match is but take more space on the sheet.
Or, if you don't have too many cells to check in each row, you could concatenate all cells in the same formula:
=IF(ISERROR(FIND(LEFT(TRIM(A1),1),B1&C1&D1&E1)),FALSE,"Row "& ROW(A1))
I'm sure Gary's Student will have a more elegant answer though!

Returning a date cell if a sum a range of a row is equal to something

I have a table that could go infinitely long, that has three categories per date. I need to figure out a way to have a cell return its date the earliest it reaches a numerical threshold (six in this case, or anything greater than five).
So with my specific workbook I’m working on (here), column AM through CH could go on forever. I would like to figure out a function to have 6th IV (Column AL) be the date (Row 1) the cumulative 6th ‘IV’ took place. So for the 6th row AL6 would be 3/17/14, because the sum of each ‘IV’ (or column with a 3 in Row 3) hits 6 on cell BD6. One reason this is throwing me off is that I can’t just use countifs, so for example, Row 8, there are 2 ‘IV's on 2/3/14 (cell AO8), so the 6th ‘IV’ is on 3/3/14 (the 6th one being in cell BA8).
Does this make sense to anyone? Any ideas, thoughts, comments, concerns?
EDIT: Solution
Public Function fn_FindDate(ByVal SearchRange As Range)
Dim Total As Integer
Total = 0
For Each Cell In SearchRange
If Not IsNull(Cell.Value) Then
Total = Total + Cell.Value
End If
If Total >= 6 Then
Cell.Font.ColorIndex = 3
fn_FindDate = Range(Chr(64 + Cell.Column) & 1).Value
Exit Function
End If
Next Cell
fn_FindDate = ""
End Function
In Column A, you put the formula =fn_FindDate(AM2:CH2) and you should be good! Feel free to remove the Cell.Font.ColorIndex = 3 if you don't want the 6th IV to turn red.
It's also set up to recognise when it PASSES 6. If you have a 1, a 1 and a 5 in a row, the 5 will trigger, even though it technically skips from 2 to 7. Also, it will return a blank value if the '6' threshold hasn't been met in a row, so you can just copy-down and it won't look sloppy.
Hope this helps!

Excel - convert column letter to number equivalent vbs

I'm writing a vbs script to extract some data from an excel spreadsheet. Currently using the function:
objSheet.Cells(rowNum, colNum).Value
To get cell values, this allows me to do maths on the column number, e.g. add three to move across three columns. But in some instances I want to specify which Columns to get by letter:
objSheet.Cells(4, E).Value
I therefore need to write a vbs function to convert column letter to numbers E => 5. Needs to be able to handle a spreadsheet more than 26 cols wide.
I've seen lots of functions on the internet and SO for doing the opposite but not found much for doing the conversion this way.
Thanks
This code will run without Excel:
Function ColNum(strCol As String) As Integer
Dim i As Integer, col As Integer
For i = Len(strCol) To 1 Step -1
col = col + (Asc(Mid(strCol, i, 1)) - 64) * (26 ^ (i - 1))
Next
ColNum = col
End Function
Alternatively, in Excel, you can simply use this:
Function ColNum(strCol As String) As Integer
ColNum = Range(strCol & "1").Column
End Function
without vba:
To convert a column number to a letter you enter this formula:
=LEFT(ADDRESS(1,3,4)) (returns the column letter for the cell C1=C)
But this is still not satisfactory because if you insert a column before the column C the number 3 won't change to 4, so here is a fix:
=LEFT(ADDRESS(1,COLUMN(C1),4))
Hope this helps.
This is especially helpful when you need to create strings that specify a cell range for example.

Resources