Below is my code; where I try to split column's Code data into different sheets.
My problem is that; I need to enter a new condition to take from Column Orders; where I store numbers from 1-50000 specific range of values each time and produce the final sheets.
For Example : I want the Sheets "101" "102" "501" with data from Column "Orders" ONLY with values=> 0<=value and value=<50.
The "value" to be populated by the user=> "Please Insert Orders from"=> 0
"Please Insert Orders up to"=>50
Thnks in advance!
data
Private Sub Run_Click()
Dim LR As Long
Dim ws As Worksheet
Dim vCol, i, j As Integer
Dim icol As Long
Dim MyArr As Variant
Dim title As String
Dim titlerow As Integer
'1-store user input in 'Fullo' variable
Dim Fullo As String
Fullo = InputBox("Please insert sheet of analysis:", "Collect User Input")
'test input before continuing to validate the input
If Not (Len(Fullo) > 0) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
'2-store user input in 'CN' variable
Dim CN As Integer
CN = InputBox("Please insert column of analysis:", "Collect User Input")
'test input before continuing to validate the input
If Not (Len(CN) > 0 And IsNumeric(CN)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
'3-store user input in 'CN' variable
Dim HKFrom As Integer
HKFrom = InputBox("Please insert Orders from:", "Collect User Input")
'test input before continuing to validate the input
If Not (Len(HKFrom) > 0 And IsNumeric(HKFrom)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
'4-store user input in 'CN' variable
Dim HKUntil As Integer
HKUntil = InputBox("Please insert Orders up to:", "Collect User Input")
'test input before continuing to validate the input
If Not (Len(HKUntil) > 0 And IsNumeric(HKUntil)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
vCol = CN
Set ws = Sheets(Fullo)
'Spot bottom row of data
LR = ws.Cells(ws.Rows.Count, vCol).End(xlUp).Row
'Range where titles are across top of data, as string, data MUST
'have titles in this row, edit to suit your titles locale
title = "A1:H1"
titlerow = ws.Range(title).Cells(1).Row
icol = ws.Columns.Count
ws.Cells(1, icol) = "Unique"
For i = 2 To LR
On Error Resume Next
If ws.Cells(i, vCol) <> "" And Application.WorksheetFunction.Match(ws.Cells(i, vCol), ws.Columns(icol), 0) = 0 Then
ws.Cells(ws.Rows.Count, icol).End(xlUp).Offset(1) = ws.Cells(i, vCol)
End If
'error handling
Next
MyArr = Application.WorksheetFunction.Transpose(ws.Columns(icol).SpecialCells(xlCellTypeConstants))
ws.Columns(icol).Clear
For i = 2 To UBound(MyArr)
ws.Range(title).AutoFilter Field:=vCol, Criteria1:=MyArr(i) & ""
If Not Evaluate("=ISREF('" & MyArr(i) & "'!A1)") Then
Sheets.Add(After:=Worksheets(Worksheets.Count)).Name = MyArr(i) & ""
Else
Sheets(MyArr(i) & "").Move After:=Worksheets(Worksheets.Count)
End If
ws.Range("A" & titlerow & ":A" & LR).EntireRow.Copy Sheets(MyArr(i) & "").Range("A1")
Sheets(MyArr(i) & "").Columns.AutoFit
Next
ws.AutoFilterMode = False
ws.Activate
End Sub
Related
I need to find the match for each cell(C:C)value of sheet1 in sheet2 (C:C) and if the value matches copy the corresponding next cell i.e, D:D and replace in sheet 2. If it does not match then copy and paste the Range A to D in the next empty cell in sheet 2
Sub Method1()
Dim strSearch As String
Dim strOut As String
Dim bFailed As Boolean
Dim i As Integer
strSearch = Sheet1.Range("C2")
i = 1
Do Until ActiveCell.Value = Empty
ActiveCell.Offset(1, 0).Select 'move down 1 row
i = i + 1 'keep a count of the ID for later use
Loop
'ActiveCell.Value = i
On Error Resume Next
strOut = Application.WorksheetFunction.VLookup(strSearch, Sheet2.Range("C:C"), 2, False)
If Err.Number <> 0 Then bFailed = True
On Error GoTo 0
If Not bFailed Then
MsgBox "corresponding value is " & vbNewLine & strOut
Else
MsgBox strSearch & " not found"
End If
End Sub
Sheet1:`enter code here
Sheet2:
However, I made change to my code and it does the job, but I want to repeat the function for each cell in C:C, have a look
Sub Method1()
Dim strSearch As String
Dim strOut As String
Dim bFailed As Boolean
Dim i As Integer
strSearch = Sheet1.Range("C2")
i = 1
'Do Until ActiveCell.Value = Empty
ActiveCell.Offset(1, 0).Select 'move down 1 row
i = i + 1 'keep a count of the ID for later use
' Loop
'ActiveCell.Value = i
On Error Resume Next
strOut = Application.WorksheetFunction.VLookup(strSearch, Sheet2.Range("C:C"), 1, False)
If Err.Number <> 0 Then bFailed = True
On Error GoTo 0
If Not bFailed Then
Worksheets("Sheet1").Range("e2").Copy
Worksheets("Sheet2").Range("e2").PasteSpecial Paste:=xlPasteFormulas
Application.CutCopyMode = False
ActiveCell.Interior.ColorIndex = 6
MsgBox "corresponding value been copied " & vbNewLine & strOut
Else
MsgBox strSearch & " not found"
End If
End Sub
Try this:
Sub Method1()
Dim cSearch As Range, m
Set cSearch = Sheet1.Range("C2")
Do While Len(cSearch.Value) > 0
'omit the "WorksheetFunction" or this will throw a run-time error
' if there's no match. Instead we check the return value for an error
m = Application.Match(cSearch.Value, Sheet2.Range("C:C"), 0)
If Not IsError(m) Then
'got a match - update ColD on sheet2
Sheet2.Cells(m, "D").Value = cSearch.Offset(0, 1).Value
Else
'no match - add row to sheet2 (edit)
cSearch.Offset(0, -2).Resize(1, 4).Copy _
Sheet2.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
End If
Set cSearch = cSearch.Offset(1, 0) 'next value to look up
Loop
End Sub
First off, ill give credit where credit is due. This is put together using code from u/Joe Was from Mr.Excel.com and exceltip.com.
Now that I have gotten that out of the way I am trying to create a search function that will search through my 9 sheet document in excel, to find a value that was typed into a search box. Then paste those values onto the first page of the workbook.
What do I need to change in my code to make it paste to the right place on the search page? I have tried changing things in the last loop because that is where I get the "Run-Time error 91. Object variable or with block variable not set".
I've googled that error, but variables always screw me up so that may be the problem.
The search page.
This is where the Debugger stops.
This is my code so far.
Sub Find_one()
'Find Function For ERF Spreadsheet'
'Type in Box, Press Button, Display the Results'
Dim ws As Worksheet, Found As Range
Dim myText As String, FirstAddress As String
Dim AddressStr As String, foundNum As Integer
myText = Range("D5")
If myText = "" Then Exit Sub
For Each ws In ThisWorkbook.Worksheets
With ws
'Do not search sheet1'
If ws.Name = "Sheet1" Then GoTo myNext
Set Found = .UsedRange.Find(What:=myText, LookIn:=xlValues, LookAt:=xlPart, MatchCase:=False)
If Not Found Is Nothing Then
FirstAddress = Found.Address
Do
foundNum = foundNum + 1
AddressStr = AddressStr & .Name & " " & Found.Address & vbCrLf
Set Found = .UsedRange.FindNext(Found)
'Found.EntireRow.Copy _
'Destination:=Worksheets("Sheet4").Range("A65536").End(xlUp).Offset(1, 0)
Loop While Not Found Is Nothing And Found.Address <> FirstAddress
End If
myNext:
End With
Next ws
If Len(AddressStr) Then
Sheet8.Range("B18") = ws.Cells(x, 1)
Sheet8.Range("C18") = ws.Cells(x, 2)
Sheet8.Range("D18") = ws.Cells(x, 3)
Sheet8.Range("E18") = ws.Cells(x, 4)
Sheet8.Range("F18") = ws.Cells(x, 5)
Sheet8.Range("G18") = ws.Cells(x, 6)
Sheet8.Range("H18") = ws.Cells(x, 7)
Sheet8.Range("I18") = ws.Cells(x, 8)
Sheet8.Range("J18") = ws.Cells(x, 9)
Else:
MsgBox "Unable to find " & myText & " in this workbook.", vbExclamation
End If
End Sub
This is the original code for the last loop...
If Len(AddressStr) Then
MsgBox "Found: """ & myText & """ " & foundNum & " times." & vbCr & _
AddressStr, vbOKOnly, myText & " found in these cells"
Else:
MsgBox "Unable to find " & myText & " in this workbook.", vbExclamation
End If
Here, try this out. I redid how I interpreted the first section. I'm not entirely sure what you're trying to do with everything so let me know if this works or where it went wrong.
Sub FindOne()
Dim k As Integer
Dim myText As String, searchColumn As String
Dim totalValues As Long
Dim nextCell As Range
k = ThisWorkbook.Worksheets.Count
myText = Sheets(1).Range("D5").Value
If myText = "" Then
MsgBox "No Address Found"
Exit Sub
End If
Select Case ComboBox1.Value
Case "Equipment Number"
searchColumn = "A"
Case "Sequence Number"
searchColumn = "B"
Case "Repair Order Number(s)"
searchColumn = "D"
Else
MsgBox "Please select a value for what you are searching by."
End Sub
End Select
For i = 2 To k
totalValues = Sheets(i).Range("A65536").End(xlUp).Row
ReDim AddressArray(totalValues) As String
For j = 0 To totalValues
AddressArray(j) = Sheets(i).Range(searchColumn & j + 1).Value
Next j
For j = 0 To totalValues
If (InStr(1, AddressArray(j), myText) > 0) Then
Set nextCell = Sheets(1).Range("A65536").End(xlUp).Offset(1, 0)
Range(nextCell, nextCell.Offset(0, 8)).Value = Sheets(i).Range("A" & j, "I" & j).Value
End If
Next j
Next i
End Sub
Also I have no clue what that second part of the code is supposed to be, so if you want to elaborate on the section with If Len(AddressStr) Then, I'd appreciate it because that really doesn't even work as an If...Then statement lol :)
As you saw from the title I am getting error 1004. I am trying to make it iterate through cells B4 to B9 and at each one and if there is no sheet with the name in that cell it creates it and pastes the headers that are on the data entry page (C1:M3) and the data on that row from C to I onto the newly created sheet. If it does exist it looks at A1 of the sheet with that name and pastes the data into column B and the row that A1 specifies. And it does this for B4:B9 on each cell. Any help would be appreciated.
Function copyHeader(inputrange As String, inputsheet As String, outputcell As String, outputsheet As String)
Sheets(inputsheet).Range(inputrange).Copy Destination:=Sheets(outputsheet).Range(outputcell)
Application.CutCopyMode = False
Cells(1, 1).Value = 4 'probably better to make this dynamic
End Function
Function copyDetail(inputrange As String, inputsheet As String, outputcell As String, outputsheet As String)
Sheets(inputsheet).Range(inputrange).Copy Destination:=Sheets(outputsheet).Range(outputcell)
Application.CutCopyMode = False
Cells(1, 1).Value = 4 'probably better to make this dynamic
End Function
Function createTab(tabname As String)
Worksheets.Add.Name = tabname
End Function
Function shtExists(shtname As String) As Boolean
Dim sht As Worksheet
On Error GoTo ErrHandler:
Set sht = Sheets(shtname)
shtExists = True
ErrHandler:
If Err.Number = 9 Then
shtExists = False
End If
End Function
Public Function lastCell(Col As String)
With ActiveSheet
lastCell = .Cells(.Rows.Count, Col).End(xlUp).Row
End With
End Function
Sub AddData()
Dim teamname As String
Dim countery As Integer
Dim teamdata As String
Dim matchcounter As String
Dim resp As Boolean
Dim maxCounter As Integer
counter = 4
maxCounter = lastCell("B")
On Error GoTo eh
For counter = 4 To maxCounter
ThisWorkbook.Sheets("DataEntry").Select
teamdata = "C" & counter & ":" & "N" & counter
teamname = ThisWorkbook.Sheets("DataEntry").Range("B" & counter).Value
resp = shtExists(teamname)
If resp = False Then
createTab (teamname)
copyHeader "C1:M3", "DataEntry", "B1", teamname
matchcounter = CStr(Sheets(teamname).Range("A1").Value)
copyDetail teamdata, "DataEntry", "B" & matchcounter, teamname
ElseIf resp = True Then
copyDetail teamdata, "DataEntry", "B" & matchcounter, teamname
End If
Next counter
Worksheets("DataEntry").Activate
Done:
Exit Sub
eh:
MsgBox "The following error occurred: " & Err.Description & " " & Err.Number & " " & Err.Source
End Sub
Here is what my data entry sheet looks like:
https://i.stack.imgur.com/NYo0P.png
Here is what the sheets that I am creating for each team look like:
https://i.stack.imgur.com/JaBfX.png
I've mocked this up here and tweaked your code to get it working. It isn't necessarily how I'd do it normally, (I wouldn't bother storing the destination row in A1 for instance - I'd detect the bottom and add there) but it works and should
a) make sense to you and
b) work with your data structure.
Option Explicit
Sub copyHeader(inputrange As String, inputsheet As String, outputcell As String, outputsheet As String)
Sheets(inputsheet).Range(inputrange).Copy Destination:=Sheets(outputsheet).Range(outputcell)
Application.CutCopyMode = False
Cells(1, 1).Value = 4 'probably better to make this dynamic
End Sub
Sub copyDetail(inputrange As String, inputsheet As String, outputcell As String, outputsheet As String)
Sheets(inputsheet).Range(inputrange).Copy Destination:=Sheets(outputsheet).Range(outputcell)
Application.CutCopyMode = False
Sheets(outputsheet).Cells(1, 1).Value = Sheets(outputsheet).Cells(1, 1).Value + 1
End Sub
Sub createTab(tabname As String)
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = tabname
End Sub
Function shtExists(shtname As String) As Boolean
Dim sht As Worksheet
On Error GoTo ErrHandler:
Set sht = Sheets(shtname)
shtExists = True
ErrHandler:
If Err.Number = 9 Then
shtExists = False
End If
End Function
Public Function lastCell(sht As Worksheet, Col As String)
With sht
lastCell = .Cells(.Rows.Count, Col).End(xlUp).Row
End With
End Function
Sub AddData()
Dim teamname As String
Dim counter As Integer
Dim teamdata As String
Dim matchcounter As String
Dim resp As Boolean
Dim maxCounter As Integer
Dim sourcesheet As Worksheet
counter = 4
Set sourcesheet = ThisWorkbook.Sheets("DataEntry")
maxCounter = lastCell(sourcesheet, "B")
On Error GoTo eh
For counter = 4 To maxCounter
sourcesheet.Select
teamdata = "C" & counter & ":" & "N" & counter
teamname = sourcesheet.Range("B" & counter).Value
resp = shtExists(teamname)
If resp = False Then
createTab (teamname)
copyHeader "C1:M3", sourcesheet.Name, "B1", teamname
matchcounter = CStr(Sheets(teamname).Range("A1").Value)
copyDetail teamdata, sourcesheet.Name, "B" & matchcounter, teamname
ElseIf resp = True Then
matchcounter = CStr(Sheets(teamname).Range("A1").Value)
copyDetail teamdata, sourcesheet.Name, "B" & matchcounter, teamname
End If
Next counter
Worksheets("DataEntry").Activate
Done:
Exit Sub
eh:
MsgBox "The following error occurred: " & Err.Description & " " & Err.Number & " " & Err.Source
End Sub
I know this has been asked several times but I'm quite confused on how to put the negative values for my column L:L in a loop. I can't get it to work. I've tried everything I researched. I'd appreciate any help.
Option Explicit
Sub Importpaymentsales()
Dim fpath As Variant
Dim wb As Excel.Workbook
Dim ws As Excel.Worksheet
Dim Text As String
On Error GoTo terminatemsg
Set wb = Excel.ActiveWorkbook
Set ws = Excel.ActiveSheet
fpath = Application.GetOpenFilename(Filefilter:="text Files(*.txt; *.txt), *.txt; *.txt", Title:="Open Prepayment Sales Report")
If fpath = False Then Exit Sub
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Text = getTextfileData(fpath)
If Len(Text) Then
ProcessData Text
AdjustDates
Else
MsgBox fpath & " is empty", vbInformation, "Import Cancelled"
Exit Sub
End If
ws.Range("J:L").Value = ws.Range("J:L").Value
ws.Range("J:L").numberformat = "#,##0.00"
ws.Range("O:Q").Value = ws.Range("O:Q").Value
ws.Range("O:Q").numberformat = "#,##0.00"
Columns.EntireColumn.AutoFit
Sheets(1).Move Before:=wb.Sheets(1)
terminatemsg:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
If Err.Number <> 0 Then MsgBox Err.Number & " " & Err.Description
End Sub
Sub ProcessData(Text As String)
Dim x As Long, y As Long, z As Long
Dim data, vLine
data = Split(Text, vbCrLf)
x = 2
Range("A1:R1").Value = Array("Supplier Name", "Supplier Number", "Inv Curr Code CurCode", "Payment CurCode", "Invoice Type", "Invoice Number", "Voucher Number", "Invoice Date", "GL Date", "Invoice Amount", "Withheld Amount", "Amount Remaining", "Description", "Account Number", "Invoice in USD", "Withheld in USD", "Amt in USD", "User Name")
For y = 0 To UBound(data)
If InStr(data(y), "|") Then
vLine = Split(data(y), "|")
If Not Trim(vLine(0)) = "Supplier" Then
For z = 0 To UBound(vLine)
vLine(z) = Trim(vLine(z))
If vLine(z) Like "*.*.*.*.*.*.*.*.*.*.*.*.*.*.*" Then vLine(z) = Left(vLine(z), InStr(vLine(z), ".") + 2)
Next
Cells(x, 1).Resize(1, UBound(vLine) + 1).Value = vLine
x = x + 1
'Range("L2:L").Value = Range("L2:L").Value * (-1)
Range("L2:L").Value = Abs(rng.Offset(teller - 1, -2).Value) * -1
End If
End If
Next
End Sub
Try this:
Dim r As Range
For Each r In Range(Range("L2"), Range("L2").End(xlDown))
If IsNumeric(r.Value) Then r.Value = -Abs(r.Value)
Next
ps: I suppose you don't have blank cells in-between in column L, if you do then a slight modification is needed.
Here it is:
Dim r As Range
For Each r In Range(Range("L2"), Range("L" & Rows.Count).End(xlUp))
If Not IsEmpty(r.Value) Then If IsNumeric(r.Value) Then r.Value = -Abs(r.Value)
Next
I'm just about finished writing this Sub for Excel. I'm basically asking my end user for a total (for example, $3000) find the total amount spent by each customer on the list and report those whose total is more than $3000 (the amount provided by the user) on a new worksheet that I created called Report.
I have this code written so far, which also validates the value entered by the user:
Sub Userinput()
Dim myValue As Variant
myValue = InputBox("Give me some input")
Range("E1").Value = myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
End Sub
Any suggestions on how I can use the inputted value to search through the customer data base and find more than what was inputted and place that in a new worksheet?
EDIT:
Data sample:
Customer orders
Order Date Customer ID Amount purchased
02-Jan-12 190 $580
02-Jan-12 144 $570
03-Jan-12 120 $1,911
03-Jan-12 192 $593
03-Jan-12 145 $332
try this
Sub Userinput()
Dim cl As Range, cl2 As Range, key, myValue
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
dic.comparemode = vbTextCompare
myValue = InputBox("Give me some input")
[E1].Value = "Amount Limit: " & myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
For Each cl In Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row)
If Not dic.exists(cl.Value) Then
dic.Add cl.Value, Nothing
End If
Next cl
Set cl = Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row)
Set cl2 = Range("C2:C" & Cells(Rows.Count, "B").End(xlUp).Row)
[E2] = ""
For Each key In dic
If WorksheetFunction.SumIf(cl, key, cl2) > myValue Then
If [E2] = "" Then
[E2] = "Customer ID: " & key
Else
[E2] = [E2] & ";" & key
End If
End If
Next key
Set dic = Nothing
End Sub
output
update
Sub Userinput()
Dim cl As Range, cl2 As Range, key, myValue, i&
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
dic.comparemode = vbTextCompare
myValue = InputBox("Give me some input")
With Sheets("Source")
.[E1].Value = "Amount Limit: " & myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
myValue = CDec(myValue)
For Each cl In .Range("B2:B" & .Cells(.Rows.Count, "B").End(xlUp).Row)
If Not dic.exists(cl.Value) Then
dic.Add cl.Value, Nothing
End If
Next cl
Set cl = .Range("B2:B" & .Cells(.Rows.Count, "B").End(xlUp).Row)
Set cl2 = .Range("C2:C" & .Cells(.Rows.Count, "B").End(xlUp).Row)
Sheets("Destination").UsedRange.ClearContents
Sheets("Destination").[A1] = "Customer ID": i = 2
For Each key In dic
If WorksheetFunction.SumIf(cl, key, cl2) > myValue Then
Sheets("Destination").Cells(i, "A") = key: i = i + 1
End If
Next key
End With
Set dic = Nothing
End Sub
output
You may try this. I assume you need copied into worksheet in same workbook
Option Explicit
Dim MyWorkbook As Workbook
Dim MyWorksheet As Worksheet
Dim MyOutputWorksheet As Worksheet
Sub Userinput()
Set MyWorkbook = Workbooks(ActiveWorkbook.Name)
Set MyWorksheet = MyWorkbook.Sheets("WorksheetName")
Set MyOutputWorksheet = MyWorkbook.Sheets("OutputWorksheetName")
Dim myValue As Long
Dim RowPointer As Long
myValue = InputBox("Give me some input")
MyWorksheet.Range("E1").Value = myValue
'conditional checking
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
For RowPointer = 2 To MyWorksheet.Cells(Rows.Count, "C").End(xlUp).Row
If MyWorksheet.Range("C" & RowPointer).Value > MyWorksheet.Range("E1").Value Then
MyWorksheet.Range(("A" & RowPointer) & ":C" & RowPointer).Copy Destination:=MyOutputWorksheet.UsedRange.Offset(1, 0)
'MyOutputWorksheet.UsedRange.Offset(1, 0).Value = MyWorksheet.Rows(RowPointer, 1).EntireRow.Value
End If
Next RowPointer
End Sub
Here is another approach which takes advantage of straight forward Excel features to Copy the customer IDs column, RemoveDuplicates, SUMIF based on customer, and Delete those rows over the minimum.
Sub CopyFilterAndCountIf()
Dim dbl_min As Double
dbl_min = InputBox("enter minimum search")
Dim sht_data As Worksheet
Dim sht_out As Worksheet
Set sht_data = ActiveSheet
Set sht_out = Worksheets.Add()
sht_data.Range("B:B").Copy sht_out.Range("A:A")
sht_out.Range("A:A").RemoveDuplicates 1, xlYes
Dim i As Integer
For i = sht_out.UsedRange.Rows.Count To 2 Step -1
If WorksheetFunction.SumIf( _
sht_data.Range("B:B"), sht_out.Cells(i, 1), sht_data.Range("C:C")) < dbl_min Then
sht_out.Cells(i, 1).EntireRow.Delete
End If
Next
End Sub
I don't do error checking on the input, but you can add that in. I am also taking advantage of Excel's willingness to process entire columns instead of dealing with finding ranges. Definitely makes it easier to understand the code.
It should also be mentioned that you can accomplish all of these same features by using a Pivot Table with a filter on the Sum and no VBA.