VBA Sum up values in row based on condition - vba

I need to write a VBA code based on conditions:
-if orders have the same value in column D, column F, column P and column P = unit then sum up values in column Q; if column P=amount then sum up values in column S.
Dim lastrow1 As Long
Dim startrow As Long
Dim Cumulative As Variant
Dim y As Long
With Wb2.Worksheets.Item(1)
lastrow1 = Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Cumulative = 0
startrow = 4 'Row where your data starts + 1, so row 3 + 1 in this case
For y = startrow To lastrow1
If Range("P" & y - 1).Value = "Unit" Then
Cumulative = Cumulative + Range("Q" & y - 1).Value
If Range("F" & y).Value = Range("F" & y - 1).Value And Range("D" & y).Value = Range("D" & y - 1).Value And Range("P" & y).Value = Range("P" & y - 1).Value Then
Range("Q" & y - 1 & .Rows.Count).End(xlUp).Value = Cumulative
Cumulative = 0
End If
ElseIf Range("P" & y - 1).Value = "Amount" Then
Cumulative = Cumulative + Range("S" & y - 1).Value
If Range("F" & y).Value = Range("F" & y - 1).Value And Range("D" & y).Value = Range("D" & y - 1).Value And Range("P" & y).Value = Range("P" & y - 1).Value Then
Range("S" & y - 1 & .Rows.Count).End(xlUp).Value = Cumulative
Cumulative = 0
End If
End If
Next y
End With
But the code doesn't work, I got the range object error 1004 in line Range("S" & y - 1 & .Rows.Count).End(xlUp).Value = Cumulative.
Where is the problem in my code?

This is wrong Range("S" & y - 1 & .Rows.Count).End(xlUp).Value = Cumulative
It evaluates to something like for example S9:1048576 , which will throw error 1004.
Change it to :
Range("S" & y - 1 & ":S" & .Rows.Count).End(xlUp).Value = Cumulative

Related

Irregularity with the looping

I have a sheet "result" and another sheet "status".
The sheet "status" has a table with column A as calendar week.
The idea is to copy the count values of column K, of the "result" sheet to the data sheet.
Similarly other count values in other columns as well.
The code is working fine with no errors.
The problem is I get an error with two of my values.
CntT acc.to code is providing me with "93" actually , I have "95"
similarly cntS acc to code is providing me "49" while actually I have "50".
Could anyone help me to figure out where I am wrong.I already posted this question and checked with the feedback. It dint work for me.
Sub result()
Dim i As Integer
Dim j As Integer
Dim cnt As Integer
Dim cntU As Integer
Dim sht As Worksheet
Dim TotalRows As Long
Set sht = Sheets("Status")
Sheets("Result").Select
TotalRows = Range("E5").End(xlDown).Row
n = Worksheets("Result").Range("E5:E" & TotalRows).Cells.SpecialCells(xlCellTypeConstants).Count
For i = 2 To WorksheetFunction.Count(sht.Columns(1))
cntT = 0
cntU = 0
cntS = 0
If sht.Range("A" & i) = Val(Format(Now, "WW")) Then Exit For
Next i
For j = 4 To WorksheetFunction.CountA(Columns(17))
If sht.Range("A" & i) = Range("Q" & j) And Range("K" & j) = "Green" Then cntT = cntT + 1
If sht.Range("A" & i) = Range("Q" & j) And Range("J" & j) = "delayed" Then cntU = cntU + 1
If sht.Range("A" & i) = Range("Q" & j) And Range("A" & j) = "" Then cntS = cntS + 1
If cntT <> 0 Then sht.Range("C" & i) = cntT
If cntU <> 0 Then sht.Range("D" & i) = cntU
If cntS <> 0 Then sht.Range("B" & i) = cntS
If n <> 0 Then sht.Range("E" & i) = n
Next j
If cntT + cntU <> 0 Then
sht.Range("F" & i) = (cntS / n)
sht.Range("G" & i) = (cntT / n)
sht.Range("H" & i) = (cntS / n)
sht.Range("G" & i & ":F" & i & ":H" & i).NumberFormat = "0.%"
End If
'sht.Range("G" & i & ":F" & i & ":H" & i).NumberFormat = "0.%"
End Sub

