Memory Leak in vba code - vba
I have created an automated macro which takes vehicle crash data from a csv file and automatically creates pivot table,charts and compares it to the previous year.
The code is approximately 1400 lines long and the data of the uploaded csv can be anywhere between 2 to 100 mb csv files with more than 100,000 rows and 36 columns.
The macro runs fine but it makes the machine very very slow and even causes it to crash most of the times. If I tab, to respond to an email, it has a high probability of crashing. Either the macro is continuing to try to do something after running successfully or it is keeping memory tied up after it has finished.
I need a way to optimize this. I have attached 3/4 of the entire macro.
Code:
Dim YEAR_COL, TYPE_COL As String
Dim CITY_COL, COUNTY_COL As String
Dim DOCNUM_COL, MONTH_COL As String
Dim COUNTY_CITY_COL, CRASH_DATE_COL As String
Dim INJ_TYPE_SERIOUS, INJ_TYPE_FATAL As Integer
Dim G_HEIGHT, G_WIDTH As Integer
Dim G_TOP, G_LEFT As Integer
Dim myColor1(12), myColor2(14) As Long
Dim CURR_YEAR As Integer, PREV_YEAR As Integer
Dim YEAR_NOT_FOUND_MSG As String
Dim INJ_TYPE_NOT_FOUND_MSG As String
Dim CATEGORY_TEXT As String
Dim UPLOADED_DATA_SHEET_NAME As String
Dim CURR_YEAR_SHEET_NAME As String
Dim PREV_YEAR_SHEET_NAME As String
Dim FILTERED_DATA_SHEET_NAME As String, DATA_SHEET_NAME As String
Dim SER_FAT_PLOT_SHEET As String
Dim SER_INJ_DATA_SHEET As String, FAT_INJ_DATA_SHEET As String
Dim SER_INJ_PIVOT_SHEET As String, FAT_INJ_PIVOT_SHEET As String
Dim CHART_SHEET As String
Dim CATEGORY_COL_NAME As String, CATEGORY_COL_NAME2 As String
Dim TOTAL_CATEGORIES As Integer, CATEGORY_TYPE As Integer
Dim SER_UNRESTRAINED_COL_NAME As String, FAT_UNRESTRAINED_COL_NAME As String
Dim ALCOHOL_COL_NAME As String, SPEED_COL_NAME As String
Dim TEEN_DRIVER_COL_NAME As String, OLD_DRIVER_COL_NAME As String
Dim DISTRACTION_COL_NAME As String, MOTORCYCLE_COL_NAME As String
Dim CMV_COL_NAME As String, BICYCLE_COL_NAME As String
Dim PEDESTRIAN_COL_NAME As String, LRG_TRUCK_COL_NAME As String
Dim CHART1_TITLE As String, CHART2_TITLE As String
Dim CHART3_TITLE As String, CHART4_TITLE As String
Dim INCREMENT_ROWS As Integer
Dim USE_EXISTING_DATA As Boolean
Private Sub InitializeVars()
TYPE_COL = "MinInjuryTypeID"
YEAR_COL = "Year"
CITY_COL = "City_Name"
COUNTY_COL = "County_Name"
COUNTY_CITY_COL = "County_City"
DOCNUM_COL = "DocumentNumber"
MONTH_COL = "MonthName"
CRASH_DATE_COL = "CrashDate"
INJ_TYPE_SERIOUS = 2
INJ_TYPE_FATAL = 1
CURR_YEAR = year(Now())
PREV_YEAR = CURR_YEAR - 1
TOTAL_YEARS = 5
CURR_YEAR_SHEET_NAME = "" & CURR_YEAR
PREV_YEAR_SHEET_NAME = "" & PREV_YEAR
INCREMENT_ROWS = 7500
' Speed, Alcohol, Unbelted, teen, old, texting, distraction
CATEGORY_TYPE = 0
CATEGORY_COL_NAME = ""
CATEGORY_COL_NAME2 = ""
FAT_UNRESTRAINED_COL_NAME = "unrestrainedFatals"
SER_UNRESTRAINED_COL_NAME = "UnrestrainedInjuries"
SPEED_COL_NAME = "Speed"
ALCOHOL_COL_NAME = "Alcohol"
CMV_COL_NAME = "CMV"
BICYCLE_COL_NAME = "Bicycle"
PEDESTRIAN_COL_NAME = "Pedestrian"
MOTORCYCLE_COL_NAME = "Motorcycle"
TEEN_DRIVER_COL_NAME = "TeenDriverInvolved"
OLD_DRIVER_COL_NAME = "OlderDriverInv"
LRG_TRUCK_COL_NAME = "LrgTruck"
DISTRACTION_COL_NAME = "DistractionInvolved"
YEAR_NOT_FOUND_MSG = "Please enter column name for filtering injury records by Year."
INJ_TYPE_NOT_FOUND_MSG = "Please enter column name for filtering by Injury Type."
G_TOP = 20
G_LEFT = 20
G_WIDTH = 2000
G_HEIGHT = 530
UPLOADED_DATA_SHEET_NAME = "Uploaded Data"
FILTERED_DATA_SHEET_NAME = "Filtered Data"
DATA_SHEET_NAME = "Data"
SER_INJ_DATA_SHEET = "Data(Ser_Injuries)"
FAT_INJ_DATA_SHEET = "Data(Fatalities)"
SER_INJ_PIVOT_SHEET = "Serious Injuries by County_City"
FAT_INJ_PIVOT_SHEET = "Fatalities by County_City"
SER_FAT_PLOT_SHEET = "Ser_Inj_Fatalities_Plot_Data"
CHART_SHEET = "Plots"
' color codes for difference chart
myColor1(1) = RGB(209, 190, 184)
myColor1(2) = RGB(196, 161, 149)
myColor1(3) = RGB(186, 133, 115)
myColor1(4) = RGB(191, 112, 86)
myColor1(5) = RGB(179, 85, 54)
myColor1(6) = RGB(163, 107, 88)
myColor1(7) = RGB(158, 93, 46)
myColor1(8) = RGB(191, 76, 38)
myColor1(9) = RGB(184, 56, 13)
myColor1(10) = RGB(145, 74, 23)
myColor1(11) = RGB(140, 42, 10)
myColor1(12) = RGB(115, 45, 22)
' color codes for total and difference chart
myColor2(1) = RGB(209, 190, 184)
myColor2(2) = RGB(196, 161, 149)
myColor2(3) = RGB(186, 133, 115)
myColor2(4) = RGB(191, 112, 86)
myColor2(5) = RGB(179, 85, 54)
myColor2(6) = RGB(163, 107, 88)
myColor2(7) = RGB(158, 93, 46)
myColor2(8) = RGB(191, 76, 38)
myColor2(9) = RGB(184, 56, 13)
myColor2(10) = RGB(145, 74, 23)
myColor2(11) = RGB(140, 42, 10)
myColor2(12) = RGB(115, 45, 22)
myColor2(13) = RGB(7, 162, 240)
myColor2(14) = RGB(255, 0, 0)
End Sub
Sub RunFullMacro()
Dim strFile As String
With Application
.Calculation = xlManual
.ScreenUpdating = False
.EnableEvents = False
End With
Call InitializeVars
'Call GetYearFromUser
strFile = GetYearForComparison()
Call GetFilterCategory
If USE_EXISTING_DATA = False Then
Call ImportCurrentYearCSV(strFile)
Call MoveDataToProperSheets(CURR_YEAR, CURR_YEAR_SHEET_NAME)
Call MoveDataToProperSheets(PREV_YEAR, PREV_YEAR_SHEET_NAME)
End If
CHART1_TITLE = "Difference in serious injuries" & CATEGORY_TEXT & " (" & PREV_YEAR & " - " & CURR_YEAR & ")"
CHART2_TITLE = "Difference in fatal injuries" & CATEGORY_TEXT & " (" & PREV_YEAR & " - " & CURR_YEAR & ")"
CHART3_TITLE = "Total number of crashes" & CATEGORY_TEXT & " with difference in number of serious injuries by month between " & _
PREV_YEAR & " and " & CURR_YEAR
CHART4_TITLE = "Total number of crashes" & CATEGORY_TEXT & " with difference in number of fatal injuries by month between " & _
PREV_YEAR & " and " & CURR_YEAR
Call CreateInitialDataSheets
Call ConcatenateColumns
Call CreateFilteredDataSheets
Call CreatePivotTables
Call CreatePlots
With Application
.Calculation = xlAutomatic
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Private Sub GetYearFromUser()
Dim userYear As String
Dim msg As String
msg = ""
EnterYear:
userYear = InputBox(Prompt:=msg & "Enter Year for comparing data:", title:="Year for comparing data")
' If no data entered, exit application
If userYear = "" Or userYear = vbNullString Then
MsgBox "Invalid Year." & vbNewLine & "Exiting."
End
ElseIf IsNumeric(userYear) = True Then
If CInt(userYear) > year(Now()) Then
msg = "Invalid Year. "
GoTo EnterYear
Else
CURR_YEAR = userYear
PREV_YEAR = CInt(userYear) - 1
End If
Else
msg = "Invalid Year. "
GoTo EnterYear
End If
' reinitialize variables
CURR_YEAR_SHEET_NAME = "" & CURR_YEAR
PREV_YEAR_SHEET_NAME = "" & PREV_YEAR
End Sub
Private Function GetYearForComparison()
Dim strFile As String
Dim answer As Integer
strFile = ""
If SheetExists(PREV_YEAR_SHEET_NAME) = False Or SheetExists(CURR_YEAR_SHEET_NAME) = False Then
USE_EXISTING_DATA = False
Else
USE_EXISTING_DATA = True
End If
If USE_EXISTING_DATA = True Then
answer = MsgBox("Do you want to use the existing data for comparison?", vbYesNo, "Use existing data")
If answer = vbYes Or answer = 6 Then
USE_EXISTING_DATA = True
Else
USE_EXISTING_DATA = False
End If
End If
' import sheet for current selected year
If USE_EXISTING_DATA = False Then
' strFile = "Macintosh HD:Users:sneha.banerjee:Sites:XLS:2016.csv"
' MsgBox "Uploading Data"
strFile = Application.GetOpenFilename("Csv Files (*.csv), *.csv", , "Please select a CSV file")
If strFile = "" Or strFile = vbNullString Then
'USE_EXISTING_DATA = True
MsgBox "Exiting..."
End
End If
End If
GetYearForComparison = strFile
End Function
Private Function SheetExists(ByVal name As String) As Boolean
On Error GoTo ReturnFalse
Sheets(name).Activate
' Sheet exists
SheetExists = True
Exit Function
ReturnFalse:
SheetExists = False
End Function
Private Sub ImportCurrentYearCSV(ByVal strFile As String)
Dim dataSheet As Worksheet
' assume previous years sheet already stored, store entered sheet as current year sheet
Call Get_Sheet(UPLOADED_DATA_SHEET_NAME, True)
Sheets(UPLOADED_DATA_SHEET_NAME).Activate
Set dataSheet = ActiveSheet
With dataSheet.QueryTables.Add(Connection:= _
"TEXT;" & strFile, Destination:=Range("A1"))
.name = "Uploaded Data"
.RefreshOnFileOpen = False
.BackgroundQuery = True
.SaveData = True
.AdjustColumnWidth = True
.TextFilePromptOnRefresh = False
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = True
.TextFileSemicolonDelimiter = True
.TextFileCommaDelimiter = True
.TextFileSpaceDelimiter = False
.Refresh BackgroundQuery:=False
End With
Application.CutCopyMode = False
'Move current year sheet after previous year
'currYearSheet.Move after:=Sheets(UPLOADED_DATA_SHEET_NAME)
'Move initial data sheet after current year
'Call Get_Sheet(DATA_SHEET_NAME, True)
'Sheets(DATA_SHEET_NAME).Move after:=Sheets(CURR_YEAR_SHEET_NAME)
End Sub
Private Sub MoveDataToProperSheets(ByVal CurrYear As Integer, ByVal sheetName As String)
Dim colNo As Integer
Dim rng1 As Range
Sheets(UPLOADED_DATA_SHEET_NAME).Activate
colNo = Search_ColumnWithTitle(YEAR_COL, "Please enter column name for Year")
With ActiveSheet
.AutoFilterMode = False
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter Field:=colNo, Criteria1:="" & CurrYear, Operator:=xlFilterValues
End With
Set rng1 = ActiveSheet.Cells.SpecialCells(xlCellTypeVisible)
If rng1.Rows.count <= 1 Then
' Do nothing
Else
Call Get_Sheet(sheetName, True)
' Copy curr year's data to proper data sheet
Call CopyInPartsSpecial(UPLOADED_DATA_SHEET_NAME, rng1, sheetName)
End If
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
End Sub
Private Function Select_File_Mac() As String
Dim MyScript As String
Dim MyFile As String
'#If Mac Then
' strFile = Select_File_Mac()
'#Else
' strFile = Application.GetOpenFilename("Csv Files (*.csv), *.csv", , "Please select a CSV file")
'#End If¼
On Error Resume Next
' In the following statement, change true to false in the line "multiple
' selections allowed true" if you do not want to be able to select more
' than one file. Additionally, if you want to filter for multiple files, change
' {""com.microsoft.Excel.xls""} to
' {""com.microsoft.excel.xls"",""public.comma-separated-values-text""}
' if you want to filter on xls and csv files, for example.
MyScript = _
"set applescript's text item delimiters to "","" " & vbNewLine & _
"set the Files to (choose file of type " & _
" {""public.comma-separated-values-text""} " & _
"with prompt ""Please select a file"" default location alias """ & _
""" multiple selections allowed false) as string" & vbNewLine & _
"set applescript's text item delimiters to """" " & vbNewLine & _
"return the Files"
MyFile = MacScript(MyScript)
On Error GoTo 0
If MyFile <> "" Then
Select_File_Or_Files_Mac = MyFile
Else
Select_File_Or_Files_Mac = ""
End If
End Function
Private Sub CreateInitialDataSheets()
Dim ws As Worksheet
Dim rng As Range
Dim rng2 As Range, destCell As Range
' validate data for curr and prev years exist
If SheetExists(PREV_YEAR_SHEET_NAME) = False Then
MsgBox "Data for " & PREV_YEAR & " not found. Upload data and try again. " & vbNewLine & "Exiting."
End
ElseIf SheetExists(CURR_YEAR_SHEET_NAME) = False Then
MsgBox "Data for " & CURR_YEAR & " not found. Upload data and try again. " & vbNewLine & "Exiting."
End
End If
' Get latest date of current year data
Call Get_Sheet(DATA_SHEET_NAME, True)
Sheets(CURR_YEAR_SHEET_NAME).Activate
colNo = Search_ColumnWithTitle(CRASH_DATE_COL, "Please enter column name for Crash Date")
col2 = Search_ColumnWithTitle(TYPE_COL, "Please enter column name for Injury type")
lastRow = Get_LastRowNo(1)
lastCol = Get_LastColumnNo()
Set rng = ActiveSheet.Range(ActiveSheet.Cells(2, colNo), ActiveSheet.Cells(lastRow, colNo))
maxDate = Application.WorksheetFunction.Max(rng) - 365
' Get data less than equal to max date of previous year
Sheets(PREV_YEAR_SHEET_NAME).Activate
colNo = Search_ColumnWithTitle(CRASH_DATE_COL, "Please enter column name for Crash Date")
With ActiveSheet
.AutoFilterMode = False
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter Field:=colNo, Criteria1:="<=" & maxDate, Operator:=xlFilterValues
End With
' Copy previous year's data to data sheet
'ActiveSheet.Cells.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets(DATA_SHEET_NAME).Range("A1")
Call CopyInPartsSpecial(PREV_YEAR_SHEET_NAME, ActiveSheet.Cells.SpecialCells(xlCellTypeVisible), DATA_SHEET_NAME)
On Error GoTo Proceed
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
Proceed:
'Copy all current year to data sheet
Sheets(CURR_YEAR_SHEET_NAME).Activate
Set ws = ActiveSheet
Set rng2 = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, lastCol))
'Set destCell = Sheets(DATA_SHEET_NAME).Cells(Rows.Count, "A").End(xlUp).Offset(1)
'rng2.Copy Destination:=destCell
Call CopyInPartsSpecial(CURR_YEAR_SHEET_NAME, rng2, DATA_SHEET_NAME)
On Error GoTo Proceed1
Sheets(DATA_SHEET_NAME).Activate
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
Columns.AutoFit
Proceed1:
End Sub
Private Sub CreateFilteredDataSheets()
Dim colNo As Integer
If CATEGORY_TYPE = 0 Then
Application.DisplayAlerts = False
Call Get_Sheet(FILTERED_DATA_SHEET_NAME, True)
Sheets(FILTERED_DATA_SHEET_NAME).Delete
FILTERED_DATA_SHEET_NAME = DATA_SHEET_NAME
Application.DisplayAlerts = True
GoTo Exitsub
End If
' copy filtered data to new sheet
Call Get_Sheet(FILTERED_DATA_SHEET_NAME, True)
Sheets(DATA_SHEET_NAME).Activate
colNo = Search_ColumnWithTitle(CATEGORY_COL_NAME, "Please enter column name for Accident category")
If CATEGORY_TYPE = 3 Then
colNo = GetCategoryColumn()
With ActiveSheet
.AutoFilterMode = False
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter Field:=colNo, Criteria1:=">=1", Operator:=xlFilterValues
End With
Else
With ActiveSheet
.AutoFilterMode = False
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter Field:=colNo, Criteria1:=Array("Y", "YES"), Operator:=xlFilterValues
End With
End If
' Copy filtered data to new sheet
Call CopyInPartsSpecial(DATA_SHEET_NAME, ActiveSheet.Cells.SpecialCells(xlCellTypeVisible), FILTERED_DATA_SHEET_NAME)
On Error GoTo Proceed
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
Proceed:
' Delete temporary column
If CATEGORY_TYPE = 3 Then
Sheets(DATA_SHEET_NAME).Columns(colNo).ClearContents
End If
Exitsub:
Sheets(FILTERED_DATA_SHEET_NAME).Activate
Columns.AutoFit
End Sub
Private Sub ConcatenateColumns()
Dim col1 As Integer, col2 As Integer
Dim rowCount As Long, resultCol As Integer
Sheets(DATA_SHEET_NAME).Activate
col1 = Search_ColumnWithTitle(COUNTY_COL, "Please enter column name for County")
col2 = Search_ColumnWithTitle(CITY_COL, "Please enter column name for City")
rowCount = Get_LastRowNo(1)
' Find first available column for results
If IsError(Application.Match(COUNTY_CITY_COL, Range(Cells(1, 1), Cells(1, Columns.count)), 0)) Then
' column not present, find first empty column
resultCol = Get_LastColumnNo() + 1
Else
' column already present, clear it
resultCol = Application.Match(COUNTY_CITY_COL, Range(Cells(1, 1), Cells(1, Columns.count)), 0)
Columns(resultCol).ClearContents
End If
' Populate Final results
Cells(1, resultCol).value = COUNTY_CITY_COL
For rowNo = 2 To rowCount
Cells(rowNo, resultCol).value = Trim(Cells(rowNo, col1).value & Cells(rowNo, col2).value)
Next
Columns(resultCol).Select
Selection.EntireColumn.AutoFit
Application.CutCopyMode = False
End Sub
Private Function GetCategoryColumn()
Dim col1 As Integer, col2 As Integer
Dim rowCount As Long, resultCol As Integer
Sheets(DATA_SHEET_NAME).Activate
col1 = Search_ColumnWithTitle(CATEGORY_COL_NAME, "Please enter column name for Unbelted Fatalities")
col2 = Search_ColumnWithTitle(CATEGORY_COL_NAME2, "Please enter column name for Unbelted Serious Injuries")
rowCount = Get_LastRowNo(1)
resultCol = Get_LastColumnNo() + 1
' Populate Final values
Cells(1, resultCol).value = "TEMP_COL"
For rowNo = 2 To rowCount
If IsTrue(Cells(rowNo, col1).value) Or IsTrue(Cells(rowNo, col2).value) Then
Cells(rowNo, resultCol).value = 1
Else
Cells(rowNo, resultCol).value = 0
End If
Next
Columns(resultCol).Select
Selection.EntireColumn.AutoFit
Application.CutCopyMode = False
GetCategoryColumn = resultCol
End Function
Private Function IsTrue(ByVal value As String) As Boolean
Dim returnValue As Integer
If IsNumeric(value) Then
If CInt(value) > 0 Then
returnValue = 1
Else
returnValue = 0
End If
ElseIf value = "YES" Or value = "Y" Then
returnValue = 1
Else
returnValue = 0
End If
IsTrue = returnValue
End Function
Private Sub CreatePivotTables()
Dim colNo As Integer
Sheets(FILTERED_DATA_SHEET_NAME).Activate
colNo = Search_ColumnWithTitle(TYPE_COL, INJ_TYPE_NOT_FOUND_MSG)
Call CreateDataSheet(INJ_TYPE_SERIOUS, colNo, SER_INJ_DATA_SHEET)
Call CreateDataSheet(INJ_TYPE_FATAL, colNo, FAT_INJ_DATA_SHEET)
On Error GoTo Proceed
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
Proceed:
Sheets(SER_INJ_DATA_SHEET).Activate
Call CreatePivotTable(SER_INJ_PIVOT_SHEET)
Sheets(FAT_INJ_DATA_SHEET).Activate
Call CreatePivotTable(FAT_INJ_PIVOT_SHEET)
End Sub
Private Sub CreateDataSheet(ByVal val As Integer, ByVal colNo As Integer, ByVal sheetName As String)
With ActiveSheet
.AutoFilterMode = False
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter
.Range(Cells(1, 1), Cells(1, Columns.count)).AutoFilter Field:=colNo, Criteria1:=val
End With
' verify sheet is present and clear it, else create new
Call Get_Sheet(sheetName, True)
' copy data sheet to new sheet
Sheets(FILTERED_DATA_SHEET_NAME).Activate
'ActiveSheet.Cells.SpecialCells(xlCellTypeVisible).Copy Destination:=Sheets(sheetName).Range("A1")
Call CopyInPartsSpecial(FILTERED_DATA_SHEET_NAME, ActiveSheet.Cells.SpecialCells(xlCellTypeVisible), sheetName)
On Error GoTo Proceed
If (ActiveSheet.AutoFilterMode And ActiveSheet.FilterMode) Or ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
ActiveSheet.AutoFilterMode = False
End If
Proceed:
Sheets(sheetName).Activate
Columns.AutoFit
Sheets(FILTERED_DATA_SHEET_NAME).Activate
End Sub
Private Sub CreatePivotTable(ByVal pvtShtName As String)
Dim pivotSheet As Worksheet
Dim dataSheet As String
dataSheet = ActiveSheet.name
' Create Pivot Sheet
Call Get_Sheet(pvtShtName, True)
Set pivotSheet = Sheets(pvtShtName)
' select data source for pivot table
Sheets(dataSheet).Activate
resultCol = Application.Match(COUNTY_CITY_COL, Range(Cells(1, 1), Cells(1, Columns.count)), 0)
rowCount = Get_LastRowNo(1)
srcData = ActiveSheet.name & "!" & Range(Cells(1, 1), Cells(rowCount, resultCol)).Address(ReferenceStyle:=xlR1C1)
' Create Pivot Cache from Source Data
Set pvtCache = ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=srcData)
pivotSheet.Activate
Set pvt = pvtCache.CreatePivotTable(TableDestination:=Range("A1"), TableName:="PT_" & pvtShtName)
' Specify row and column fields
With pvt.PivotFields(YEAR_COL)
.Orientation = xlColumnField
.PivotFilters.Add Type:=xlCaptionIsGreaterThanOrEqualTo, Value1:=PREV_YEAR
End With
pvt.PivotFields(MONTH_COL).Orientation = xlColumnField
With pvt.PivotFields(COUNTY_CITY_COL)
.Orientation = xlRowField
.AutoSort xlAscending, COUNTY_CITY_COL
End With
With pvt.PivotFields(DOCNUM_COL)
.Orientation = xlDataField
.Function = xlCount
End With
Application.CutCopyMode = False
End Sub
Private Function Get_LastRowNo(ByVal colNo As Integer) As Long
Get_LastRowNo = Cells(Rows.count, colNo).End(xlUp).Row
End Function
Private Function Get_LastColumnNo() As Integer
Get_LastColumnNo = Cells(1, Columns.count).End(xlToLeft).Column
End Function
Private Function Get_Sheet(ByVal sheetName As String, ByVal clearSheet As Boolean) As Boolean
Dim ws As Worksheet
Dim dataSheet As String
Dim chtObj As ChartObject
' Check if sheet present, if not create new
dataSheet = ActiveSheet.name
On Error GoTo CreateSheet
Set ws = Sheets(sheetName)
If clearSheet = True Then
ws.Cells.Clear
End If
' Delete all existing charts
For Each chtObj In ws.ChartObjects
chtObj.Delete
Next
Sheets(dataSheet).Activate
Get_Sheet = False
Exit Function
CreateSheet:
' If current sheet empty, rename it and use it
If ActiveSheet.UsedRange.Rows.count = 1 _
And ActiveSheet.UsedRange.Columns.count = 1 And Cells(1, 1).value = "" Then
ActiveSheet.name = sheetName
Else
Sheets.Add(, ActiveSheet).name = sheetName
Sheets(dataSheet).Activate
End If
Get_Sheet = True
End Function
' Assuming ActiveSheet and title on Row 1
Private Function Search_ColumnWithTitle(ByVal title As String, ByVal msg As String) As Integer
CheckColumn:
If IsError(Application.Match(title, Range(Cells(1, 1), Cells(1, Columns.count)), 0)) Then
title = InputBox(Prompt:="Column '" & title & "' not found. " & msg, _
title:="Enter " & title & " column name")
If title = "" Or title = vbNullString Then
MsgBox "No column name entered. Exiting..."
End
Else
GoTo CheckColumn
End If
End If
Search_ColumnWithTitle = Application.Match(title, Range(Cells(1, 1), Cells(1, Columns.count)), 0)
End Function
Private Sub GetFilterCategory()
Dim categoryNum As String
Dim text As String
TOTAL_CATEGORIES = 11
text = "0. All categories" & vbNewLine & _
"1. Alcohol" & vbNewLine & _
"2. Speed" & vbNewLine & _
"3. Unrestrained" & vbNewLine & _
"4. CMV" & vbNewLine & _
"5. Bicylce" & vbNewLine & _
"6. Pedestrian" & vbNewLine & _
"7. Motorcycle" & vbNewLine & _
"8. Teen driver involved" & vbNewLine & _
"9. Older driver involved" & vbNewLine & _
"10. Large Truck" & vbNewLine & _
"11. Distraction involved" & vbNewLine & _
"Enter the category number to be filtered"
categoryNum = InputBox(Prompt:=text, title:="Filter accidents by category")
If IsNumeric(categoryNum) Then
If CInt(categoryNum) >= 0 And CInt(categoryNum) <= TOTAL_CATEGORIES Then
CATEGORY_TYPE = CInt(categoryNum)
Else
CATEGORY_TYPE = 0
End If
Else
MsgBox "Invalid Entry. Exiting..."
End
End If
Select Case CATEGORY_TYPE
Case 1
CATEGORY_COL_NAME = ALCOHOL_COL_NAME
CATEGORY_TEXT = " - Alcohol -"
Case 2
CATEGORY_COL_NAME = SPEED_COL_NAME
CATEGORY_TEXT = " - Speeding -"
Case 3
CATEGORY_COL_NAME = FAT_UNRESTRAINED_COL_NAME
CATEGORY_COL_NAME2 = SER_UNRESTRAINED_COL_NAME
CATEGORY_TEXT = " - Unrestrained -"
Case 4
CATEGORY_COL_NAME = CMV_COL_NAME
CATEGORY_TEXT = " - CMV -"
Case 5
CATEGORY_COL_NAME = BICYCLE_COL_NAME
CATEGORY_TEXT = " - Bicycle -"
Case 6
CATEGORY_COL_NAME = PEDESTRIAN_COL_NAME
CATEGORY_TEXT = " - Pedestrian -"
Case 7
CATEGORY_COL_NAME = MOTORCYCLE_COL_NAME
CATEGORY_TEXT = " - Motorcycle -"
Case 8
CATEGORY_COL_NAME = TEEN_DRIVER_COL_NAME
CATEGORY_TEXT = " - Teen driver -"
Case 9
CATEGORY_COL_NAME = OLD_DRIVER_COL_NAME
CATEGORY_TEXT = " - Older driver -"
Case 10
CATEGORY_COL_NAME = LRG_TRUCK_COL_NAME
CATEGORY_TEXT = " - Large truck -"
Case 11
CATEGORY_COL_NAME = DISTRACTION_COL_NAME
CATEGORY_TEXT = " - Distraction -"
Case Else
CATEGORY_COL_NAME = ""
CATEGORY_TEXT = ""
End Select
End Sub
Private Function ExitIfColumnNotFound(ByVal colName As String)
If IsError(Application.Match(colName, Range(Cells(1, 1), Cells(1, Columns.count)), 0)) Then
MsgBox "Column '" & colName & "' not found. Exiting..."
End
End If
End Function
Related
Set slicer from data branch and print PDF
I have data from pivot-filter I world like to set data branch for select filter something like this 001 Great Northern << select 002 Great Eastern << select 003 Great Southen << not select 004 Great Midland << Not select 015 Great Mainline Transport << Select 025 Great Asia Industy << not select 030 Great Deutscher << Select Select with single select after print PDF unselect and select next to finish how to do this code thank you sir (sorry for bad english. I'm not good conversation english) Sub Button99_PDF() Dim wsA As Worksheet Dim wbA As Workbook Dim strTime As String Dim strName As String Dim strPath As String Dim strFile As String Dim strPathFile As String Dim myFile As Variant Dim codebranch As String Dim branchname As String Dim lictype As String On Error GoTo errHandler Dim tblRaw As ListObject, tblFiltered As ListObject Dim sh_raw As Worksheet, sh_filtered As Worksheet Dim critRange As Range, copyToRng As Range, resizeRng As Range Dim startRow As Long, lastRow As Long Application.ScreenUpdating = False Application.EnableEvents = False Application.Calculation = xlCalculationManual If Sheets("Pivot_Filters").Range("a8").Value = "" Then Exit Sub Set wsPF = ThisWorkbook.Sheets("Pivot_Filters") Set wsSD = ThisWorkbook.Sheets("SalesData") Set wsOP = ThisWorkbook.Sheets("Output") Set tblFiltered = wsOP.ListObjects("table2") Set ws = ThisWorkbook.Sheets("Output") Select Case tblFiltered.ListRows.Count Case Is > 0 tblFiltered.DataBodyRange.Delete tblFiltered.ListRows.Add Case Else tblFiltered.ListRows.Add End Select For Each slcCache In ActiveWorkbook.SlicerCaches slcCache.ClearManualFilter Next With ActiveWorkbook.SlicerCaches("Slicer_รหัส_สาขา") For Each oSlicerItem In .SlicerItems If oSlicerItem.Name = "001 : วิภาวดี" Then oSlicerItem.Selected = True Else oSlicerItem.Selected = False End If With ActiveWorkbook.SlicerCaches("Slicer_ประเภท_ใบอนุญาต") .SlicerItems("ตัวแทน").Selected = True .SlicerItems("Micro Insurance").Selected = True .SlicerItems("นายหน้าบุคคล").Selected = False .SlicerItems("นายหน้านิติบุคคล").Selected = False .SlicerItems("พรบ.").Selected = True .SlicerItems("นายหน้า").Selected = False .SlicerItems("โบรคเกอร์").Selected = False .SlicerItems("ไม่มีบัตร").Selected = False .SlicerItems("FALSE").Selected = False End With With ActiveWorkbook.SlicerCaches("Slicer_ชื่อหลักสูตร") .SlicerItems("ขอต่อใบอนุญาตนายหน้าประกันวินาศภัยครั้งที่ 1").Selected = True .SlicerItems("ขอต่อใบอนุญาตนายหน้าประกันวินาศภัยครั้งที่ 2").Selected = True .SlicerItems("ขอต่อใบอนุญาตนายหน้าประกันวินาศภัยครั้งที่ 3").Selected = True .SlicerItems("ขอต่อใบอนุญาตนายหน้าประกันวินาศภัยครั้งที่ 4").Selected = True .SlicerItems("ขอรับใบอนุญาตนายหน้าประกันวินาศภัย").Selected = True .SlicerItems("ขอต่อใบอนุญาตตัวแทนประกันวินาศภัยครั้งที่ 1").Selected = True .SlicerItems("ขอต่อใบอนุญาตตัวแทนประกันวินาศภัยครั้งที่ 2").Selected = True .SlicerItems("ขอต่อใบอนุญาตตัวแทนประกันวินาศภัยครั้งที่ 3").Selected = True .SlicerItems("ขอต่อใบอนุญาตตัวแทนประกันวินาศภัยครั้งที่ 4").Selected = True .SlicerItems("ขอรับใบอนุญาตตัวแทนประกันวินาศภัย").Selected = True .SlicerItems("ไม่มีข้อมูล").Selected = False End With ActiveSheet.ListObjects("Table2").TableStyle = "TableStyleLight21" wsSD.Range("Sales_Data[#All]").AdvancedFilter _ Action:=xlFilterCopy, _ CriteriaRange:=wsPF.Range("CritSlicers"), _ CopyToRange:=wsOP.Range("ExtractSlicers"), _ Unique:=False 'Find Filtered table Header row startRow = tblFiltered.HeaderRowRange.Row 'Find last row on Filtered tab (deduct 1 since Advanced filter retrieves the headers) lastRow = wsOP.Columns(2).Find("*", , , , xlByRows, xlPrevious).Row 'If the last raw is greater than the Header row, resize the Filtered table and delete the retrieved Headers (which will be in the first row of the Filtered table) If lastRow > startRow Then Set resizeRng = Range("table2[#All]").Resize(tblFiltered.Range.Rows.Count + (lastRow - startRow - 1), tblFiltered.Range.Columns.Count) tblFiltered.Resize resizeRng ' tblFiltered.ListRows(2).Delete Else 'If the last row is equal to Header row it means only the Column headers have been fetched, so there is no matching row to the filter criterias 'The if condition is only for let's say second line of defence If tblFiltered.HeaderRowRange(11, 2) = tblFiltered.DataBodyRange(11, 2) Then tblFiltered.DataBodyRange.Delete End If End If Application.ScreenUpdating = True Application.EnableEvents = True Application.Calculation = xlCalculationAutomatic ActiveWorkbook.Worksheets("Output").ListObjects("Table2").Sort.SortFields.Clear ActiveWorkbook.Worksheets("Output").ListObjects("Table2").Sort.SortFields.Add2 _ Key:=Range("Table2[ครั้งที่]"), SortOn:=xlSortOnValues, Order:= _ xlAscending, DataOption:=xlSortTextAsNumbers ActiveWorkbook.Worksheets("Output").ListObjects("Table2").Sort.SortFields.Add2 _ Key:=Range("Table2[วัน" & Chr(10) & "หมดอายุ]"), SortOn:=xlSortOnValues, Order:= _ xlAscending, DataOption:=xlSortNormal With ActiveWorkbook.Worksheets("Output").ListObjects("Table2").Sort .Header = xlYes .MatchCase = False .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With Worksheets("Output").Columns("A:M").AutoFit Worksheets("Output").Columns("K").Hidden = True Worksheets("Output").PageSetup.PrintArea = "PrintFocus" stword3 = GetSelectedSlicerItems("Slicer_รหัส_สาขา") stword = "รายงานต่อใบอนุญาต" stword4 = "ประกันวินาศภัย" stword5 = GetSelectedSlicerItems2("Slicer_ประเภท_ใบอนุญาต") Range("A9") = stword & " " & stword3 & " " & stword5 & " " & stword4 If InStr(Range("a9").Value, "นายหน้า") > 0 Then lictype = "นายหน้า" ElseIf InStr(Range("a9").Value, "ตัวแทน") > 0 Then lictype = "ตัวแทน" ElseIf InStr(Range("a9").Value, "ใบอนุญาตทั้งหมด") > 0 Then lictype = "ร่วมใบอนุญาต" End If codebranch = GetSelectedSlicerItems3("Slicer_รหัส_สาขา") branchname = GetSelectedSlicerItems("Slicer_รหัส_สาขา") Set wbA = ActiveWorkbook Set wsA = ActiveSheet strTime = Format(Now(), "dd_mm_yy") 'get active workbook folder, if saved strPath = wbA.Path If strPath = "" Then strPath = Application.DefaultFilePath End If strPath = strPath & "\" 'replace spaces and periods in sheet name strName = Replace(wsA.Name, " ", "") strName = Replace(strName, ".", "_") 'create default name for savng file strFile = lictype & "_" & codebranch & "_" & branchname & "_" & strTime & ".pdf" strPathFile = strPath & strFile 'use can enter name and ' select folder for file myFile = Application.GetSaveAsFilename _ (InitialFileName:=strPathFile, _ filefilter:="PDF Files (*.pdf), *.pdf", _ Title:="Select Folder and FileName to save") 'export to PDF if a folder was selected If myFile <> "False" Then wsA.ExportAsFixedFormat _ Type:=xlTypePDF, _ Filename:=myFile, _ Quality:=xlQualityStandard, _ IncludeDocProperties:=True, _ IgnorePrintAreas:=False, _ OpenAfterPublish:=False 'confirmation message with file info MsgBox "PDF file has been created: " _ & vbCrLf _ & myFile End If Next oSlicerItem End With exitHandler: Exit Sub errHandler: MsgBox "Could not create PDF file" Resume exitHandler End Sub
I'm looking for code Set branch into the VBA Slicer. Then make ordering print loop by set branch field VBA. 001 Great Northern << select 002 Great Eastern << select 003 Great Southen << not select 004 Great Midland << Not select 015 Great Mainline Transport << Select 025 Great Asia Industy << not select 030 Great Deutscher << Select This code from searching internet. I try hard for searching this but its look right only count slicer from first data to last data. For Each slcCache In ActiveWorkbook.SlicerCaches slcCache.ClearManualFilter Next With ActiveWorkbook.SlicerCaches("Slicer_รหัส_สาขา") For Each oSlicerItem In .SlicerItems If oSlicerItem.Name = "001 : วิภาวดี" Then oSlicerItem.Selected = True Else oSlicerItem.Selected = False End If
Application or object defined error in excel-vba
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
Convert column positive values to negative values VBA
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
Loop to go through a list of values
I currently have a macro which goes through a column on my master spreadsheet, then exports all the rows where the value input at the start matches the value in the column. It then saves the new worksheet as the value. Here is the code I currently have: Option Explicit Public Const l_HeaderRow As Long = 2 'The header row of the data sheet Public Const l_DistanceCol As Long = 5 'The column containing the distance values Public Sub ExportDistance() Dim ws_Data As Worksheet, wb_Export As Workbook, ws_Export As Worksheet Dim l_InputRow As Long, l_OutputRow As Long Dim l_LastCol As Long Dim l_NumberOfMatches As Long Dim s_Distance As String, l_Distance As Long Dim s_ExportPath As String, s_ExportFile As String, s_PathDelimiter As String Set ws_Data = ActiveSheet s_Distance = InputBox("Enter Distance to Export to New File", "Enter Distance") If s_Distance = "" Then Exit Sub l_Distance = CLng(s_Distance) l_NumberOfMatches = WorksheetFunction.Match(l_Distance, ws_Data.Columns(5), 0) If l_NumberOfMatches <= 0 Then Exit Sub 'Application.ScreenUpdating = False 'Application.Calculation = xlCalculationManual Application.DisplayAlerts = False On Error Resume Next Call Application.Workbooks.Add Set wb_Export = Application.Workbooks(Application.Workbooks.Count) Set ws_Export = wb_Export.Worksheets(1) Call wb_Export.Worksheets("Sheet2").Delete Call wb_Export.Worksheets("Sheet3").Delete Application.DisplayAlerts = True ws_Export.Name = GetNextSheetname(ws_Data.Name & "-" & s_Distance, wb_Export) Call ws_Data.Rows(1).Resize(l_HeaderRow).Copy Call ws_Export.Rows(1).Resize(l_HeaderRow).Select Call ws_Export.Paste l_OutputRow = l_HeaderRow + 1 l_LastCol = ws_Data.UsedRange.Columns.Count For l_InputRow = l_HeaderRow + 1 To ws_Data.UsedRange.Rows.Count If ws_Data.Cells(l_InputRow, l_DistanceCol).Value = l_Distance Then Call ws_Data.Range(ws_Data.Cells(l_InputRow, 1), ws_Data.Cells(l_InputRow, l_LastCol)).Copy Call ws_Export.Rows(l_OutputRow).Select Call ws_Export.Paste l_OutputRow = l_OutputRow + 1 ElseIf ws_Data.Cells(l_InputRow, l_DistanceCol).Value = l_Distance Then Call ws_Data.Range(ws_Data.Cells(l_InputRow, 1), ws_Data.Cells(l_InputRow, l_LastCol)).Copy Call ws_Export.Rows(l_OutputRow).Select Call ws_Export.Paste l_OutputRow = l_OutputRow + 1 End If Next l_InputRow s_ExportPath = ThisWorkbook.Path s_PathDelimiter = Application.PathSeparator If Right(s_ExportPath, 1) <> s_PathDelimiter Then s_ExportPath = s_ExportPath & s_PathDelimiter s_ExportPath = s_ExportPath & "Output" & s_PathDelimiter If Dir(s_ExportPath) = Empty Then Call MkDir(s_ExportPath) End If Select Case Application.DefaultSaveFormat Case xlOpenXMLWorkbook s_ExportFile = s_Distance & ".xlsx" Case xlOpenXMLWorkbookMacroEnabled s_ExportFile = s_Distance & ".xlsm" Case xlExcel12 s_ExportFile = s_Distance & ".xlsb" Case xlExcel8 s_ExportFile = s_Distance & ".xls" Case xlCSV s_ExportFile = s_Distance & ".csv" Case Else s_ExportFile = s_Distance End Select Call wb_Export.SaveAs(Filename:=s_ExportPath & s_ExportFile, FileFormat:=Application.DefaultSaveFormat) Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub Public Function GetNextSheetname(s_Name As String, Optional wb_Book As Workbook) As String Dim l_FIndex As Long Dim s_Target As String If wb_Book Is Nothing Then Set wb_Book = ActiveWorkbook s_Name = Left(s_Name, 31) If IsValidSheet(wb_Book, s_Name) Then l_FIndex = 1 s_Target = Left(s_Name, 27) & " (" & l_FIndex & ")" Do While IsValidSheet(wb_Book, s_Target) l_FIndex = l_FIndex + 1 If l_FIndex < 10 Then s_Target = Left(s_Name, 27) & " (" & l_FIndex & ")" ElseIf l_FIndex < 100 Then s_Target = Left(s_Name, 26) & " (" & l_FIndex & ")" ElseIf l_FIndex < 1000 Then s_Target = Left(s_Name, 25) & " (" & l_FIndex & ")" End If Loop GetNextSheetname = s_Target Else GetNextSheetname = s_Name End If End Function Public Function IsValidSheet(wbSearchBook As Workbook, v_TestIndex As Variant) As Boolean Dim v_Index As Variant On Error GoTo ExitLine v_Index = wbSearchBook.Worksheets(v_TestIndex).Name IsValidSheet = True Exit Function ExitLine: IsValidSheet = False End Function Please will you help me make this loop through a list of values, rather than my having manually to run the macro each time and input the value myself?
Download this example here. This is a simple example of how to loop through one range and loop through another range to find the values. It loops through Column D and then loops through column A, when it finds a match it does something, so basically Column D has taken the place of your inputbox. run the macro The code Sub DblLoop() Dim aLp As Range 'column A Dim dLp As Range, dRw As Long 'column D Dim d As Range, a As Range Set aLp = Columns("A:A").SpecialCells(xlCellTypeConstants, 23) dRw = Cells(Rows.Count, "D").End(xlUp).Row Set dLp = Range("D2:D" & dRw) 'start the loop 'loops through column D and finds value 'in column A, and does something with it For Each d In dLp.Cells 'loops through column D For Each a In aLp.Cells 'loops through column A If d = a Then 'When a match, then do something 'this is where your actual code would go Range("A" & a.Row & ":B" & a.Row).Copy Cells(Rows.Count, "F").End(xlUp).Offset(1) End If Next a 'keeps going through column A Next d 'next item in column D End Sub
Find if a given value is in a cell, if so then try next value until unique
I have the below sub that checks on a separate worksheet if the created number in textbox8 already exists, at the moment there is a message box that alerts the user that the part number already exists, they have to click OK, then the number is incremented by 1, the process is repeated until a unique number is found. This is the written to the worksheet along with some other data. What I need to do is remove the message box so it will automatically search and find the next available number. I added the following code to the sub, but this has no effect: Application.DisplayAlerts = False MsgBox "This already exists" SendKeys "{ENTER}" Application.DisplayAlerts = True code 'Create part number and check Private Sub CommandButton2_Click() With TextBox26 If myreset = True Then .Tag = 0 myreset = False End If .Tag = Val(.Tag) + 1 .Text = "-" & VBA.Format(Val(.Tag), "0000") End With Dim iNum(1 To 8) As String iNum(1) = TextBox24.Value iNum(2) = TextBox25.Value iNum(3) = TextBox26.Value TextBox8.Value = iNum(1) + iNum(2) + iNum(3) 'check article exists Dim emptyRow As Long Dim rcnt As Long Dim i As Long ActiveWorkbook.Sheets("existing").Activate rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row For i = 2 To rcnt If TextBox8.Text = Sheets("existing").Range("A" & i).Value Then Application.DisplayAlerts = False MsgBox "This already exists" SendKeys "{ENTER}" Application.DisplayAlerts = True Exit Sub End If Next Range("A1").Select Do If IsEmpty(ActiveCell) = False Then ActiveCell.Offset(1, 0).Select End If Loop Until IsEmpty(ActiveCell) = True ActiveCell.Value = TextBox8.Text
To remove the message Box all you need to do is delete the following lines in your code Application.DisplayAlerts = False MsgBox "This already exists" SendKeys "{ENTER}" Application.DisplayAlerts = True I am not sure what the first part of the code is doing. if you could provide some example I can help with that. But I have rationalized the second part and this will now achieve what the original code was attempting to achieve with lesser lines. 'check article exists Dim emptyRow As Long Dim rcnt As Long Dim i As Long Dim varProdCode As Long ActiveWorkbook.Sheets("existing").Activate varProdCode = TextBox8.Text rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row Do Until varProdCode = 0 For i = 2 To rcnt If varProdCode = Sheets("existing").Range("A" & i).Value Then varProdCode = varProdCode + 1 Exit For Else Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = varProdCode varProdCode = 0 Exit Sub End If Next Loop
This is the code that works Private Sub CommandButton2_Click() With TextBox26 If myreset = True Then .Tag = 0 myreset = False End If .Tag = Val(.Tag) + 1 .Value = VBA.Format(Val(.Tag), "0000") End With Dim emptyRow As Long Dim rcnt As Long Dim c As Long rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row For c = 2 To rcnt Dim iNum(1 To 8) As String iNum(1) = TextBox24.Value iNum(2) = TextBox25.Value iNum(3) = TextBox26.Value 'check if article exists ActiveWorkbook.Sheets("existing").Activate If Sheets("existing").Range("A" & c).Value = iNum(1) & iNum(2) & "-" & iNum(3) Then TextBox26.Value = TextBox26.Value + 1 iNum(3) = TextBox26.Value End If Next c 'create article number TextBox8.Value = iNum(1) + iNum(2) + "-" + iNum(3) 'select first column Range("A1").Select