Case without select case error compile error - excel

Hello I keep getting a compile error on this segment of my code and can't find what i'm missing:
Case 5 ' Base oil specification changes?
' search datatbl for next empty row
rw = data.Range.Rows.Count
If rw = 2 Then
If data.Range(rw, 1).Value = "" Then
rw = 1
Else
data.Range(rw, 1).ListObject.ListRows.Add alwaysinsert:=True
End If
End If
'populate the data table
With data
.Range(rw, 1).Offset(1) = Date
.Range(rw, 2).Offset(1) = "A"
.Range(rw, 3).Offset(1) = "Marketing"
.Range(rw, 4).Offset(1) = Me.Controls("lblA" & i).Caption
End With
If Me.Controls("OptA" & i & "Y") = True Then
With data
.Range(rw, 5).Offset(1) = Me.Controls("OptA" & i & "Y").Caption
.Range(rw, 6).Offset(1) = Me.Controls("txtA" & i).Value
.Range(rw, 7).Offset(1) = "PLANT"
End With
'add data to summary table
r = summary.Range.Rows.Count
If r = 2 Then
If summary.Range(r, 1).Value = "" Then
r = 1
Else
summary.Range(r, 1).ListObject.ListRows.Add alwaysinsert:=True
End If
End If
With summary
.Range(r, 1).Offset(1) = Me.Controls("lblA" & i).Caption
.Range(r, 2).Offset(1) = Me.Controls("OptA" & i & "Y").Caption
.Range(r, 3).Offset(1) = Me.Controls("txtA" & i).Value
.Range(r, 4).Offset(1) = "PLANT"
End With
ElseIf Me.Controls("OptA" & i & "N") = True Then
data.Range(rw, 5).Offset(1) = Me.Controls("OptA" & i & "N").Caption
End If

You need to add Select Case in order to use the Case method followed by the object that is being analyzed. Once complete, end with End Select.
Generic example below showing how to implement the basics of Select Case where the object to be analyzed is Range("A1")
Select Case Range("A1")
Case 5
'Do something if case is met
Case Else
'Do something is case is Else
End Select

Related

Userform Data entry "Update" setting wrong values when editing an entry

So I've got a userform for entering and looking up customer information, Everythign seems to currently work, except for the "Update" Button. When utilizing the update button, its changing my city and state values to my zipcode value, aswell as adjusting whatever else was changed. City and state should not be changing to my zipcode value. city and state values are populated utilizing a vlookup within a zipcodedata tab.
Below is the code for my update button:
Private Sub UpdateButton_Click()
If Me.CustID.Value = "" Then
MsgBox "Select customer record to update!"
Exit Sub
End If
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("Customer Database")
Dim Selected_Row As Long
Selected_Row = Application.WorksheetFunction.Match(CLng(Me.CustID.Value), ThisWorkbook.Worksheets("Customer Database").Range("A:A"), 0)
'Validations-----------------------------------------------------
If Me.CustomerName.Value = "" Then
MsgBox "Plese enter the customers name!", vbCritical
Exit Sub
End If
'-------
If Me.CustomerBusiness.Value = "" Then
MsgBox "Plese enter the customers business!", vbCritical
Exit Sub
End If
'-------
If Me.CustomerAddress.Value = "" Then
MsgBox "Plese enter the customers address!", vbCritical
Exit Sub
End If
'-------
If Me.CustomerPhone.Value = "" Then
MsgBox "Plese enter the customers phone number!", vbCritical
Exit Sub
End If
'----------------------------------------------------------------
sh.Range("B" & Selected_Row).Value = Me.CustomerName.Value
sh.Range("C" & Selected_Row).Value = Me.CustomerBusiness.Value
sh.Range("D" & Selected_Row).Value = Me.CustomerAddress.Value
sh.Range("E" & Selected_Row).Value = Me.City.Value
sh.Range("F" & Selected_Row).Value = Me.State.Value
sh.Range("G" & Selected_Row).Value = Me.Zipcode.Value
sh.Range("H" & Selected_Row).Value = Me.CustomerPhone.Value
sh.Range("I" & Selected_Row).Value = Me.CustomerEmail.Value
sh.Range("J" & Selected_Row).Value = Me.MachineSerial1.Value
sh.Range("K" & Selected_Row).Value = Me.MachineSerial2.Value
sh.Range("L" & Selected_Row).Value = Me.MachineSerial3.Value
'----------------------------------------------------------------
Me.CustomerName.Value = ""
Me.LCaseName.Value = ""
Me.CustomerBusiness.Value = ""
Me.CustomerAddress.Value = ""
Me.Zipcode.Value = ""
Me.City.Value = ""
Me.State.Value = ""
Me.CustomerPhone.Value = ""
Me.CustomerEmail.Value = ""
Me.MachineSerial1.Value = ""
Me.MachineSerial2.Value = ""
Me.MachineSerial3.Value = ""
Me.CustID.Value = ""
'----------------------------------------------------------------
Call Refresh
End Sub
Here is the code for populating the City and State text boxes:
Private Sub Zipcode_Change()
Dim rng As Range
Dim a As Integer
On Error Resume Next
a = 0
Set rng = Worksheets("ZipCodeData").Range("ZipCodes")
Lastrow = Worksheets("ZipCodeData").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To Lastrow
If Me.Zipcode = Worksheets("ZipCodeData").Cells(i, 1).Value Then
a = a + 1
End If
Next
If a >= 1 Then
Me.City.Value = Application.WorksheetFunction.VLookup(Zipcode.Value, rng, 2, 0)
Me.State.Value = Application.WorksheetFunction.VLookup(Zipcode.Value, rng, 3, 0)
End If
If a = 0 Then
Me.City.Value = ""
Me.State.Value = ""
End If
End Sub
I've tried commenting out my "Zipcode_Change" sub, as I thought perhaps it was having issues interpreting the vlookup values when utilizing the update feature. I have a "add" button (which is identical to the update button, except the Selected_Row is a Last_Row. The "Add" button functions and works as intended, so I recopied my "Add" button code and readjusted it for the update button, and the issue persists.