Excel VBA - in a list, if cell equals specific value then

I started working on some code, and it works, but I feel like it could be done more effiently. Below is a portion of it to show what I'm doing. To simplify the idea, I've made it here so if the cell in column M is A, B, or C, it puts a 1 in column L. If column M is a D, E, or F, it puts a 2 in column L. And if column M is a G, H, or I, it puts a 3 in column L.
Is there an easier way to do this than how I'm doing it? I'm going to be dealing with a couple hundred possible values.
Sub ChangeTest()
Dim LastRow As Long
Dim i As Long
LastRow = Range("M" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow
If Range("M" & i).Value = "A" Or Range("M" & i).Value = "B" Or Range("M" & i).Value = "C" Then
Range("L" & i).Value = "1"
End If
If Range("M" & i).Value = "D" Or Range("M" & i).Value = "E" Or Range("M" & i).Value = "F" Then
Range("L" & i).Value = "2"
End If
If Range("M" & i).Value = "G" Or Range("M" & i).Value = "H" Or Range("M" & i).Value = "I" Then
Range("L" & i).Value = "3"
End If
Next i
End Sub

how to initialise my counter in vba excel

I have a problem with my vba project.
My workbook has 4 sheets (Draft, cky, coy and bey), in the sheet "draft i have all my data and i want to reorganise them. the columns "G" of the sheet "draft" contains the values (cky, coy and bey).
I want my macro to go through the colums and copy all the cells that have the same value and paste them in their corresponding sheet starting at the cell (A2), for exemple: i want the macro to copy all the data that have "cky" and paste it in the sheet "cky" starting at the cell A2 and so on/
Below you can see what i have done so far:
Sub MainPower()
Dim lmid As String
Dim srange, SelData, ExtBbFor As String
Dim lastrow As Long
Dim i, j, k As Integer
lastrow = ActiveSheet.Range("B30000").End(xlUp).Row
srange = "G1:G" & lastrow
SelData = "A1:G" & lastrow
For i = 1 To lastrow
If InStr(1, LCase(Range("E" & i)), "bb") <> 0 Then
Range("G" & i).Value = Mid(Range("E" & i), 4, 3)
ElseIf Left(Range("E" & i), 1) = "H" Then
Range("G" & i).Value = Mid(Range("E" & i), 7, 3)
Else
Range("G" & i).Value = Mid(Range("E" & i), 1, 3)
End If
Next i
'Sorting data
Range("A1").AutoFilter
Range(SelData).Sort key1:=Range(srange), order1:=xlAscending, Header:=xlYes
'Spreading to the appropriate sheets
j = 1
For i = 1 To lastrow
If Range("G" & i).Value = "CKY" Then
Sheets("CKY").Range("A" & j & ":E" & j).Value = Sheets("Draft").Range("C" & i & ":G" & i).Value
ElseIf Range("G" & i).Value = "BEY" Then
Sheets("BEY").Range("A" & j & ":E" & j).Value = Sheets("Draft").Range("C" & i & ":G" & i).Value
ElseIf Range("G" & i).Value = "COY" Then
Sheets("COY").Range("A" & j & ":E" & j).Value = Sheets("Draft").Range("C" & i & ":G" & i).Value
End If
j = j + 1
Next i
End Sub
Thank you to help
best regards
Use this refactored code in the For Loop and it should work for better for you:
For i = 1 To lastrow
Select Case Sheets("Draft").Range("G" & i).Value
Case is = "CKY","COY","BEY"
Dim wsPaste as Worksheet
Set wsPaste = Sheets(Range("G"& i).Value)
Dim lRowPaste as Long
lRowPaste = wsPaste.Range("A" & .Rows.COunt).End(xlup).Offset(1).Row
wsPaste.Range("A" & lRowPaste & ":E" & lRowPaste).Value = _
Sheets("Draft").Range("C" & i & ":G" & i).Value
End Select
Next i

For...Next loop breaks when using Not() operator

I am running a for...next loop that checking whether entries in a dataset meet a certain condition (in this case IsNA). However, changing the if-then-else conditions within this loop to also check whether a condition is not met seems to break the for/next loop. I receive a Next without For error even though that element of the sub hasn't changed.
I'm lost as to why the it thinks there is no next in the for loop when that part of the code hasn't changed.
--Original Working Code--
Option Explicit
Dim i As Double
Dim a As Range
Public ssht As Worksheet
Public susht As Worksheet
Public mdsht As Worksheet
Public LastRow As Long
Dim testcell As Long
Public Sub MissingDataSetCopy()
'Part Bii
'Find rows with NA error
Application.ScreenUpdating = False
Dim i, j As Integer
j = 4
'Finds current range on Summary worksheet
Set ssht = ThisWorkbook.Worksheets("sandbox")
Set mdsht = ThisWorkbook.Worksheets("MissingData")
Set susht = ThisWorkbook.Worksheets("summary")
'Copies data to sandbox sheet as values
susht.UsedRange.copy
ssht.Range("A1").PasteSpecial (xlPasteValues)
LastRow = ssht.Range("A4").CurrentRegion.Rows.Count
Dim testcell As Double
Dim numchk As Boolean
'For...Next look call ISNUMBER test
For i = 860 To 874
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i - 1 & ":G" & i - 1).Value
j = j + 1
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i + 1 & ":G" & i + 1).Value
j = j + 1
End If
Next i
Dim fnd As Variant
Dim rplc As Variant
fnd = "#N/A"
rplc = "=NA()"
mdsht.Cells.Replace what:=fnd, Replacement:=rplc, _
LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
SearchFormat:=False, ReplaceFormat:=False
End Sub
--Edit to If Statements--
For i = 860 To 874
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1)) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Not (Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1))) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i - 1 & ":G" & i - 1).Value
j = j + 1
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
End If
Next i
You need to close the second If block:
For i = 860 To 874
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1)) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
End If '<-- it was not closed
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Not (Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1))) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i - 1 & ":G" & i - 1).Value
j = j + 1
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
End If
Next i
Or alternatively using the ElseIf keyword if the two conditions (at it seems) are excluding each other:
For i = 860 To 874
If Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1)) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
ElseIf Application.WorksheetFunction.IsNA(ssht.Range("B" & i)) And Not (Application.WorksheetFunction.IsNA(ssht.Range("B" & i - 1))) Then
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i - 1 & ":G" & i - 1).Value
j = j + 1
mdsht.Range("B" & j & ":H" & j).Value = ssht.Range("A" & i & ":G" & i).Value
j = j + 1
End If
Next i

