Excel 2013 VBA add new line to Formula - vba

With my VBA Code i add a new line to a table. In the last row of the table i have a =Sum(SumIf(...)) Formula, this row will jump one row down if i add the new line.
So now i want to add the added line to the Formula.
This is my Code so far:
Private Sub CommandButton1_Click()
Dim lastrow As Long
Dim i As Integer
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row + 1
i = 4
Do Until i = lastrow
calc = "SUMIF($K$3:$K$19,N" & i & ",$L$3:$L$19))"
ActiveSheet.Range("N" & lastrow + 1 & ":BI" & lastrow + 1).Formula = "=SUM(SUMIF($K$3:$K$19,N3,$L$3:$L$19)," & calc
i = i + 1
Loop
End Sub
In fact it works fine, but in the End the Formula looks like this:
=Sum(SumIf($K$3:$K$19,N3,$L$3:$L$19),SumIF($K$3:$K$19,N21,$L$3:$L$19))
What do i have to add to the code that every row will be added to the Formula?
Hope someone can help me. I am new to VBA.
EDIT:
The Worksheet shows all assignments and the working progress. With a CommandButton i add a new assignment to the table. So right now my table has 20 rows, in row 21 is the =SUM(SUMIF(..)) - Formula. If i add a new assignment the formula goes to row 22 and in row 21 the new assignment will be shown.
With my Code i want that every row will be added to the formula. Right now the formula goes from N3 to N20. If i add the new line the N21 will not be added to the formula. With my code above it only shows the first and the last row.
In fact i want that the formula will look like this:
=SUM(SUMIF($K$3:$K$19,N3,$L$3:$L$19),SUMIF($K$3:$K$19,N4,$L$3:$L$19) ... SUMIF($K$3:$K$19,N21,$L$3:$L$19))
This is my table hope it will help

This will solve your problem.
You need to assign a value to the variable "calc" before your loop. Then add to its value inside the loop with another statement. Finally, do not put the formula into the cells' values until after you have exited the loop and add a final parentheses to the formula.
Dim lastrow As Long
Dim i As Integer
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row + 1
i = 4
calc = "=SUM(SUMIF($K$3:$K$19,N3,$L$3:$L$19),"
Do Until i = lastrow
calc = calc & "SUMIF($K$3:$K$19,N" & i & ",$L$3:$L$19),"
i = i + 1
Loop
ActiveSheet.Range("N" & lastrow + 1 & ":BI" & lastrow + 1).Value = calc & ")"

Related

How can I insert a dynamic last row into a formula?