Fast way to compare two excel files?

I want to compare 2 excels files [Having only 1 sheet in both] having 10-15 columns and rows will be more than 30K. We got one excel macro file which complete the comparison within 5-10Mins. Limitation of this macro is that it can compare only 2-3 columns at a time. So every time we need to run this macro multiple times which is time consuming process. So I created one utility file [.vbs file] which perform this task in one go but it takes around 1-3Hrs.
Is there any other way to perform this comparison in short time in one go?
startTime=Timer()
Set objExcel=Createobject("Excel.application")
objExcel.Visible=True
Set objWorkbook=objExcel.Workbooks.Open("E:\QTP trial version\Data.xls")
'Set deleteAnalysis_CopySheet=objWorkbook.sheets("Analysis_Copy")
'deleteAnalysis_CopySheet.delete
'Set deleteSummarySheet=objWorkbook.sheets("Summary")
'deleteSummarySheet.delete
Set objAnalysis_Copy=objWorkbook.sheets.add
objAnalysis_Copy.name="Analysis_Copy"
Set objSummary=objWorkbook.sheets.add
objSummary.name="Summary"
objSummary.Cells(1,1)="Analysis Row Count"
objSummary.Cells(2,1)="Reporting Row Count"
objSummary.Cells(3,1)="Analysis Column Count"
objSummary.Cells(4,1)="Reporting Column Count"
objSummary.Cells(5,1)="Difference of Row Count"
objSummary.Cells(6,1)="Difference of Column Count"
objSummary.Cells(7,1)="False Count"
' ------------------------1st Check - Verify the position of ''Metrics' in Analysis and Reporting tab. It must be same---------------------
'Get the control of Analysis tab
Set objAnalysis=objExcel.Worksheets.Item("Analysis")
intAnalysisRowCount=objAnalysis.Usedrange.rows.count
objSummary.Cells(1,2)=intAnalysisRowCount
intAnalysisColCount=objAnalysis.Usedrange.Columns.count
objSummary.Cells(3,2)=intAnalysisColCount
'Get Column number of 'Metric' Column from Analysis tab
For intMetricAnalysis=1 to intAnalysisColCount
If(Trim(Lcase(objAnalysis.Cells(1,intMetricAnalysis)))=Trim(Lcase("Metrics"))) Then
Exit for
End If
Next
'Get all Analysis columns in 1 string
strAnalysisColumnOrder=""
For intAnalysisColumnOrder=1 to intAnalysisColCount
strAnalysisColumnOrder=strAnalysisColumnOrder&"*"&objAnalysis.Cells(1,intAnalysisColumnOrder)
If(intAnalysisColumnOrder=1) then
strAnalysisColumnOrder=Replace(strAnalysisColumnOrder,"*","")
End If
Next
Set objReporting=objExcel.Worksheets.Item("Reporting")
intReportingRowCount=objReporting.Usedrange.rows.count
objSummary.Cells(2,2)=intReportingRowCount
intReportingColCount=objReporting.Usedrange.Columns.count
objSummary.Cells(4,2)=intReportingColCount
''Get Column number of 'Metric' Column from Reporting tab
For intMetricReporting=1 to intReportingColCount
If(Trim(Lcase(objReporting.Cells(1,intMetricReporting)))=Trim(Lcase("Metrics"))) Then
Exit for
End If
Next
'Get all Reporting columns in 1 string
strReportingColumnOrder=""
For intReportingColumnOrder=1 to intAnalysisColCount
strReportingColumnOrder=strReportingColumnOrder&"*"&objReporting.Cells(1,intReportingColumnOrder)
If(intReportingColumnOrder=1) then
strReportingColumnOrder=Replace(strReportingColumnOrder,"*","")
End If
Next
''Metric' column number must be same
If(intMetricAnalysis<>intMetricReporting) then
msgbox "Merics column is at "&intMetricAnalysis&" position in 'Analysis' Tab And at "&intMetricReporting&" position in 'Reporting' tab. 'Metrics' column should be at same position in both tab."
strMetricsFlag=False
Else
strMetricsFlag=True
End IF
'-----------2nd Check, Verify count of columns in 'Analysis' And 'Reporting' tab . It Must be same
If intAnalysisColCount<>intReportingColCount Then
msgbox "Column count of 'Reporting' Tab is not same as of 'Analysis tab'."
strAnalysisColCount=False
Else
strAnalysisColCount=True
End If
''---------------3rd Check , Verify Order of columns in 'Analysis' And 'Reporting' tab . It Must be same
If Trim(Lcase(strAnalysisColumnOrder))<>Trim(Lcase(strReportingColumnOrder)) then
msgbox "Column order of 'Reporting' Tab is not same as of 'Analysis tab'. Reporting column order should be "&strAnalysisColumnOrder
strAnalysisColumnOrderFlag=False
Else
strAnalysisColumnOrderFlag=True
End IF
'Creare 'Analysis_Copy' tab and add headers
Set objAnalysisCopy=objExcel.Worksheets.Item("Analysis_Copy")
strFirstCoulmn_AggKeys=""
For intHeaderAggkey=1 to intMetricAnalysis-1
strFirstCoulmn_AggKeys=strFirstCoulmn_AggKeys&"*"&objAnalysis.Cells(1,intHeaderAggkey)
If(intHeaderAggkey=1) then
strFirstCoulmn_AggKeys=Replace(strFirstCoulmn_AggKeys,"*","")
End If
Next
objAnalysisCopy.Cells(1,1)=strFirstCoulmn_AggKeys
strSecondCoulmn_AnalysisMetrics=""
For intHeaderAnalysisMetrics=intMetricAnalysis+1 to intAnalysisColCount
strSecondCoulmn_AnalysisMetrics=strSecondCoulmn_AnalysisMetrics&"*"&objAnalysis.Cells(1,intHeaderAnalysisMetrics)
If(intHeaderAnalysisMetrics=intMetricAnalysis+1 ) then
strSecondCoulmn_AnalysisMetrics=Replace(strSecondCoulmn_AnalysisMetrics,"*","")
End If
Next
objAnalysisCopy.Cells(1,2)="Analysis_"&strSecondCoulmn_AnalysisMetrics
objAnalysisCopy.Cells(1,3)="Reporting_"&strSecondCoulmn_AnalysisMetrics
objAnalysisCopy.Cells(1,4)="Status"
objWorkbook.Save
'$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
If strAnalysisColumnOrderFlag=False OR strMetricsFlag=False OR strAnalysisColCount=False Then
msgbox "So Data Comparision can not be done"
objWorkbook.Save
objWorkbook.Close
objExcel.Quit
Else
intFalseCount=0
For intAnalysisRow=2 to intAnalysisRowCount
' ------ Get the control of ''Analysis' tab and the string of Aggrecate Keys [strAnalysisAggrData] and respective metrics [strAnalysisMetricsData]
Set objAnalysis=objExcel.Worksheets.Item("Analysis")
' Append all data of each row which is before 'Metrics' column
strAnalysisAggrData=""
For intAnalysisColumn=1 to intMetricAnalysis-1
strAnalysisAggrData=strAnalysisAggrData&"*"&objAnalysis.Cells(intAnalysisRow,intAnalysisColumn)
If(intAnalysisColumn=1) then
strAnalysisAggrData=Replace(strAnalysisAggrData,"*","")
End If
Next
' ' Append all data of each row which is after 'Metrics' column
strAnalysisMetricsData=""
For intFromMetric=intMetricAnalysis+1 to intAnalysisColCount
strAnalysisMetricsData=strAnalysisMetricsData&"*"&objAnalysis.Cells(intAnalysisRow,intFromMetric)
If(intFromMetric=intMetricAnalysis+1 ) then
strAnalysisMetricsData=Replace(strAnalysisMetricsData,"*","")
End If
Next
' ------ Get the control of ''Reporting' tab and the string of Aggrecate Keys [strAnalysisAggrData] and respective metrics [strAnalysisMetricsData]
Set objReporting=objExcel.Worksheets.Item("Reporting")
For intReportingRow=1 to intReportingRowCount
' Append all data of each row which is before 'Metrics' column
strReportingAggrData=""
For intBeforeMetricReporting=1 to intMetricReporting-1
strReportingAggrData=strReportingAggrData&"*"&objReporting.Cells(intReportingRow,intBeforeMetricReporting)
If(intBeforeMetricReporting=1) then
strReportingAggrData=Replace(strReportingAggrData,"*","")
End If
Next
' Append all data of each row which is after 'Metrics' column
strReportingMetricsData=""
For intFromReportingMetric=intMetricReporting+1 to intReportingColCount
strReportingMetricsData=strReportingMetricsData&"*"&objReporting.Cells(intReportingRow,intFromReportingMetric)
If(intFromReportingMetric=intMetricReporting+1 ) then
strReportingMetricsData=Replace(strReportingMetricsData,"*","")
End If
Next
'------------------------------------------------------------ Actual Comparision will be from here ------------------------------------------
If Trim(LCase(strAnalysisAggrData))=Trim(LCase(strReportingAggrData)) Then
objAnalysisCopy.Cells(intAnalysisRow,1)=strAnalysisAggrData
objAnalysisCopy.Cells(intAnalysisRow,2)=strAnalysisMetricsData
objAnalysisCopy.Cells(intAnalysisRow,3)=strReportingMetricsData
'Compare Metrics Data
If Trim(LCase(strAnalysisMetricsData))=Trim(LCase(strReportingMetricsData)) Then
objAnalysisCopy.Cells(intAnalysisRow,4)="PASS"
objAnalysisCopy.Cells(intAnalysisRow,4).font.color=vbGreen
Else
objAnalysisCopy.Cells(intAnalysisRow,4)="FAIL"
intFalseCount=intFalseCount+1
objAnalysisCopy.Cells(intAnalysisRow,4).font.color=vbRed
End If
Exit For
End If
Next
Next
objSummary.Cells(5,2)=intAnalysisRowCount-intReportingRowCount
objSummary.Cells(6,2)=intAnalysisColCount-intReportingColCount
objSummary.Cells(7,2)=intFalseCount
objSummary.Cells(7,2).font.color=vbRed
objWorkbook.Save
objWorkbook.Close
objExcel.Quit
EndTime=Timer()
TotalTime=EndTime-startTime
msgbox "Data Comparision is Completed. Comparision time is "&TotalTime&"Secs"
End If
Use a dictionary and you avoid the nested loops and only scan each sheet once. For example as a VBA macro (untested)
Sub compare()
Dim wb As Workbook
Dim ws(2) As Worksheet, wsSum As Worksheet, wsCopy As Worksheet
Dim rowCount(2) As Long, colCount(2) As Integer, colMetric(2) As Integer
Dim colsMetric(2) As String, colsAll(2) As String, colsKeys(2) As String
Dim bMetricsFlag As Boolean, bColCountFlag As Boolean, bColOrderFlag As Boolean
Dim i As Long, ar, msg As String, intFalseCount As Long
Dim t0 as Single
t0 = Timer
Set wb = ThisWorkbook
Set ws(1) = wb.Sheets("Analysis")
Set ws(2) = wb.Sheets("Reporting")
Set wsSum = wb.Sheets("Summary")
wsSum.Cells.Clear
wsSum.Range("A1:A7") = WorksheetFunction.Transpose(Array("Analysis Row Count", _
"Reporting Row Count", "Analysis Column Count", "Reporting Column Count", _
"Difference of Row Count", "Difference of Column Count", "False Count"))
Set wsCopy = wb.Sheets("Analysis_Copy")
wsCopy.Cells.Clear
' get stats for each sheet 1-Analyis 2=Reporting
For i = 1 To 2
ar = Stats(ws(i))
rowCount(i) = ar(0)
colCount(i) = ar(1)
colMetric(i) = ar(2)
colsAll(i) = ar(3)
colsMetric(i) = ar(4)
colsKeys(i) = ar(5)
Next
' summary
With wsSum
.Cells(1, 2) = rowCount(1)
.Cells(2, 2) = rowCount(2)
.Cells(3, 2) = colCount(1)
.Cells(4, 2) = colCount(2)
End With
' check stats
'Metric' column number must be same
If colMetric(1) = 0 Or colMetric(2) = 0 Or colMetric(1) <> colMetric(2) Then
msg = "Metrics columns not the same or missing : " & vbCr & _
"Analysis : " & colMetric(1) & vbCr & _
"Reporting : " & colMetric(2)
MsgBox msg, vbCritical
bMetricsFlag = False
Else
bMetricsFlag = True
End If
' Verify count of columns
If colCount(1) <> colCount(2) Then
msg = "Column counts not the same : " & vbCr & _
"Analysis : " & colCount(1) & vbCr & _
"Reporting : " & colCount(2)
MsgBox msg, vbCritical
bColCountFlag = False
Else
bColCountFlag = True
End If
'Verify Order of columns
If colsAll(1) <> colsAll(2) Then
msg = "Column order not the same : " & vbCr & _
"Analysis : " & colsAll(1) & vbCr & _
"Reporting : " & colsAll(2)
MsgBox msg, vbCritical
bColOrderFlag = False
Else
bColOrderFlag = True
End If
With wsCopy
.Cells(1, 1) = colsKeys(1)
.Cells(1, 2) = "Analysis_" & colsMetric(1)
.Cells(1, 3) = "Reporting_" & colsMetric(2)
.Cells(1, 4) = "Status"
End With
' checks OK ?
If bColOrderFlag And bMetricsFlag And bColCountFlag Then
' ok
Else
MsgBox "So Data Comparision can not be done", vbCritical
Exit Sub
End If
' start comparison
Dim dict As Object, m As Long, c As Long, s As String
Dim sKey As String, sMetric As String
Set dict = CreateObject("Scripting.Dictionary")
' scan Reporting sheet to build dictionary
m = colMetric(2)
For i = 1 To rowCount(2)
'join cols up to and after metric col
sMetric = "": sKey = ""
For c = 1 To colCount(2)
s = Trim(ws(2).Cells(i, c))
If c < m Then
If sMetric <> "" Then sMetric = sMetric & "*"
sMetric = sMetric & s
ElseIf c > m Then
If sKey <> "" Then sKey = sKey & "*"
sKey = sKey & s
End If
Next
dict(sKey) = sMetric
Next
' scan Analysis sheet to compare dictionary
m = colMetric(1)
For i = 2 To rowCount(1)
'join cols up to and after metric col
sMetric = "": sKey = ""
For c = 1 To colCount(1)
s = Trim(ws(1).Cells(i, c))
If c < m Then
If sMetric <> "" Then sMetric = sMetric & "*"
sMetric = sMetric & s
ElseIf c > m Then
If sKey <> "" Then sKey = sKey & "*"
sKey = sKey & s
End If
Next
' result
wsCopy.Cells(i, 1) = sKey
wsCopy.Cells(i, 2) = sMetric
wsCopy.Cells(i, 3) = dict(sKey)
' pass or fail
If sMetric = dict(sKey) Then
wsCopy.Cells(i, 4) = "PASS"
wsCopy.Cells(i, 4).Font.Color = vbGreen
Else
wsCopy.Cells(i, 4) = "FAIL"
wsCopy.Cells(i, 4).Font.Color = vbRed
intFalseCount = intFalseCount + 1
End If
Next
With wsSum
.Cells(5, 2) = rowCount(1) - rowCount(2)
.Cells(6, 2) = colCount(1) - colCount(2)
.Cells(7, 2) = intFalseCount
.Cells(7, 2).Font.Color = vbRed
End With
MsgBox i - 2 & " rows scanned " & vbCrLf & _
intFalseCount & " FAILED", vbInformation, Int(Timer - t0) & "seconds"
End Sub
Function Stats(ws As Worksheet) As Variant
Dim c As Integer, ar(5) As Variant, s As String
ar(0) = ws.UsedRange.Rows.Count
ar(1) = ws.UsedRange.Columns.Count
ar(2) = 0 'metric column
ar(3) = "" ' col aggregated
ar(4) = "" ' cols upto not including metric
ar(5) = "" ' cols after metric
For c = 1 To ar(1)
s = LCase(Trim(ws.Cells(1, c)))
If s = "metric" Then
ar(2) = c
End If
' aggregate headers before/after metric
If ar(2) = 0 Then
If ar(4) <> "" Then ar(4) = ar(4) & "*"
ar(4) = ar(4) & s
ElseIf c > ar(2) Then
If ar(5) <> "" Then ar(5) = ar(5) & "*"
ar(5) = ar(5) & s
End If
' aggregate all
If ar(3) <> "" Then ar(3) = ar(3) & "*"
ar(3) = ar(3) & s
Next
Stats = ar
End Function
Test data generator
Sub testdata()
Dim ws As Worksheet, n, r, c, ar
ar = Array("", "Analysis", "Reporting")
For n = 1 To 2
Set ws = Sheets(ar(n))
For r = 1 To 30000
For c = 1 To 15
ws.Cells(r, c) = Chr(64 + c) & r & "_abcdefghijklmnopqrstuvwxyz_"
Next
Next
ws.Cells(1, 10) = "metric" ' col J
Next
MsgBox "test data created"
End Sub

