Private Const HEADER_ROW = 3 ' Set to be the row that contains the headers on the Data sheet
Private Const CRITERIA_RANGE = "$C$15:$C$26" ' Set to be the range that contains the criteria on the Report sheet
Private Const BUCKET_RANGE = "$I$15:$L$15" ' Set to be the range where we will put the values on the Report sheet
Private Const BUCKET_VALUES = "$N$6:$N$8" ' Set to be the range that contains the bucket value limits
Private Const EXTRA_CRITERIA_VALUE = "$C$30" ' Set to be the extra criteria header name
Private Const EXTRA_CRITERIA_RANGE = "$C$31:$C$36" ' Set to be the extra criteria range
Private Const INCLUDE_EXTRA_CRITERIA_IN_AVERAGE = False ' Determines whether the extra criteria column is used in the average calculation
Public Sub Levels()
Dim lastRow As Long
Dim lastCol As Long
Dim thisRow As Long
Dim thisCol As Long
Dim buckets(3) As Long
Dim headerCount As Long
Dim rowAverage As Double
Dim wsReport As Worksheet
Dim wsData As Worksheet
Dim dataSheet As Long
Dim validRow As Boolean
' Find the report sheet
Set wsReport = Worksheets("Levels")
' Clear previous results from the report sheet
wsReport.Range("I15:L64").ClearContents
' Process all data sheets
For dataSheet = 1 To 50
' Find the data sheet
Set wsData = Nothing
On Error Resume Next
Set wsData = Worksheets(CStr(dataSheet))
On Error GoTo 0
' Did we find the sheet
If Not wsData Is Nothing Then
' Clear out the buckets
For thisCol = 0 To 3
buckets(thisCol) = 0
Next thisCol
' Find the last row of data
lastRow = wsData.Cells(wsData.Rows.Count, 1).End(xlUp).Row
' Find the last column
lastCol = wsData.Cells(HEADER_ROW, wsData.Columns.Count).End(xlToLeft).Column
' Work through all rows
For thisRow = HEADER_ROW + 1 To lastRow
' Reset the average for this row and the number of headers matched
rowAverage = 0
headerCount = 0
' Decide if this row is valid
validRow = True
' Process all columns on this row
For thisCol = 1 To lastCol
' Is the header on this column in the list of headers?
If Not IsError(Application.Match(wsData.Cells(HEADER_ROW, thisCol).Value, wsReport.Range(CRITERIA_RANGE), 0)) Then
' Yes it is - accumulate this value and add 1 to the header count
headerCount = headerCount + 1
rowAverage = rowAverage + wsData.Cells(thisRow, thisCol).Value
End If
' Does this match the extra criteria?
If wsReport.Range(EXTRA_CRITERIA_VALUE).Value <> "" Then
If wsData.Cells(HEADER_ROW, thisCol).Value = wsReport.Range(EXTRA_CRITERIA_VALUE).Value Then
If IsError(Application.Match(wsData.Cells(thisRow, thisCol).Value, wsReport.Range(EXTRA_CRITERIA_RANGE), 0)) Then
validRow = False
ElseIf INCLUDE_EXTRA_CRITERIA_IN_AVERAGE Then
headerCount = headerCount + 1
rowAverage = rowAverage + wsData.Cells(thisRow, thisCol).Value
End If
End If
End If
Next thisCol
If validRow Then
' Divide the total by the number of headers
rowAverage = rowAverage / headerCount
' Decide which bucket to put the row in
If rowAverage >= wsReport.Range(BUCKET_VALUES)(1).Value Then
buckets(0) = buckets(0) + 1
ElseIf rowAverage >= wsReport.Range(BUCKET_VALUES)(2).Value Then
buckets(1) = buckets(1) + 1
ElseIf rowAverage > wsReport.Range(BUCKET_VALUES)(3).Value Then
buckets(2) = buckets(2) + 1
Else
buckets(3) = buckets(3) + 1
End If
End If
Next thisRow
' Now populate the totals into the table
For thisCol = 0 To 3
wsReport.Range(BUCKET_RANGE).Offset(dataSheet - 1)(thisCol + 1).Value = buckets(thisCol)
Next
End If
Next dataSheet
End Sub