I'm working with a clean sheet where I paste one column of dates with a varying number of rows. My goal is to show how many times each date shows up. However, every time I get to the last line I keep getting Run-time error '1004' Application-defined or object-defined error.
Here is my code:
Dim lastrow As Long
Set ws = ActiveSheet
Set startcell = Range("A1")
lastrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
Range("B2").Formula = "=countif(A1:" & lastrow & ")"
Thanks in advance!!
COUNTIF function takes 2 arguments (https://support.microsoft.com/en-us/office/countif-function-e0de10c6-f885-4e71-abb4-1f464816df34), not one as in your code. Also missed column letter in range. If you want to process N dates, you have to make N formulas COUNTIF.
Try this code (dates in column A from A1, formulas in column B):
Sub times()
With ActiveSheet
Intersect(.Columns(1), .UsedRange).Offset(0, 1).FormulaR1C1 = "=COUNTIF(C[-1],RC[-1])"
End With
End Sub
Result:
SOLVED! 4 WAYS
High-level
Countif formula is incorrect (missing: col label A + condition)
Outlook: quick to fix, but requires loop for all dates
Current method may be CPU/time-intensive for large lists
Solutions A-D:
See Below (Links section), for google sheets (with full macro code, descriptions) for 4 solutions (3 macro based + 1 macro-free albeit dynamic soln). Briefly:
A: output with correction to your code
B: as for A, with for loop deployed
C: VB code for much quicker implementation of for loop/.Function code
D: macro-free variant (proposed/preferred)
Screenshots
Comparison table
Links:
Google Sheet
VBA count and sumifs - Automate Excel
VB code (A-C)
For completeness (same can be found in linked Google Sheet, typed - so macro-free / safe workbook):
Sub Macro_A():
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
cell = Range("a4").Address
Range("B4").Value = "=countif(A1:" & "A" & lastrow & "," & cell & ")"
' For i = 1 To lastrow - Range(cell).Row + 1
' Range("B4").Offset(i - 1).Formula = "=countif(A1:" & "A" & lastrow & "," & Range(cell).Offset(i - 1).Address & ")"
' Next
End Sub
Sub Macro_B():
Application.Calculation = xlCalculationManual
start_time = Timer
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
cell = Range("a4").Address
' Range("B4").Value = "=countif(A1:" & "A" & lastrow & "," & cell & ")"
For i = 1 To lastrow - Range(cell).Row + 1
Range("c4").Offset(i - 1).Formula = "=countif(A1:" & "A" & lastrow & "," & Range(cell).Offset(i - 1).Address & ")"
Next
Application.Calculation = xlCalculationAutomatic
Range("c3").End(xlDown).Offset(2).Value = Round(Timer - start_time, 2)
End Sub
Sub Macro_C():
start_time = Timer
Set Rng = Range("A4", Range("A4").End(xlDown))
For Each cell In Rng
cell.Offset(0, 3) = WorksheetFunction.CountIf(Rng, cell.Value)
Next
Range("d3").End(xlDown).Offset(2).Value = Round(Timer - start_time, 2)
End Sub
Macro-free soln (D)
Go to Formulas (ribbon), Name Manager:
In Name Manager window that apperas, click 'New...'
Populate dialogue box as req. (modifying Sheet name and $A$4 starting cell as req.)
Test your new dynamic range by clicking on upward arrow in bottom right hand corner (which should select dates in column A as depicted below)
Enter single formula in first cell of output range (here, cell D4)*:
Formulae (for convenience):
range_countif:
=Sheet1!$A$4:OFFSET(Sheet1!$A$4,COUNTA(Sheet1!$A:$A)-2,0,1,1)
Entry in cell D4
=COUNTIF(range_countif,range_countif)
*Notes: requires Office 360 for 'spill effect' (input as array formula with 'ctrl' + 'shift' + 'enter' otherwise).
Let me know if you have any further Qs. Best of luck with your excel Spreadsheet!
So many ways to achieve. I use this formula to get the number of rows
=ArrayFormula(MAX(IF(L2s!A2:A1009<>"",ROW(2:1011))))
Then I build a string from it
="L2s!A2:E"&D3
I love named ranges so I named the cell with the string built DynamicRangeL2s
Here is how I used the dynamic range in my formula (denormalize() is a custom function I wrote but could be any function) using the INDIRECT() function
=denormalize(INDIRECT(DynamicRangeL2s),INDIRECT(DynamicRangeSchedule),2,2,"right")
Here is a great article on Dynamic Ranges
https://www.benlcollins.com/formula-examples/dynamic-named-ranges/

VBA - Using Columns() in Formula

Right now i am using this code for a SumIf Formula:
Public Sub CommandButton1_Click()
Dim lastrow As Long
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row + 1
i = 4
calc = "=SUM(SUMIF($A$2:$A$22,N3,$B$2:$B$22),"
Do Until i = lastrow + 1
calc = calc & "SUMIF($A$2:$A$22,N" & i & ",$B$2:$B$22),"
i = i + 1
Loop
ActiveSheet.Range("N" & lastrow + 1 & ":BI" & lastrow + 1).Value = calc & ")"
End Sub
My Question now is, is there a way that i can change the criteria part in calc = calc & SUMIF($A$2:$A$22,N" & i & ",$B$2:$B$22)," that it jumps from column N to column M till column BI?
In fact my code works fine, but if i move some cells in the table it also moves the formula. And if i add the $ sign it only uses column N.
I tried to add this, but it doesn´t work
i = 4
lCol = 14
calc = "=SUM(SUMIF($A$2:$A$22,N3,$B$2:$B$22),"
Do Until i = lastrow + 1
calc = calc & "SUMIF($A$2:$A$22," & Columns(i, lCol) & ",$B$2:$B$22),"
i = i + 1
lCol = lCol + 1
Loop
I hope it is clear what i mean and someone can help me.
Try creating a cell and using its address.
calc = calc & "SUMIF($A$2:$A$22," & Cells(i, lCol).address(0, 0) & ",$B$2:$B$22),"
#Jeeped:
I tried to change the syntax for .address, but i still does not solve my problem. I hope with the following pictures i can explain it better.
In the first picture you can see how my table looks and which cells are used in the formula.
In the second picture i moved some cells to the left and unfortunately the formula also moves. This is what i want to prevent
And if i use .Address(0, 1) the formula looks like this in every column:
=SUM(SUMIF($A$2:$A$22;$N3;$B$2:$B$22),SUMIF($A$2:$A$22;$N4;$B$2:$B$22) ... )

Find empty cell, add all the cells above, and place sum in the empty cell

I am new to VBA and I've been working on a VBA project that needs to find the empty cell and add all the cells above that empty cell and also place the sum on it. I tried finding the right code for it but no luck. Any suggestions will be greatly appreciated.
Here's the part of the data in the project:
Thank you!
Actually, your question is not clear. The logic of my code is
Looping all row between startRow and lastRowAnd find blank cell(#N/A).If found, adding values of all above cell from that cell and set total to that cell.But the adding is quarterly. And If continuous cells are found, set 0.
Means:If startRow = 1 and lastRow = 11, blank cell are 5, 10 and 11.
So, total value from row 5 cell is adding of above 4 cell(1+2+3+4) and
total value from row 10 cell is also adding of above 4 cell(6+7+8+9).And total value from row 11 cell is 0. Don't know logic to do.
I think that I give an right answer. I already tested the code. It perfectly work for me. If it is not for you, let me know. Here the code:
Public Sub findTotal()
Dim startRow, lastRow As Long
Dim row, innerStart As Long
With Sheets("Budget")
'Set start row
startRow = 1
innerStart = startRow
'last row must be last blank row for add all cell above from that
lastRow = 35
'Looping all row between startRow and lastRow
For row = startRow To lastRow Step 1
'Loop until blank
If .Range("N" & row).Text = "#N/A" Then
If row - startRow > 0 And row <> innerStart Then
'Set total of above cell to blank cell
.Range("N" & row) = WorksheetFunction.Sum(.Range("N" & row - 1, "N" & innerStart))
'Set next start row for adding next blank cell
innerStart = row + 1
Else
'Set 0 for continuous cells
.Range("N" & row) = 0
'Here, if you want to set above total, you can use as follow:
'.Range("N" & row) = .Range("N" & row - 1)
End If
End If
Next row
End With
End Sub

Create a VBA macro that Find and Copy?

I need a little bit help with a macro of Excel.
I need to create a macro that automatically find users and copy the values that i have in an other Sheet:
I have one sheet with values that contains the Users and their Kills and Deaths, I create 3 sheets more (3 different groups of users), and I need that the macro copy values automatically finding the users and copying values.
Images to describe it better:
----(Copy this values on)----->
You don't need a macro for this, using the worksheetfunction VLOOKUP is sufficient.
As an example, if you have your headers in row 1 and users in column A, what you'd put into cell B2 (the number of kills for the first user) would be =VLOOKUP($A2;Values!$A$2:$C$9;2;FALSE) and C2 would be =VLOOKUP($A2;Values!$A$2:$C$9;3;FALSE).
The arguments for the function (which you can also find in the linked document) is:
First, the value you're looking for, in your case whatever is in A2
Next the array of values which you want to return a result from - vlookup will only look through the first column, but since you want to return results from the other columns we include columns A:C in the formula.
What column in the range you search to return the result from for kills it is column 2, for deaths column 3.
Finally whether you want to have an exact match (false) or if an approximate one is ok (true).
If I understand what you're after, you should be able to do this with VLOOKUPs
(No VBA necessary)
The following source code solve your problem.
Option Explicit
Dim MyResultWorkbook As Workbook
Dim ValuesWorksheet As Worksheet
Dim SniperWorksheet As Worksheet
Dim ARsWorksheet As Worksheet
Sub CopyResult()
Set MyResultWorkbook = ActiveWorkbook
Set ValuesWorksheet = MyResultWorkbook.Sheets("Values")
Set SniperWorksheet = MyResultWorkbook.Sheets("Sniper")
Set ARsWorksheet = MyResultWorkbook.Sheets("Ars")
Dim SniperLastRow As Long
Dim ARLastRow As Long
Dim RowPointer As Long
Dim ValuePointer As Long
ValuePointer = 2
'Update the Sniper worksheets
SniperLastRow = SniperWorksheet.Cells(SniperWorksheet.Rows.Count, "A").End(xlUp).Row
For RowPointer = 2 To SniperLastRow
Do While (SniperWorksheet.Range("A" & RowPointer).Value <> ValuesWorksheet.Range("A" & ValuePointer).Value)
ValuePointer = ValuePointer + 1
Loop
SniperWorksheet.Range("A" & RowPointer).Offset(0, 1).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 1).Value 'copy kill
SniperWorksheet.Range("A" & RowPointer).Offset(0, 2).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 2).Value 'copy death
ValuePointer = 2
Next
'Update the Ars worksheets
ARLastRow = ARsWorksheet.Cells(ARsWorksheet.Rows.Count, "A").End(xlUp).Row
For RowPointer = 2 To ARLastRow
Do While (ARsWorksheet.Range("A" & RowPointer).Value <> ValuesWorksheet.Range("A" & ValuePointer).Value)
ValuePointer = ValuePointer + 1
Loop
ARsWorksheet.Range("A" & RowPointer).Offset(0, 1).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 1).Value 'copy kill
ARsWorksheet.Range("A" & RowPointer).Offset(0, 2).Value = ValuesWorksheet.Range("A" & ValuePointer).Offset(0, 2).Value 'copy death
ValuePointer = 2
Next
End Sub