Excel VBA script not working when grouping multiple levels

I have an excel document that runs a VBA script that I use user forms to input data. The script works fine, except for the grouping. There are 2 groups. The first is at the Customer Name, which works fine. The second is at the Effort Name, which does not. It groups the effort, but when grouped it still displays the last row. The developer I hired to write the script said that this error appears to be a bug in Excel or for some reason by design when two groups have the same last row.
Does anyone have a solution?
Images show the macros script and grouping Image of marcos
Image of grouping
Below is the VBA script that was written for creating the effort via user form.
Private Sub ButtonAddEffort_Click()
Dim c As Object
Dim sht As Worksheet
Dim foundrow As Long
Dim blassign As Boolean
Dim x As Long
Dim rowstart As Long
Dim rowend As Long
Dim i As Long
Dim rowstarteffort As Long
If IsNull(Me.txtProjectNumberLocate) Or Me.txtProjectNumberLocate = "" Then
MsgBox "Please enter a project number."
Me.txtProjectNumberLocate.SetFocus
Exit Sub
End If
If IsNull(Me.txtEffortName) Or Me.txtEffortName = "" Then
MsgBox "Please enter an effort name."
Me.txtEffortName.SetFocus
Exit Sub
End If
If Not IsNull(Me.txtStartDate) And Me.txtStartDate <> "" Then
If Not IsDate(Me.txtStartDate) Then
MsgBox "Please enter a valid start date in 'mm/dd/yyyy' format."
Me.txtStartDate.SetFocus
Exit Sub
End If
End If
If Not IsNull(Me.txtFinishDate) And Me.txtFinishDate <> "" Then
If Not IsDate(Me.txtFinishDate) Then
MsgBox "Please enter a valid finish date in 'mm/dd/yyyy' format."
Me.txtFinishDate.SetFocus
Exit Sub
End If
End If
Set sht = Sheets("Sheet1")
Set c = sht.Range("F:F").Find(what:=Me.txtProjectNumberLocate, after:=sht.Cells(1, 6), LookIn:=xlValues, lookat:=xlWhole, searchorder:=xlByRows, searchdirection:=xlPrevious, MatchCase:=False)
If Not c Is Nothing Then
foundrow = c.Row
rowstart = foundrow
rowstarteffort = foundrow
Else
foundrow = 0
End If
If foundrow = 0 Then
MsgBox "Could not find project # " & Me.txtProjectNumberLocate
Exit Sub
End If
''any efforts exist1
Set c = sht.Range("A:A").Find(what:="*", after:=sht.Cells(foundrow, 1), LookIn:=xlValues, lookat:=xlPart, searchorder:=xlByRows, searchdirection:=xlNext, MatchCase:=False)
If Not c Is Nothing Then
foundrownext = c.Row
Else
foundrownext = 0
End If
If foundrownext > foundrow Then
foundrow = foundrownext - 1
End If
'check work order format
For x = 1 To 8
If Not IsNull(Me("txtworkorder" & x)) And Me("Txtworkorder" & x) <> "" Then
If Me("CheckBox" & x) = True Then
If Len(Me("txtWorkOrder" & x)) <> 8 Then
MsgBox "Work order numbers must be in 'xxxx-xxx' format."
Me("txtWorkOrder" & x).SetFocus
Exit Sub
End If
If InStr(1, Me("txtWorkOrder" & x), "-") = 0 Then
MsgBox "Work order numbers must be in 'xxxx-xxx' format."
Me("txtWorkOrder" & x).SetFocus
Exit Sub
End If
If Mid(Me("txtworkorder" & x), 5, 1) <> "-" Then
MsgBox "Work order numbers must be in 'xxxx-xxx' format."
Me("txtWorkOrder" & x).SetFocus
Exit Sub
End If
If InStr(1, Left(Me("txtWorkOrder" & x), 4), "-") <> 0 Then
MsgBox "Work order numbers must be in 'xxxx-xxx' format."
Me("txtWorkOrder" & x).SetFocus
Exit Sub
End If
If InStr(1, Right(Me("txtWorkOrder" & x), 3), "-") <> 0 Then
MsgBox "Work order numbers must be in 'xxxx-xxx' format."
Me("txtWorkOrder" & x).SetFocus
Exit Sub
End If
End If
End If
Next x
i = 0
If foundrownext > 1 Then
sht.Rows(rowstart + 1 & ":" & foundrownext - 1).Select
On Error Resume Next
Selection.Rows.Ungroup
On Error GoTo 0
End If
blassign = False
For x = 8 To 1 Step -1
If Me("CheckBox" & x) = True Then
blassign = True
End If
Next x
If blassign = False Then
sht.Range(foundrow + 1 & ":" & foundrow + 1).EntireRow.Insert shift:=xlDown
sht.Range("B" & foundrow + 1) = Me.txtEffortName
sht.Range("B" & foundrow + 1).Font.Color = 13998939
sht.Range("B" & foundrow + 1).Font.Underline = True
sht.Range("I" & foundrow + 1) = Me.txtStartDate
sht.Range("J" & foundrow + 1) = Me.txtFinishDate
i = 1
Else
sht.Range(foundrow + 1 & ":" & foundrow + 1).EntireRow.Insert shift:=xlDown
sht.Range("B" & foundrow + 1) = Me.txtEffortName
sht.Range("B" & foundrow + 1).Font.Color = 13998939
sht.Range("B" & foundrow + 1).Font.Underline = True
sht.Range("I" & foundrow + 1) = Me.txtStartDate
sht.Range("J" & foundrow + 1) = Me.txtFinishDate
For x = 8 To 1 Step -1
If Me("CheckBox" & x) = True Then
sht.Range(foundrow + 2 & ":" & foundrow + 2).EntireRow.Insert shift:=xlDown
sht.Range("F" & foundrow + 2) = Me("txtWorkOrder" & x)
sht.Range("G" & foundrow + 2) = Me("cmbAssign" & x)
i = i + 1
End If
Next x
End If
''group new efforts
If foundrownext <= 1 Then
foundrownext = rowstart + 1
End If
sht.Rows(foundrow + 2 & ":" & foundrownext + i).Select
Selection.Rows.Group
''ungroup and group old project data
rowend = foundrownext + i - 1
sht.Rows(rowstart + 1 & ":" & rowend).Select
Selection.Rows.Group
''
MsgBox "Done!"
End Sub
Private Sub ButtonClose_Click()
Unload Me
End Sub
Private Sub ComboBox1_Change()
End Sub
Private Sub ComboBox2_Change()
End Sub
Private Sub ComboBox3_Change()
End Sub
Private Sub ComboBox4_Change()
End Sub
Private Sub TextBox9_Change()
End Sub
Private Sub UserForm_Click()
End Sub
Outline (group) in Excel requires a summary row, that depending on the settings you have in your computer, should be placed below (default) or above each outline level.
Your situation
What's happening in your spreadsheet is that you currently have the default settings, i.e. summary row should be below the current outline level. And you're grouping the rows 9,10 and 13.
My guess here is that the developer tried to group effort 1 and effort 2 and it didn't work, because to group effort 2 without leaving an additional row would just look like this:
Note: See the 4 dots on the right of rows 13 to 16
The Excel solution
In this case, you need to toggle the settings so the summary rows are above the detail
How to adjust the settings
Outline settings:
Current configuration:
Adjusted configuration
This would allow to have the summary row above details like this:
And when collapsed:
The VBA solution
Now, about the VBA code you have, although it can certainly be improved, I understand it accomplishes your requirements.
I suggest to specially check these two blocks:
Block # 1:
''group new efforts
If foundrownext <= 1 Then
foundrownext = rowstart + 1
End If
sht.Rows(foundrow + 2 & ":" & foundrownext + i).Select
Selection.Rows.Group
Block #2
''ungroup and group old project data
rowend = foundrownext + i - 1
sht.Rows(rowstart + 1 & ":" & rowend).Select
Selection.Rows.Group
I'd suggest the developer to read this article on how and why to avoid select in Excel VBA.
Please let me know if the solution works and remember to mark the answer (tick the check mark at the left) if it does.

