Find alternative to using nested loops for subtotalling data

totalchaos

New Member
Joined
Jul 6, 2012
Messages
40
I currently have data (below) that I sort by date, then job, then trade and then shift. For each date, job, trade and shift, I must provide subtotals and output the results to a separate sheet.

The code I currently use has nested do..loops which navigates the data, fills an array and writes to a separate sheet. The code (below) is the gist of what I have. The actual code is so complex to look at it gives me a headache and is hard to manage.

I'm looking for an alternative to the approach I've taken. I researched using autofilter. Unfortunately, from I can tell, I cannot get the list of unique values inside each filter which I would use to store in an array and then loop through and autofilter the specific values in the 4 fields I listed in the first paragraph. I'd then use the worksheetfunction.subtotal to get my subtotals. If anybody knows how to do this, it would be greatly helpful to me to simplify my code and possibly provide some performance efficiency. If it's not possible to use autofilter, any other suggestions would be greatly appreciated to simplify my code and improve the efficiency since my actual list is much larger. I'm using excel 2007 and 2010 on different computers.

Here is the data:

Excel 2007
ABCDEFGHI
1Line#EmployeeJobTradeCodeExtra #ShiftWork DateHours
2111201CarpenterA017/19/20124
3211201CarpenterB017/19/20124
4321201PlumberA127/18/20124
5421201PlumberA217/18/20123
6521201PlumberA017/18/20121
7631201ElectricianB127/19/20123
8731202ElectricianB027/19/20125
9841201ElectricianB017/19/20128
10941201ElectricianA017/18/20128
111051202CarpenterA017/19/20128
121161201ElectricianA117/19/20122
131261201ElectricianA017/19/20123
141361201ElectricianB017/19/20122
151461201ElectricianB117/19/20121
161571202PlumberA127/19/20123
171671202PlumberA027/19/20122
181771202PlumberA227/19/20124
191881202CarpenterA127/18/20122
201981201CarpenterB127/18/20126
212091202PlumberA117/18/20124
222191202PlumberA017/18/20124
2322101202CarpenterA117/18/20122
2423101202CarpenterB217/18/20121
2524101202CarpenterB017/18/20123
2625101201CarpenterB017/18/20122
Sheet1

<colgroup><col style="width: 48pt;" span="10" width="64"> <tbody>
</tbody>

Here is the code I currently use in a standard module:

Option Explicit
Dim wsSrce As Worksheet, rng As Range, sngHours As Single, strWrkDate As String, _
strJobNum As String, strTrade As String, strShift As String, Cntr As Long, _
arr() As Variant, i As Integer