VBA Unique Sum Code

I have Surnames in Column A, First Names in Column B, Dates in Column C and Hours worked in Column D.
E.G.
Surname First Name Date Hours
COX Daniel 3/03/2015 6
COX Daniel 3/03/2015 4
COX Daniel 4/03/2015 3.5
COX Daniel 4/03/2015 4
COX Daniel 4/03/2015 2.5
COX Daniel 4/03/2015 0
I would like to sum the number of hours each person has worked each day into a new sheet.
Surname First Name Date Hours
COX Daniel 3/03/2015 10
COX Daniel 4/03/2015 10
I have a code that works, however, it is very longwinded and would like to see how I can improve my coding. My code is also limited by the number of entries on a specific date (I have done up to 6 entries); there could be more.
Sub WorkHours()
Application.ScreenUpdating = False
Dim R As Integer
For R = ActiveSheet.UsedRange.Rows.Count To 1 Step -1
'Sort Data by Date and then by Surname
Sheets("Sheet1").Select
Worksheets("Sheet1").Columns("A:N").Sort key1:=Range("C2"), order1:=xlAscending, Header:=xlYes
Worksheets("Sheet1").Columns("A:N").Sort key1:=Range("A2"), order1:=xlAscending, Header:=xlYes
'Sum Work Hours for One Day
Worksheets("Sheet1").Select
If Range("C" & R) = Range("C" & (R + 1)) And Range("C" & R + 1) = Range("C" & (R + 2)) And Range("C" & R + 2) = Range("C" & (R + 3)) And Range("C" & R + 3) = Range("C" & (R + 4)) And Range("C" & R + 4) = Range("C" & (R + 5)) And Range("C" & R + 5) <> Range("C" & (R + 6)) Then
Range("C" & R).Select
ActiveCell.Offset(5, 2) = Application.Sum(Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(5, 1)))
End If
If Range("C" & R) = Range("C" & (R + 1)) And Range("C" & R + 1) = Range("C" & (R + 2)) And Range("C" & R + 2) = Range("C" & (R + 3)) And Range("C" & R + 3) = Range("C" & (R + 4)) And Range("C" & R + 4) <> Range("C" & (R + 5)) Then
Range("C" & R).Select
ActiveCell.Offset(4, 2) = Application.Sum(Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(4, 1)))
End If
If Range("C" & R) = Range("C" & (R + 1)) And Range("C" & R + 1) = Range("C" & (R + 2)) And Range("C" & R + 2) = Range("C" & (R + 3)) And Range("C" & R + 3) <> Range("C" & (R + 4)) Then
Range("C" & R).Select
ActiveCell.Offset(3, 2) = Application.Sum(Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(3, 1)))
End If
If Range("C" & R) = Range("C" & (R + 1)) And Range("C" & R + 1) = Range("C" & (R + 2)) And Range("C" & R + 2) <> Range("C" & (R + 3)) Then
Range("C" & R).Select
ActiveCell.Offset(2, 2) = Application.Sum(Range(ActiveCell.Offset(0, 1), ActiveCell.Offset(2, 1)))
End If
If Range("C" & R) = Range("C" & (R + 1)) And Range("C" & R + 1) <> Range("C" & (R + 2)) Then
Range("C" & R).Select
ActiveCell.Offset(1, 2) = Application.Sum(ActiveCell.Offset(0, 1), ActiveCell.Offset(1, 1))
End If
If Range("C" & R) <> Range("C" & (R + 1)) Then
Range("C" & R).Select
ActiveCell.Offset(0, 2) = ActiveCell.Offset(0, 1)
End If
Next R
'Copy Sheet
Sheets("Sheet1").Columns(1).Copy Destination:=Sheets("Sheet2").Columns(1)
Sheets("Sheet1").Columns(2).Copy Destination:=Sheets("Sheet2").Columns(2)
Sheets("Sheet1").Columns(3).Copy Destination:=Sheets("Sheet2").Columns(3)
Sheets("Sheet1").Columns(5).Copy Destination:=Sheets("Sheet2").Columns(4)
'Delete Empty Hours Columns
Sheets("Sheet2").Select`
On Error Resume Next
Columns("D").SpecialCells(xlCellTypeBlanks).EntireRow.Delete`
'AutoFit Columns
Cells.Select
Cells.EntireColumn.AutoFit
Application.ScreenUpdating = True
End Sub
You should name your range of cells. You should then save your workbook, and click
Data>From Other Sources>From Microsoft Query
You should then select Excel Files, Ok, then navigate to your Excel file. You should select your range, then click Ok. Then, drop in the following SQL statement, updated for your range
SELECT Values.Surname, Values.[First Name], Values.Date, SUM(Values.Hours) _
FROM Values Value GROUP BY Values.Surname, Values.[First Name], Values.Date