Excel VBA Dynamic filters

I am trying to create dynamic filters based on varying conditions and different criteria. Suppose the user is providing some data like
Sal>100 and sal<1000 and not equal to 500
I am dynamically able to create the string with all the criteria and values and store that in a variable.
Here is the example:
Filter_con has the following value
Criteria1:=">10", Operator:=xlAnd, Criteria2:="<100000000",Operator:=xlFilterValues
When I am trying to execute the code
Selection.AutoFilter Field:=235, Filter_con
I am getting the error:
Run time error: 1004
AutoFilter method of range class failed.
Here is the code
t_lastrow = Cells(Rows.Count, 1).End(xlUp).Row
Range("A3:XFD" & t_lastrow).Select
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or
ActiveSheet.FilterMode Then
Selection.ShowAllData
End If
Filter_Con=">10","<100000000"
Filter_numric_data = Split(Replace(Filter_Con, Chr(34), ""), ",")
UBU = UBound(Filter_numric_data)
Filter_Con = ""
For i__ = 0 To UBU
If i__ <> UBU Then
MsgBox (Filter_numric_data(i__))
Filter_Con = Filter_Con & " Criteria" & i__ + 1 & ":=" &
Filter_numric_data(i__) & ", Operator:=xlAnd,"
Else
Filter_Con = Filter_Con & " Criteria" & i__ + 1 & ":=" &
Filter_numric_data(i__)
End If
Next
Range("A3:XFD" & t_lastrow).Select
Selection.AutoFilter Field:=Filter_Field & "," & Filter_Con
Create a dictionary of all values to be shown. Use the dictionary items as the criteria1 with xlfiltervalues.
Option Explicit
Sub sdfgh()
Dim vals As Variant, i As Long, dict As Object
Set dict = CreateObject("scripting.dictionary")
With Worksheets("sheet1")
If .AutoFilterMode Then .AutoFilterMode = False
vals = .Range(.Cells(2, "IA"), .Cells(.Rows.Count, "IA").End(xlUp)).Value2
For i = LBound(vals, 1) To UBound(vals, 1)
Select Case True
Case vals(i, 1) > 100 And vals(i, 1) < 1000 And vals(i, 1) <> 500
'xlFilterValues requires text
dict.Item(vals(i, 1)) = CStr(vals(i, 1))
Case Else
'do nothing
End Select
Next i
With .Cells(1, "A").CurrentRegion
.AutoFilter field:=235, Criteria1:=dict.items, Operator:=xlFilterValues
End With
End With
End Sub