Private Sub WorkReport()
Set wsSrce = ActiveWorkbook.Worksheets("Sheet1")
Set rng = wsSrce.Range("A1:I26")
'Sort by workdate, job, trade, shift
With wsSrce.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("H2:H26"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("C2:C26"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("D2:D26"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SortFields.Add Key:=Range("G2:G26"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange rng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'sum hours for each unique workdate, job, trade, shift combination
With wsSrce
Cntr = 1
Do Until IsEmpty(.Cells(Cntr, 1)) '1
Cntr = Cntr + 1
strWrkDate = .Cells(Cntr, 8)
Do While .Cells(Cntr, 8) = strWrkDate '2
strJobNum = .Cells(Cntr, 3)
Do While .Cells(Cntr, 8) = strWrkDate And .Cells(Cntr, 3) = strJobNum '3
strTrade = .Cells(Cntr, 4)
Do While .Cells(Cntr, 8) = strWrkDate And .Cells(Cntr, 3) = strJobNum And .Cells(Cntr, 4) = strTrade '4
strShift = .Cells(Cntr, 7)
Do While .Cells(Cntr, 8) = strWrkDate And .Cells(Cntr, 3) = strJobNum And .Cells(Cntr, 4) = strTrade And .Cells(Cntr, 7) = strShift '5
sngHours = sngHours + .Cells(Cntr, 9)
Cntr = Cntr + 1
Loop
FillArray
sngHours = 0
Loop
Loop
Loop
Loop
End With
WriteArray
'sort back to original order
With wsSrce.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("A2:A26"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange rng
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Private Sub FillArray()
i = i + 1
ReDim Preserve arr(1 To 5, 1 To i)
arr(1, i) = strWrkDate
arr(2, i) = strJobNum
arr(3, i) = strTrade
arr(4, i) = strShift
arr(5, i) = sngHours
End Sub
Private Sub WriteArray()
Dim a As Integer, wsTrgt As Worksheet, lngLR As Long
Set wsTrgt = ActiveWorkbook.Worksheets("Sheet2")
For a = 1 To UBound(arr, 2)
With wsTrgt
lngLR = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(lngLR, 1) = arr(1, a)
.Cells(lngLR, 2) = arr(2, a)
.Cells(lngLR, 3) = arr(3, a)
.Cells(lngLR, 4) = arr(4, a)
.Cells(lngLR, 5) = arr(5, a)
End With
Next a
Erase arr
End Sub

Any help is greatly appreciated!
 

Excel Facts

When they said...
When they said you are going to "Excel at life", they meant you "will be doing Excel your whole life".
Can you give me an example of what you want the output to be? It's hard keeping all the tables/arrays + code in my head at once.

Edit: Nevermind, I ran your code and I can see.
 
Last edited:
Upvote 0
Have you ever tried using a pivot table?


If you haven't, you should select the data, go to Insert -> Pivot Table (Located on the left side if you use my version) and then press OK.

On this new sheet with the pivot table, you will have options called Pivot Field List (on my version it's on the right side) and also other options at the top for the table.

Look for "Tabular Layout" in PivotTable Tools -> Design -> Layout Options and select it.

Finally, in the pivot table field list, check tickmarks in this order: WorkDate, Job (Make sure this is in the "Row Labels" area instead of "Sum"), Trade, Shift (Again, put this as a "Row Label"), and Hours (Leave this as a sum).


This might be an easy solution to what you're looking for, and it doesn't even require a macro. Editing a pivot tables with macros can be hard, though (at least, I haven't found an easy way yet), and they're generally just for information purposes. You can also keep ALL your data there, and can hide/show categories as you would like to see them. Is this kind-of what you were looking for?
 
Upvote 0
As above, depends on the output you want... have you considered using SUMIFS or AVERAGEIFS formulas etc...

You could sum the number of carpentry hours on job 1201 on 19 July by using...

=SUMIFS($I:$I, $D:$D, "Carpenter",$C:$C, 1201, $H:$H, 41109)

Of course you can refer to other cells in your formulas, instead of typing the criteria in manually.

Pivot tables work good too.
 
Upvote 0
I initially thought the sumifs could work too by using them in vba with worksheetfunction. Unfortunately I won't know the criteria to be used in the formula until the timesheets are summarized into the first table I posted above. Then I must determine unique values of each of the 4 columns I need and filter the various combinations so that I get totals for each shift within each trade within each job within each date. I'm beginning to think that the easiest way to do this is with the nested loops I'm using now.
 
Upvote 0
Why do you need the data in this specific format? If you can tell us what you're using the data for, then perhaps there's an easier way to accomplish it.
 
Upvote 0
The data must be in the format as shown below. I'm not worried about the employee count part right now. Ultimately, this data will be written to a customer's report form in this format. Hopefully, this will help you understand what I'm trying to accomplish. Thanks.

Excel 2007
ABCDEFG
1Employee CountHours
2Work DateJobTradeShift 1Shift 2Shift 1Shift 2
37/18/20121201Carpenter1126
47/18/20121201Electrician1080
57/18/20121201Plumber1144
67/18/20121202Carpenter1162
77/18/20121202Plumber1080
87/19/20121201Carpenter1080
97/19/20121201Electrician21163
107/19/20121202Electrician0105
117/19/20121202Plumber0109
127/19/20121202Carpenter1080
Sheet4

<colgroup><col style="width: 48pt;" span="8" width="64"> <tbody>
</tbody>
 
Upvote 0
=SUMPRODUCT(--(Sheet1!$H$2:$H$1000=$A3), --(Sheet1!$B$2:$B$1000=$B3), --(Sheet1!$D$2:$D$1000=C3), --(Sheet1!$G$2:$G$1000=D$2), Sheet1!$I$2:$I$1000)

If you put that in D3 and copied that cell+pasted it to D3:G12, will it show the correct data?
Note: goes up to row 1000 on the source ws; you can make it depend on the length of your source ws if you use code to generate it.

If you can populate your resulting list with that (that way you won't have to do so many loops to add up hours), then perhaps it will make your code simpler. The next step is to replace your loops with ways to populate the result list with all possible combinations of date/job number/trades, then paste in the formula at D3, then fill right and down for all combinations.

Does this help? I have other ideas, too.
 
Upvote 0
I can't get the formula to work, but I am seriously leaning toward a pivot table, then navigating that with vba to get the data I need and finally writing that to our customer's report form. At this point, I don't know how to navigate pivot tables. There is a pivot items property which I will check out. One problem I can see with the pivot table is counting the number of unique employees. It counts an employee that has two different codes in one day twice. Any ideas?
 
Upvote 0
Specify both Code and Trade as identifiers; If you didn't, the person looking at the data wouldn't be able to tell the difference either.
 
Last edited:
Upvote 0

Forum statistics

Threads
1,215,639
Messages
6,125,971
Members
449,276
Latest member
surendra75

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top