How to sum total row and the bottom of the data - excel

Below is my lines of code
sub test
Dim VR As Long
VR = Range("H" & Rows.Count).End(xlUp).Row
Range("J" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(J2:J" & VR &
")"
Range("L" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(L2:L" & VR &
")"
Range("M" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(M2:M" & VR &
")"
Range("N" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(N2:N" & VR &
")"
Range("O" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(O2:O" & VR &
")"
Range("P" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(P2:P" & VR &
")"
Range("Q" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(Q2:Q" & VR &
")"
Range("R" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(R2:R" & VR &
")"
Range("S" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(S2:S" & VR &
")"
Range("T" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(T2:T" & VR &
")"
Range("U" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(U2:U" & VR &
")"
Range("V" & Rows.Count).End(xlUp).Offset(2, 0).Formula = "=sum(V2:V" & VR &
")"
end sub
I have these lines of code that sum up every column of data but how do I sum these cells?

Try, please:
Range("X" & VR + 2).formula = "=sum(J" & VR + 2 & ":V" & VR + 2 & ")"

Not an answer to your question but a probably a huge simplification, to insert the formula into all the columns in one step:
Dim VR As Long
VR = Range("H" & Rows.Count).End(xlUp).Row
Dim VR2 As Long
VR2 = VR + 2 ' I'm assuming that you just need to offset the last row by 2
Range("J" & VR2 & ",L" & VR2 & ":V" & VR2).Formula = "=sum(J2:J" & VR & ")"

You have range of columns which you want to sum. For each column you want to:
sum all values that exist in a column,
write sum 2 cells below last row.
Currently, you get the last row for H column and apply it to every column, which might not be valid. Just imagine that last row for H column is 25th and for J column it is 27th. You would write sum of J2:J25 in cell J27 and overwrite value in J27.
So I recommend writing loop over set of columns and apply listed above actions:
cols = Array("J", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V")
rowsCnt = Rows.Count
' This variable will contain sum of all values
totalSum = 0
For i = LBound(cols) to UBound(cols)
lastRow = Range(cols(i) & rowsCnt).End(xlUp)
colSum = Application.Sum(Range(cols(i) & "2"), Range(cols(i) & lastRow))
Range(cols(i) & (lastRow + 2)) = colSum
' Here you sum all column sums
totalSum = totalSum + colSum
Next

Related

How to convert several non-adjacent columns to lowercase

This is looping through a worksheet that is about 10k rows and it is taking a considerable amount of time. Is there a way to do this faster aside from an array? thank you
For i = 2 To spberowcnt
With spbe30
.Range("b" & i).Value = LCase(.Range("b" & i).Value)
.Range("d" & i).Value = LCase(.Range("d" & i).Value)
.Range("i" & i).Value = LCase(.Range("i" & i).Value)
.Range("j" & i).Value = LCase(.Range("j" & i).Value)
.Range("l" & i).Value = LCase(.Range("l" & i).Value)
.Range("m" & i).Value = LCase(.Range("m" & i).Value)
.Range("n" & i).Value = LCase(.Range("n" & i).Value)
.Range("p" & i).Value = LCase(.Range("p" & i).Value)
.Range("q" & i).Value = LCase(.Range("q" & i).Value)
.Range("r" & i).Value = LCase(.Range("r" & i).Value)
.Range("z" & i).Value = LCase(.Range("z" & i).Value)
.Range("aa" & i).Value = LCase(.Range("aa" & i).Value)
End With
Next i
For i = 2 To spberowcnt
With spbe60
.Range("b" & i).Value = LCase(.Range("b" & i).Value)
.Range("d" & i).Value = LCase(.Range("d" & i).Value)
.Range("i" & i).Value = LCase(.Range("i" & i).Value)
.Range("j" & i).Value = LCase(.Range("j" & i).Value)
.Range("l" & i).Value = LCase(.Range("l" & i).Value)
.Range("m" & i).Value = LCase(.Range("m" & i).Value)
.Range("n" & i).Value = LCase(.Range("n" & i).Value)
.Range("p" & i).Value = LCase(.Range("p" & i).Value)
.Range("q" & i).Value = LCase(.Range("q" & i).Value)
.Range("r" & i).Value = LCase(.Range("r" & i).Value)
.Range("z" & i).Value = LCase(.Range("z" & i).Value)
.Range("aa" & i).Value = LCase(.Range("aa" & i).Value)
End With
Next i
This is the array solution
Sub test()
Application.ScreenUpdating = False
Dim arrWorksheets(1) As Variant, ws As Worksheet
Set arrWorksheets(0) = spbe30
Set arrWorksheets(1) = spbe60
Dim arrColumns As Variant
arrColumns = Array("B", "D", "AA") 'adjust to your needs
Dim arrValues As Variant
Dim iWs As Long, iC As Long, i As Long
For iWs = 0 To UBound(arrWorksheets)
Set ws = arrWorksheets(iWs)
For iC = 0 To UBound(arrColumns)
arrValues = ws.Range(arrColumns(iC) & "2").Resize(spberowcnt).Value
For i = 1 To UBound(arrValues, 1)
arrValues(i, 1) = LCase(arrValues(i, 1))
Next
ws.Range(arrColumns(iC) & "2").Resize(spberowcnt).Value = arrValues
Next
Next
Application.ScreenUpdating = True
End Sub
Alternative: helper columns ...
You could try something like the following, looping over the columns instead of the individual cells and using Evaluate and Lower on the entire column. You could also process adjacent columns together.
cols = Array("B", "D", "I:J", "L:N", "P:R", "Z:AA")
For i = LBound(cols) to Ubound(cols)
Dim col As String
col = cols(i)
With spbe30
Dim rng As Range
Set rng = .Rows("2:" & spberowcnt).Columns(col)
rng.Value = .Evaluate("LOWER(" & rng.Address & ")")
End With
Next
But as mentioned in comments, an array is probably the way to go.

Using VBA in excel - Pad the resulting output of a formula with a 0

I have written a block of code using VBA in excel that counts the number of records produced in a file exported from another platform on the very last line of the file.
This file has to contain a specific number of characters to validate. If the record count is 9 or less then it will operate just fine. However, if the record count is 10 or above the character limit is exceeded and it will fail.
Is there a way to embed a line code into the module that will pad the output from this last line of syntax with a leading 0 if the record count is less than 10? If so, I can then alter the earlier part of the code to remove a static character and meet the files requirements regardless of if the record count is above or below 9.
Code is below...The bolded area on the last line of the code at the very end (" & lastrow - 2 & ") is where I need to pad the 0 of the resulting formula.
Sub Hidden_macro1()
On Error Resume Next
Application.DisplayAlerts = False
Sheets("Testing_Report_Out").Delete
Application.DisplayAlerts = True
On Error GoTo 0
Sheets.Add.Name = "Testing_Report_Out"
Dim lastrow As Long
Dim lastrowfooter As Long
Dim I As Integer
Dim J As Integer
Sheets("Testing Report").Select
lastrow = Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row + 1
Sheets("Testing_Report_Out").Select
Range("A1").Formula = "=CONCATENATE('Testing Report'!A4,"" "",'Testing Report'!B4,'Testing Report'!C4,"" "",'Testing Report'!D4,'Testing Report'!E4,"" "",'Testing Report'!F4)"
I = 4
J = 2
Do Until I = lastrow
'Fill 1st formula (:20:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!G" & I & ",'Testing Report'!H" & I & ")"
J = J + 1
'Fill 2nd formula (:23B:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!I" & I & ",'Testing Report'!J" & I & ")"
J = J + 1
'Fill 3rd formula (:32A:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!K" & I & ",'Testing Report'!L" & I & ",'Testing Report'!M" & I & ",'Testing Report'!N" & I & ",'Testing Report'!O" & I & ")"
J = J + 1
'Fill 4th formula (:50K:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!P" & I & ",'Testing Report'!Q" & I & ")"
J = J + 1
'Fill 5th formula (:50K: Addy)
Range("A" & J).Formula = "='Testing Report'!R" & I & ""
J = J + 1
'Fill 6th formula (:57A:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!S" & I & ",'Testing Report'!T" & I & ")"
J = J + 1
'Fill 7th formula (:59:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!U" & I & ",'Testing Report'!V" & I & ")"
J = J + 1
'Fill 8th formula (:59:/ 3)
Range("A" & J).Formula = "='Testing Report'!W" & I & ""
J = J + 1
'Fill 9th formula (:59:/ 5)
Range("A" & J).Formula = "='Testing Report'!X" & I & ""
J = J + 1
'Fill 10th formula (:70:)
Range("A" & J).Formula = "=CONCATENATE('Testing Report'!Z" & I & ",'Testing Report'!AA" & I & ")"
J = J + 1
'Fill 11th formula (:71A:)
Range("A" & J).Formula = "='Testing Report'!AB" & I & ""
J = J + 1
'Fill 12th formula (:72:)
Range("A" & J).Formula = "='Testing Report'!AC" & I & ""
I = I + 1
J = J + 1
Loop
lastrowfooter = Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
Range("A" & lastrowfooter + 1).Formula = "=CONCATENATE('Testing Report'!AD4,'Testing Report'!AE4,'Testing Report'!AF4,'Testing Report'!AG4,"" "",'Testing Report'!AH4,'Testing Report'!AI4,'Testing Report'!AJ4," **& lastrow - 2 &** ")"
End Sub
You can use Format() as suggested by #BigBen
Range("A" & lastrowfooter + 1).Formula = _
"=CONCATENATE('Testing Report'!AD4,'Testing Report'!AE4,'Testing Report'!AF4," & _
"'Testing Report'!AG4,"" "",'Testing Report'!AH4,'Testing Report'!AI4," & _
"'Testing Report'!AJ4," & Format(lastrow - 2, "00") & ")"

VBA Code adding incorrect column rows for sub-totals

I am trying to update a previous employees code.
Column D and E are not adding the correct sub-totals. It seems for each sub total row, it is counting A4 which is the first row of numbers.
Not sure how to adjust the code.
Set firstSub = Range("D" & cTL.Row) 'set first sum from
For Each c In Range("D" & cTL.Row, "D" & cBR.Row)
If c.Value2 = "" Then
c.ClearContents
End If
'This if will only run for column D, but will fill column D and E with total fields
If Right(c.Offset(0, -2).Value2, Len(sTotal)) = sTotal Then
c.FormulaR1C1 = "=sum(R" & firstSub.Row & "C" & c.Column & ":R" & c.Offset(-1, 0).Row & "C" & c.Column & ")"
c.Offset(0, 1).FormulaR1C1 = "=sum(R" & firstSub.Row & "C" & c.Offset(0, 1).Column & ":R" & c.Offset(-1, 0).Row & "C" & c.Offset(0, 1).Column & ")"
formulaStrD = formulaStrD & c.Address([], [], xlR1C1) & ","
formulaStrE = formulaStrD & c.Offset(0, 1).Address([], [], xlR1C1) & ","
ElseIf Right(Range("A" & c.Row), Len(sTotal)) = sTotal Then
formulaStrD = Left(formulaStrD, Len(formulaStrD) - 1)
formulaStrE = Left(formulaStrE, Len(formulaStrE) - 1)
c.FormulaR1C1 = "=SUM(" & formulaStrD & ")"
c.Offset(0, 1).FormulaR1C1 = "=SUM(" & formulaStrE & ")"
End If
Next c
For Each c In Range("E" & cTL.Row, "H" & cBR.Row)
If c.Value2 = "" Then
c.ClearContents
End If
Next c
End Function
The key to fixing this (I think) is to 'reset' the "first row" each time the value in column B changes - otherwise, each sub-total for each distinct value in column B will reflect the aggregate of all rows above it - including the other sub-totals.
Set firstSub = Range("D" & cTL.Row) 'set first sum from
For Each c In Range("D" & cTL.Row, "D" & cBR.Row)
If c.Value2 = "" Then
c.ClearContents
End If
'This if will only run for column D, but will fill column D and E with total fields
If Right(c.Offset(0, -2).Value2, Len(sTotal)) = sTotal Then
c.FormulaR1C1 = "=sum(R" & firstSub.Row & "C" & c.Column & ":R" & c.Offset(-1, 0).Row & "C" & c.Column & ")"
c.Offset(0, 1).FormulaR1C1 = "=sum(R" & firstSub.Row & "C" & c.Offset(0, 1).Column & ":R" & c.Offset(-1, 0).Row & "C" & c.Offset(0, 1).Column & ")"
formulaStrD = formulaStrD & c.Address([], [], xlR1C1) & ","
' Fix the Column E subtotal reference
formulaStrE = formulaStrE & c.Offset(0, 1).Address([], [], xlR1C1) & ","
' Reset the "firstRow" so that we don't accidentally pickup
' the other subtotals
Set firstSub = c.Offset(1, 0)
ElseIf Right(Range("A" & c.Row), Len(sTotal)) = sTotal Then
formulaStrD = Left(formulaStrD, Len(formulaStrD) - 1)
formulaStrE = Left(formulaStrE, Len(formulaStrE) - 1)
c.FormulaR1C1 = "=SUM(" & formulaStrD & ")"
c.Offset(0, 1).FormulaR1C1 = "=SUM(" & formulaStrE & ")"
' Reset the subtotal formulas along with the "firstRow"
formulaStrD = ""
formulaStrD = ""
Set firstSub = c.Offset(1, 0)
End If
Next c
For Each c In Range("E" & cTL.Row, "H" & cBR.Row)
If c.Value2 = "" Then
c.ClearContents
End If
Next c

VBA to write data in cells very slow

I have written a very straightforward script which writes data into excel cells.
Basically, this is a loop over an array and it writes data into specific cells or formulas.
The problem is that this part of the script is extremly slow.
Any ideas on how to improve thath?
Thanks.
For j = 0 To i - 1
'Insère nouvelle ligne
Rows(startRow & ":" & startRow).Select
Selection.Copy
Rows(startRow + 1 & ":" & startRow + 1).Select
Selection.Insert Shift:=xlDown
'Insère données
If roomType(j) <> "" Then
Feuil3.Cells(startRow, 1).Value = roomName(j)
Feuil3.Cells(startRow, 2).Value = roomSurface(j)
Feuil3.Cells(startRow, 7).Value = roomPeople(j)
Feuil3.Cells(startRow, 12).Value = roomPeople(j)
Feuil3.Cells(startRow, 5).Value = dict.Item(roomType(j))
Feuil3.Cells(startRow, 3).Value = roomHeight(j)
Feuil3.Range("F" & startRow).Formula = "=IFERROR(IF($E" & startRow & "=Data!$A$55,,ROUNDUP($B" & startRow & "/VLOOKUP($E" & startRow & ",Data!$A$3:$E$55,4,FALSE),0)),)"
Feuil3.Range("H" & startRow).Formula = "=$C$25"
Feuil3.Range("I" & startRow).Formula = "=IF($E" & startRow & "=Data!$A$55,$B" & startRow & "*$E$55,(MAX(F" & startRow & ",G" & startRow & ")*H" & startRow & "))"
Feuil3.Range("N" & startRow).Formula = "=IFERROR(VLOOKUP($K" & startRow & ",$M$22:$O$26,3,FALSE),)"
Feuil3.Range("O" & startRow).Formula = "=IFERROR(IF(ISBLANK(M" & startRow & ")=TRUE,L" & startRow & "*N" & startRow & ",L" & startRow & "*M" & startRow & "*N" & startRow & "),)"
Feuil3.Range("Q" & startRow).Formula = "=MAX(I" & startRow & ",O" & startRow & ")"
Feuil3.Range("T" & startRow).Formula = "=IFERROR(MAX(R" & startRow & ",S" & startRow & ")/(B" & startRow & "*C" & startRow & "),)"
End If
startRow = startRow + 1
Next j
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
It is quicker to assign an array to a range of cells than to assign to individual cells in a loop. You could try sometihing like: Worksheets("MySheet").Range("A1:D100").Value = myArray. It is because communication between VBA and Excel takes some time. A little bit more on that here: VBA Excel large data manipulation taking forever
Also using Cells instead of Range is aboout 2.6 times faster. Here is a question on that: Range() VS Cells() - run times
I cut the script in pieces.
This part takes most of the time
For j = 0 To i - 2
Feuil3.Cells(startRow, 5).Value = dict.Item(roomType(j))
Feuil3.Cells(startRow, 6).Formula = "=IFERROR(IF($E" & startRow & "=Data!$A$55,,ROUNDUP($B" & startRow & "/VLOOKUP($E" & startRow & ",Data!$A$3:$E$55,4,FALSE),0)),)"
Feuil3.Cells(startRow, 8).Formula = "=$C$25"
Feuil3.Cells(startRow, 9).Formula = "=IF($E" & startRow & "=Data!$A$55,$B" & startRow & "*$E$55,(MAX(F" & startRow & ",G" & startRow & ")*H" & startRow & "))"
Feuil3.Cells(startRow, 14).Formula = "=IFERROR(VLOOKUP($K" & startRow & ",$M$22:$O$26,3,FALSE),)"
Feuil3.Cells(startRow, 15).Formula = "=IFERROR(IF(ISBLANK(M" & startRow & ")=TRUE,L" & startRow & "*N" & startRow & ",L" & startRow & "*M" & startRow & "*N" & startRow & "),)"
Feuil3.Cells(startRow, 17).Formula = "=MAX(I" & startRow & ",O" & startRow & ")"
Feuil3.Cells(startRow, 20).Formula = "=IFERROR(MAX(R" & startRow & ",S" & startRow & ")/(B" & startRow & "*C" & startRow & "),)"
startRow = startRow + 1
Next j

Need to run a Do While loop across multiple worksheets

I have been trying to run the same Do While loop function across multiple worksheets in a workbook and compile the data in another worksheet. The code works for the one worksheet that is specified but how do I get it to work across the others that are in the workbook at the same time?
Also worth mentioning that I only want it to run on some of the worksheets not all that are in the workbook (sheets are named as years - 2014, 2015 etc).
This is the code
Sub Total_Button1_Click()
Dim i As Integer
Dim strSheetFrom As String
Dim j As Integer
Dim strSheetTo As String
i = 3
j = 2
strSheetFrom = "2014"
strSheetTo = "Total"
Do While Trim(Sheets(strSheetTo).Range("B" & CStr(j)).Text) <> ""
j = j + 2
Loop
Do While Trim(Sheets(strSheetFrom).Range("B" & CStr(i)).Text) <> ""
If UCase(Trim(Sheets(strSheetFrom).Range("A" & CStr(i)).Text)) = "Y" Then
Sheets(strSheetTo).Range("B" & j & ":G" & j).Value = Sheets(strSheetFrom).Range("B" & i & ":G" & i).Value
Sheets(strSheetTo).Range("H" & j & ":I" & j).Value = Sheets(strSheetFrom).Range("I" & i & ":J" & i).Value
Sheets(strSheetTo).Range("J" & j & ":J" & j).Value = Sheets(strSheetFrom).Range("L" & i & ":L" & i).Value
Sheets(strSheetTo).Range("K" & j & ":K" & j).Value = Sheets(strSheetFrom).Range("Q" & i & ":Q" & i).Value
Sheets(strSheetTo).Range("L" & j & ":AH" & j).Value = Sheets(strSheetFrom).Range("s" & i & ":AO" & i).Value
j = j + 1
End If
i = i + 1
Loop
MsgBox "Total book created"
End Sub
Try making your strSheetFrom variable an array something like this:
strSheetFrom = new strSheetFrom[3]
strSheetFrom[2] = "2012"
strSheetFrom[1] = "2013"
strSheetFrom[0] = "2014"
Then put your code into another loop like so:
dim w as integer
for w = 0 To 3
Do While Trim(Sheets(strSheetTo).Range("B" & CStr(j)).Text) <> ""
j = j + 2
Loop
Do While Trim(Sheets(strSheetFrom[w]).Range("B" & CStr(i)).Text) <> ""
If UCase(Trim(Sheets(strSheetFrom[w]).Range("A" & CStr(i)).Text)) = "Y" Then
Sheets(strSheetTo).Range("B" & j & ":G" & j).Value = Sheets(strSheetFrom[w]).Range("B" & i & ":G" & i).Value
Sheets(strSheetTo).Range("H" & j & ":I" & j).Value = Sheets(strSheetFrom[w]).Range("I" & i & ":J" & i).Value
Sheets(strSheetTo).Range("J" & j & ":J" & j).Value = Sheets(strSheetFrom[w]).Range("L" & i & ":L" & i).Value
Sheets(strSheetTo).Range("K" & j & ":K" & j).Value = Sheets(strSheetFrom[w]).Range("Q" & i & ":Q" & i).Value
Sheets(strSheetTo).Range("L" & j & ":AH" & j).Value = Sheets(strSheetFrom[w]).Range("s" & i & ":AO" & i).Value
j = j + 1
End If
i = i + 1
Loop
w -= 1
next
I haven't tested it, but something like that. You get the idea.
Use a For Each and iterate over the Worksheet collections like this
'Variables
Dim useWorkSheet As Worksheet
Dim totalWorkSheet As Worksheet
Dim yearAsNumeric As Integer
Dim startingYear As Integer
'Settings
startingYear = 2014
'To reference the total worksheet so we can work with it
Set totalWorkSheet = ActiveWorkbook.Worksheets("Total")
'Iterate over each item in the collection
For Each useWorkSheet In ActiveWorkbook.Worksheets
'Force the name into a numeric value. If it starts with anything non numeric (A-Z|a-z|$,#,etc) then it will return 0
yearAsNumeric = Val(useWorkSheet.Name)
'Greater than or equal to the year we want to start with?
If yearAsNumeric >= startingYear Then
'Yes. Do your stuff here
useWorkSheet.Name
End If
Next

Resources