How to optimize Macro Code That Looks into 2 Worksheets

Problem:
I have 1 Excel Sheet with 2 tabs
Tab 1 = Shipment Package
Tab 2 = Mass Update Steps
I want to go through all the values in column B of Tab 2 one by one.
As I go through each row in Tab 2, I will select and copy the values in column C and D of Tab 2.
After selecting and copying, I want to find Tab 2-column B's corresponding values in Tab 1 column G.
If a match is found, I will select column E of Tab 1 (in row where the match was found), and paste there the values copied from Tab 2.
So far this is the code I have which works. However the values from being searched are hard coded. With the values growing in number in Tab 2, the code is hard to maintain. I would like to optimize it. I have googled several possible solutions. But I keep on getting these run-time errors when declaring or setting the range for the 2 sheets. Here is my code.
Private Sub btn_Updt_Steps_Click()
Dim lastRow As Long
With Sheets("Shipment Package")
.Activate
lastRow = .Range("G65000").End(xlUp).Row
For i = 1 To lastRow
If (InStr(1, .Range("G" & i).Value, "Code 001", vbTextCompare) > 0) Then
Sheets("Mass Update Steps").Activate
ActiveSheet.Range("C4:D4").Select
Selection.Copy
Sheets("Shipment Package").Activate
.Range("E" & i).Select
ActiveSheet.Paste
ElseIf (InStr(1, .Range("G" & i).Value, "Code 002", vbTextCompare) > 0) Then
Sheets("Mass Update Steps").Activate
ActiveSheet.Range("C5:D5").Select
Selection.Copy
Sheets("Shipment Package").Activate
.Range("E" & i).Select
ActiveSheet.Paste
ElseIf (InStr(1, .Range("G" & i).Value, "Code 003", vbTextCompare) > 0) Then
Sheets("Mass Update Steps").Activate
ActiveSheet.Range("C6:D6").Select
Selection.Copy
Sheets("Shipment Package").Activate
.Range("E" & i).Select
ActiveSheet.Paste
End If
Next
End With
NotFoundErr:
Debug.Print "value not found"
End Sub
Solution:
Private Sub btn_Updt_Steps_Click()
Dim i As Long
Dim j As Long
Dim Tab2ColC As String
Dim Tab2ColD As String
Dim Tab1ColE As String
Dim Tab1ColF As String
Tab1 = "Shipment Package"
Tab2 = "Mass Update Steps"
With Worksheets(Tab1)
LastRowTab1 = .Cells(.Rows.Count, "G").End(xlUp).Row 'LastRowInColumn(2, Tab1)
End With
With Worksheets(Tab2)
LastRowTab2 = .Cells(.Rows.Count, "B").End(xlUp).Row 'LastRowInColumn(2, Tab2)
End With
For i = 4 To LastRowTab2
Tab2ColumnB = Trim(Sheets(Tab2).Range("B" & i).Value)
Sheets(Tab2).Activate
If Tab2ColumnB <> "" Then
Tab2ColC = "C" & i
Tab2ColD = "D" & i
ActiveSheet.Range(Tab2ColC, Tab2ColD).Copy
For j = 16 To LastRowTab1
Tab1ColumnG = Trim(Sheets(Tab1).Range("G" & j).Value)
If Tab1ColumnG = Tab2ColumnB Then
Sheets(Tab1).Activate
Tab1ColE = "E" & j
Tab1ColF = "F" & j
Sheets(Tab1).Range(Tab1ColE, Tab1ColF).Select
ActiveSheet.Paste
End If
Next
End If
Next
End Sub
For optimization, you can avoid select statements, activate statements etc. Check the code below.
For i = 1 To lastRow
Application.ScreenUpdating = False
If YourCondn1 Then
Sheets("Mass Update Steps").Range("C4:D4").Copy
Sheets("Shipment Package").Range("E" & i).PasteSpecial xlPasteAll
ElseIf YourCondn2 Then
Sheets("Mass Update Steps").Range("C5:D5").Copy
Sheets("Shipment Package").Range("E" & i).PasteSpecial xlPasteAll
ElseIf YourCondn3 Then
Sheets("Mass Update Steps").Range("C6:D6").Copy
Sheets("Shipment Package").Range("E" & i).PasteSpecial xlPasteAll
End If
Application.ScreenUpdating = True
Next
Adding the code that you require. Hope this will work. I haven't tested it. Please check.
Private Sub btn_Updt_Steps_Click()
'Finding LastRow in Tab 2
Tab1 = "Shipment Package"
Tab2 = "Mass Update Steps"
With Worksheets(Tab2)
LastRowTab2 = .Cells(.Rows.Count, 2).End(xlUp).Row 'LastRowInColumn(2, Tab2)
End With
MatchFound = 0
For i = 1 To LastRowTab2
'checking whether value in tab2 column b is same as tab1 column g
Tab2ColumnB = Trim(Sheets(Tab2).Range("B" & i).Value)
Tab1ColumnG = Trim(Sheets(Tab1).Range("G" & i).Value)
If Tab2ColumnB = Tab1ColumnG Then
Tab2ColumnC = Trim(Sheets(Tab2).Range("C" & i).Value)
Tab2ColumnD = Trim(Sheets(Tab2).Range("D" & i).Value)
Sheets(Tab1).Range("E" & i).Value = Tab2ColumnC
Sheets(Tab1).Range("F" & i).Value = Tab2ColumnD
MatchFound = MatchFound + 1
End If
Next
If MatchFound = 0 Then
MsgBox "No matches found"
ElseIf MatchFound > 0 Then
MsgBox MatchFound & " matches were found."
End If
End Sub
I think you can achieve what you want with simple Excel formulas.
In Shipment Package, type the following into E1 and F1 and then drag formula down:
E1 = VLOOKUP(G1,'Mass Update Steps'!$B$1:$D$20,2,0)
F1 = VLOOKUP(G1,'Mass Update Steps'!$B$1:$D$20,3,0)
NB - you'll need to amend $B$1:$D$20 depending on how much data you have in Mass Update
Finally, this assumes that there is always a match. If not, and you want to get rid of those pesky #N/A values, then update the formuals with ISNA e.g.
E1 = IF(ISNA(VLOOKUP(G1,'Mass Update Steps'!$B$1:$D$4,2,0)),"",VLOOKUP(G1,'Mass Update Steps'!$B$1:$D$4,2,0))
Hope that helps.

Resources