Change a cell's format to boldface if the value is over 500

I am using Excel 2010 and trying to add a bunch of rows placing the sum of columns A and B in column C. If the sum is over 500 I would then like to boldface the number in column C. My code below works works mathematically but will not do the bold formatting. Can someone tell me what I am doing wrong? Thank you.
Public Sub addMyRows()
Dim row As Integer 'creates a variable called 'row'
row = 2 'sets row to 2 b/c first row is a title
Do
Cells(row, 3).Formula = "=A" & row & "+B" & row 'the 3 stands for column C.
If ActiveCell.Value > 500 Then Selection.Font.Bold = True
row = row + 1
'loops until it encounters an empty row
Loop Until Len(Cells(row, 1)) = 0
End Sub
Pure VBA approach:
Public Sub AddMyRows()
Dim LRow As Long
Dim Rng As Range, Cell As Range
LRow = Range("A" & Rows.Count).End(xlUp).Row
Set Rng = Range("C2:C" & LRow)
Rng.Formula = "=A2+B2"
For Each Cell In Rng
Cell.Font.Bold = (Cell.Value > 500)
Next Cell
End Sub
Screenshot:
An alternative is conditional formatting.
Hope this helps.
Note: The formula in the block has been edited to reflect #simoco's comment regarding a re-run of the code. This makes the code safer for the times when you need to re-run it. :)