I have multiple Excel files with the following structure:
Each file has the exact same columns (Apples, Oranges, Bananas, etc.) but placed under different letters throughout the sheets. For example, column "Apples" is under letter A in the first 5 sheets, but it's under letter C in the rest of the sheets. This order is not consistent and varies in each file.
I would like a macro capable of:
Unwrap all the cells in all sheets.
Hide columns from A to Z in all sheets.
Unhide only three columns featuring the words "apples/apple", "oranges/orange" and "bananas/bananas" in row 1.
Shrink to fit the text in the "apples/apple" column and set the width to 120.
Wrap to fit the text on the "oranges/orange" and "bananas/bananas" columns and set the width to 350.
Zoom all sheets to 100%.
I have this macro that works like a charm, as it allows me to choose which three columns I want to keep. However, it works exclusively if they are placed in the exact same order in all sheets:
Sub AdjustTF()
ColumnWidth = 10
ActiveWindow.Zoom = 100
Dim wsh As Worksheet
Dim rng As Range
Dim i As Long
Dim f As Boolean
Dim c As Long
On Error GoTo ErrHandler
' The following two lines are optional
Worksheets(1).Select
Range("A1").Select
For Each wsh In Worksheets
wsh.Cells.WrapText = False
wsh.Cells.VerticalAlignment = xlBottom
wsh.Cells.HorizontalAlignment = xlLeft
wsh.Cells.EntireColumn.Hidden = False
If f = False Then
Set rng = Application.InputBox( _
Prompt:="Select the columns to keep.", _
Type:=8).EntireColumn
f = True
End If
Set rng = wsh.Range(rng.Address).EntireColumn
c = wsh.Cells.Find(What:="*", SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
wsh.Range(wsh.Cells(1, 1), wsh.Cells(1, c)).EntireColumn.Hidden = True
With rng
.Hidden = False
With .Areas(1)
.ColumnWidth = 3
For i = 1 To 3
.ColumnWidth = 120 / .Width * .ColumnWidth
Next i
.ShrinkToFit = True
End With
With .Areas(2)
.ColumnWidth = 8
For i = 1 To 3
.ColumnWidth = 350 / .Width * .ColumnWidth
Next i
.WrapText = True
End With
With .Areas(3)
.ColumnWidth = 8
For i = 1 To 3
.ColumnWidth = 350 / .Width * .ColumnWidth
Next i
.WrapText = True
End With
End With
wsh.Cells.EntireRow.AutoFit
NextSheet:
Next wsh
Application.Goto Worksheets(1).Range("A1"), True
Exit Sub
ErrHandler:
Select Case Err
Case 424 ' Object required
Resume NextSheet
Case Else
MsgBox Err.Description, vbExclamation
End Select
End Sub
EDIT: I've also this code, which is significantly lighter (even though doesn't quite perform all tasks I wanted) but for some reasons works only with a single file and not when assigned to my Personal.xls sheet.
Sub AdjustTFAlternate()
Dim R As Range
Dim Ws As Worksheet
Dim Item
'In each worksheet
For Each Ws In ActiveWorkbook.Worksheets
'Hide all columns
Ws.UsedRange.EntireColumn.Hidden = True
'Search for this words
For Each Item In Array("apple*", "orange*", "banana*")
'Search for a keyword in the 1st row
Set R = Ws.Rows(1).Find(Item, LookIn:=xlFormulas, LookAt:=xlWhole)
If R Is Nothing Then
'Not found
Exit For
End If
'Unhide this column
R.EntireColumn.Hidden = False
Next
Next
End Sub
If you simply want a popup box for the user to select the 3 columns on each sheet, remove the line that reads
f = True
that is inside the If f = False Then statement.
If you want the macro to "remember" the column headers for each column chosen on the first page, then you'll need to modify the code slightly (and make some assumptions):
Assumptions
The column headers are in the first row
The column headers are unique (i.e., you don't have the same column title multiple times in the same sheet).
EDIT:
Code will now store all selected columns in an array that will search on each worksheet. For example, if on worksheet 1 you have apple, banana, and coconut, you will get an initial InputBox. If on worksheet 3, you now have apples, bananas, and coconuts, then you will get a second InputBox asking for these values. Now, on worksheets 4-n, the code will search for either apple or apples.
Code
Sub AdjustTF()
ColumnWidth = 10
Dim wsh As Worksheet
Dim rng As Range
Dim i As Long
Dim f As Boolean
Dim c As Long
'Dim aCol(1 To 1, 1 To 3) As String
Dim aCol() As String
ReDim aCol(1 To 3, 1 To 1)
Dim iCol(1 To 3) As Integer
Dim iTemp As Integer
Dim uStr As String
On Error GoTo ErrHandler
' The following two lines are optional
Worksheets(1).Select
Range("A1").Select
For Each wsh In Worksheets
d = 1
wsh.Cells.WrapText = False
wsh.Cells.VerticalAlignment = xlBottom
wsh.Cells.HorizontalAlignment = xlLeft
wsh.Cells.EntireColumn.Hidden = False
If f = False Then
On Error Resume Next
Err.Number = 0
Set rng = Application.InputBox( _
Prompt:="Select the columns to keep.", _
Type:=8).EntireColumn
If Err.Number > 0 Then
Exit Sub
End If
On Error GoTo ErrHandler
f = True
aCol(1, 1) = wsh.Cells(1, rng.Areas(1).Column).Value
aCol(2, 1) = wsh.Cells(1, rng.Areas(2).Column).Value
aCol(3, 1) = wsh.Cells(1, rng.Areas(3).Column).Value
Else
On Error Resume Next
For a = 1 To 3
iCol(a) = 0
Next
For a = 1 To UBound(aCol, 2)
Err.Number = 0
iTemp = wsh.Cells.Find(what:=aCol(1, a), lookat:=xlWhole).Column
If Err.Number = 0 And iCol(1) = 0 Then iCol(1) = iTemp
Err.Number = 0
iTemp = wsh.Cells.Find(what:=aCol(2, a), lookat:=xlWhole).Column
If Err.Number = 0 And iCol(2) = 0 Then iCol(2) = iTemp
Err.Number = 0
iTemp = wsh.Cells.Find(what:=aCol(3, a), lookat:=xlWhole).Column
If Err.Number = 0 And iCol(3) = 0 Then iCol(3) = iTemp
If iCol(1) > 0 And iCol(2) > 0 And iCol(3) > 0 Then Exit For
Next
If iCol(1) = 0 Or iCol(2) = 0 Or iCol(3) = 0 Then
wsh.Activate
Err.Number = 0
Set rng = Application.InputBox( _
Prompt:="Select the columns to keep.", _
Type:=8).EntireColumn
If Err.Number > 0 Then
Exit Sub
End If
a = UBound(aCol, 2) + 1
ReDim Preserve aCol(1 To 3, 1 To a)
aCol(1, a) = wsh.Cells(1, rng.Areas(1).Column).Value
aCol(2, a) = wsh.Cells(1, rng.Areas(2).Column).Value
aCol(3, a) = wsh.Cells(1, rng.Areas(3).Column).Value
Else
uStr = Range(wsh.Cells(1, iCol(1)), wsh.Cells(1, iCol(1))).Address & "," & _
Range(wsh.Cells(1, iCol(2)), wsh.Cells(1, iCol(2))).Address & "," & _
Range(wsh.Cells(1, iCol(3)), wsh.Cells(1, iCol(3))).Address
Set rng = Range(uStr)
End If
On Error GoTo ErrHandler
End If
Set rng = wsh.Range(rng.Address).EntireColumn
c = wsh.Cells.Find(what:="*", SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
wsh.Range(wsh.Cells(1, 1), wsh.Cells(1, c)).EntireColumn.Hidden = True
With rng
.Hidden = False
With .Areas(1)
.ColumnWidth = 3
For i = 1 To 3
.ColumnWidth = 120 / .Width * .ColumnWidth
Next i
.ShrinkToFit = True
End With
With .Areas(2)
.ColumnWidth = 8
For i = 1 To 3
.ColumnWidth = 350 / .Width * .ColumnWidth
Next i
.WrapText = True
End With
With .Areas(3)
.ColumnWidth = 8
For i = 1 To 3
.ColumnWidth = 350 / .Width * .ColumnWidth
Next i
.WrapText = True
End With
End With
wsh.Cells.EntireRow.AutoFit
wsh.Activate
ActiveWindow.Zoom = 100
wsh.Cells(1, 1).Select
NextSheet:
Next wsh
Application.Goto Worksheets(1).Range("A1"), True
Exit Sub
ErrHandler:
Select Case Err
Case 424 ' Object required
Resume NextSheet
Case Else
MsgBox Err.Description, vbExclamation
End Select
End Sub
Related
I want to write some VBA code that will count how many sets of "contiguous rows of Ts" there are in a single column in a worksheet. However I want such data sets to only be counted if there are more than 500 rows after the final T in a set that contain F values. For example, if T values are found at rows 500-510, then rows 511- 1010 would have to contain F values for one to be added to the count. If another T is encountered before reaching 1010, then the code would "reset" the 500 row counter and begin again.
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1600 = F
row 1601 - 1611 = T
row 1612 - 3000 = F
In this case the counter would display 2
Conversely:
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1400 = F
row 1401 - 1411 = T
row 1412 - 3000 = F
The counter would only display 1 as the Ts in cluster 1001-1011 are <500 rows within cluster 1401-1411.
I am also aware that in some scenarios there may be a set of Ts that are within 500 rows of the end of overall data. These would also need to be ignored from the count (I.e. using the example above, if Ts occurred a 2,700 - 2710, in a set of data with 3,000 rows, these would need to be ignored from the count). Similarly I would need to exclude rows 1-500 from the count also.
I don't know if this would be possible or even how to begin writing the code for this, so any assistance will be greatly appreciated. Excerpt of data:
F
F
F
F
F
F
F
F
F
T
T
T
T
T
F
F
F
F
F
F
F
F
This is going to be added to a much larger macro which then goes to filter out all rows containing Ts and deleting them. However I want to perform the count of contiguous Ts first before taking this step.
Code for rest of macro (This code is called by another macro which takes the values generated and pastes them into a master file):
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim Rng As Range, Cell As Range
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("A3:Q3").Copy
.Range("A3:Q3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:Q3").Copy
End With
End Sub
Code with Tim's suggested additions:
Sub Populate_Ensocoat()
On Error GoTo eh
Dim MyBook As String
Dim Wb As Workbook
Dim strFolder As String
Dim strFil As String
Dim StartTime As Double
Dim SecondsElapsed As Double
Dim xCount As Long
Dim SourceRang1 As Range
Dim FillRange1 As Range
'Code to improve performance
Application.ScreenUpdating = False
Application.EnableEvents = False
'Code to Prompt user to select file location
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
strFolder = .SelectedItems(1)
Err.Clear
End With
'Code to count how many files are in folder and ask user if they wish to continue based on value counted
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> ""
xCount = xCount + 1
strFil = Dir()
Loop
If MsgBox("You have selected " & xCount & " files. Are you sure you wish to continue?", vbYesNo) = vbNo Then GoTo eh
'Code to Start timer
StartTime = Timer
'Code to make final report sheet visible and launch sheet hidden
Sheet1.Visible = True
Sheet1.Activate
Sheets("Sheet3").Visible = False
'declaring existing open workbook's name
MyBook = ActiveWorkbook.Name
'Code to cycle through all files in folder and paste values into master report
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> vbNullString
Set Wb = Workbooks.Open(strFolder & "\" & strFil)
Call RollMap_Ensocoat(Wb)
Workbooks(MyBook).Activate
ActiveSheet.Paste
Selection.HorizontalAlignment = xlCenter
ActiveCell.Offset(1).Select
Wb.Close SaveChanges:=False
strFil = Dir
Loop
'Formatting of values in final report
Range("B:I").NumberFormat = "#,##0"
Range("J:K").NumberFormat = "0.000"
Range("L:L").NumberFormat = "0.00"
Range("P:P").NumberFormat = "dd/MM/yyyy"
Range("Q:Q").NumberFormat = "hh:mm"
'Code to add header data to report (i.e. total files, name of person who created report, date and time report was created)
Range("Y2").Value = Now
Range("H2").Value = "# of Files Reported on: " & xCount
Range("P2").Value = Application.UserName
'Re-enabling features disabled for improved macro performance that are now needed to display finished report
Application.EnableEvents = True
Application.ScreenUpdating = True
'Code to refresh sheet so that graphs display properly
ThisWorkbook.RefreshAll
'Code to automatically save report in folder where files are located. Overrides warning prompting user that file is being saved in Non-macro enabled workbook.
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:=strFolder & "\" & "Summary Report", FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
'Code to display message box letting user know the number of files reported on and the time taken.
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "Operation successfully performed on " & xCount & " files in " & SecondsElapsed & " seconds." & vbNewLine & vbNewLine & "Report created at location: " & Application.ActiveWorkbook.FullName, vbInformation
Done:
Exit Sub
eh:
MsgBox "No Folder Selected. Please select re-select a board grade"
End Sub
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
.Range("H1").Formula = "=TCount(G3:G10000)"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("R3").Formula = "='1'!H1"
.Range("A3:R3").Copy
.Range("A3:R3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:R3").Copy
End With
End Sub
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv
End Function
Something like this.
You may need to adjust if I made wrong assumptions about your rules.
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean, earlyT as Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
If i <= GAP_SIZE Then earlyT = True '<<EDIT
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv - IIf(earlyT, 1, 0) '<< EDIT
End Function
I have the following code and it works great except for one thing when it is used it finds every blank field in the table and inserts the value of the field above it. I only need it to fill the fields above the rows that were inserted by the code.
Sub ERCACMPCleanup()
'Cleans ERCA_CMP Worksheet and creates extra records for comma delimited
Dim X As Long, LastRow As Long, A As Range, Table As Range, Data() As String
Const Delimiter As String = ", "
Const DelimitedColumn As String = "A"
Const TableColumns As String = "A:O"
Const StartRow As Long = 2
Application.ScreenUpdating = False
ActiveWorkbook.Worksheets("ERCA_CMP").Visible = True
ActiveWorkbook.Worksheets("ERCA_CMP").Activate
LastRow = Columns(TableColumns).Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlFormulas).Row
For X = LastRow To StartRow Step -1
Data = Split(Cells(X, DelimitedColumn), Delimiter)
If UBound(Data) > 0 Then
Intersect(Rows(X + 1), Columns(TableColumns)).Resize(UBound(Data)).Insert xlShiftDown
End If
If Len(Cells(X, DelimitedColumn)) Then
Cells(X, DelimitedColumn).Resize(UBound(Data) + 1) = WorksheetFunction.Transpose(Data)
End If
Next
**LastRow = Cells(Rows.Count, DelimitedColumn).End(xlUp).Row
On Error Resume Next
Set Table = Intersect(Columns(TableColumns), Rows(StartRow).Resize(LastRow - StartRow + 1))
If Err.Number = 0 Then
Table.SpecialCells(xlBlanks).FormulaR1C1 = "=R[-1]C"
Columns(DelimitedColumn).SpecialCells(xlFormulas).Clear
Table.Value = Table.Value
End If
On Error GoTo 0**
End Sub
The issue is in the last few rows this code needs to only fill the blanks in the inserted rows not all blank fields in the table.
Any help is greatly appreciated.
Modified the code to check if all cells in B:0 are null. I think intersect would not be correct in this case as you don't want to apply this to all the cells.
Note 1: There would be better solution than this too as I'm not familiar with complete VBA
Note 2: If you put Application.ScreenUpdating = False you should set it to True at the end of the program too.
Sub ERCACMPCleanup()
'Cleans ERCA_CMP Worksheet and creates extra records for comma delimited
Dim X As Long, LastRow As Long, A As Range, Table As Range, Data() As String
Dim flgval As Boolean, rcntr As Integer, ccntr As Integer, rownum As Integer
Const Delimiter As String = ", "
Const DelimitedColumn As String = "A"
Const TableColumns As String = "A:O"
Const StartRow As Long = 2
Application.ScreenUpdating = False
ActiveWorkbook.Worksheets("ERCA_CMP").Visible = True
ActiveWorkbook.Worksheets("ERCA_CMP").Activate
LastRow = Columns(TableColumns).Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlFormulas).Row
For X = LastRow To StartRow Step -1
Data = Split(Cells(X, DelimitedColumn), Delimiter)
If UBound(Data) > 0 Then
Intersect(Rows(X + 1), Columns(TableColumns)).Resize(UBound(Data)).Insert xlShiftDown
End If
If Len(Cells(X, DelimitedColumn)) Then
Cells(X, DelimitedColumn).Resize(UBound(Data) + 1) = WorksheetFunction.Transpose(Data)
End If
Next
'Modification Start for the question
'flgval turns true if cells B:O are not empty
flgval = False
Range("A1").Activate
For rcntr = 0 To LastRow - 1
For ccntr = 1 To 14
If ActiveCell.Offset(0, ccntr).Value <> "" Then
flgval = True
Exit For
End If
Next
If flgval = False Then
For ccntr = 1 To 14
ActiveCell.Offset(0, ccntr).FormulaR1C1 = "=R[-1]C"
Next
Else
flgval = False
End If
ActiveCell.Offset(1, 0).Activate
Next
'**LastRow = Cells(Rows.Count, DelimitedColumn).End(xlUp).Row
'On Error Resume Next
'Set Table = Intersect(Columns(TableColumns), Rows(StartRow).Resize(rownum - StartRow))
'If Err.Number = 0 Then
' Table.SpecialCells(xlBlanks).FormulaR1C1 = "=R[-1]C"
' Columns(DelimitedColumn).SpecialCells(xlFormulas).Clear
' Table.Value = Table.Value
'End If
'On Error GoTo 0**
Application.ScreenUpdating = True
End Sub
So it's a bit tricky for me since I started learning this 3 days ago...
I have a table with 4 columns: Station name | Date | Program name | Status
When I insert a new record, it will match older ones - but the date will always be different.
I need a code to add to my code that will allow an automatic search of similar records by : Station Name + Program Name - but only for those in the current month, and delete the old existing record before writing in the new one.
This is my current code connected to a button:
Sub OK()
Application.ScreenUpdating = False
' Check if all data was filled
With Empt
If IsEmpty(Sheet1.Range("D4").Value) = True Then
MsgBox "Please fill all fields"
' ElseIf IsEmpty(Sheet1.Range("E4").Value) = True Then
'MsgBox "Please fill all fields"
ElseIf IsEmpty(Sheet1.Range("F4").Value) = True Then
MsgBox "Please fill all fields"
ElseIf IsEmpty(Sheet1.Range("G4").Value) = True Then
MsgBox "Please fill all fields"
Else
'Insert data to table
Sheet1.Range("E4").Value = Now()
Sheet1.Range("D4:G4").Copy
Sheet1.Range("A10").Rows("1:1").Insert Shift:=xlDown
MsgBox "All data have been copied!"
Sheet1.Range("D4:G4").ClearContents
'Sheet1.Range("E4").Value = "Auto Fill"
End If
End With
'CHANGE COLOR OF CELLS
With colrng
NonEmp = Sheet1.Application.CountA(Range("D10:D100000"))
Set MyPlage = Range("D10:D10" & NonEmp)
For Each Cell In MyPlage
Select Case Cell.Value
Case Is = "Completed"
Cell.Interior.ColorIndex = 43
Case Is = "Waiting"
Cell.Interior.ColorIndex = 3
Case Is = "Uploading"
Cell.Interior.ColorIndex = 6
Case Else
Cell.EntireRow.Interior.ColorIndex = xlNone
End Select
Next
End With
' Save records
Sheet1.Range("A10:E50000").Validation.Delete
ThisWorkbook.Save
End Sub
Can someone help please?
Option Explicit
Public Sub OK()
Dim ws As Worksheet, ur As Range, lr As Long, inc As Range, ref As Range
Set ws = Worksheets("Main")
Set inc = ws.Range("D4:G4") 'Insert Data
Set ref = ws.Range("A9") 'Station
With ws
lr = .Cells(.Rows.Count, 4).End(xlUp).Row
If inputIsValid(.Range("D4,F4,G4")) Then
Application.ScreenUpdating = False
Set ur = .Range(ref, "D" & lr)
removePrev ur, .Range("D4"), .Range("F4")
.Range("E4").Value = Now
inc.Copy
ref.Rows(2).Insert Shift:=xlDown
inc.ClearContents
With ref.Offset(1, 3)
Select Case .Value2
Case "Completed": .Interior.ColorIndex = 43
Case "Waiting": .Interior.ColorIndex = 3
Case "Uploading": .Interior.ColorIndex = 6
End Select
End With
.Range("D4").Activate
ThisWorkbook.Save
Application.ScreenUpdating = True
End If
End With
End Sub
Private Function inputIsValid(ByRef inRng As Range) As Boolean
Dim cel As Range, result As Boolean, invRng As Range
result = True
For Each cel In inRng
If Len(cel) = 0 Then
If invRng Is Nothing Then Set invRng = cel Else Set invRng = Union(invRng, cel)
result = False
End If
Next
If Not result Then
invRng.Interior.Color = vbBlue
MsgBox "Please enter values in blue cell(s)"
invRng.Interior.ColorIndex = xlColorIndexAutomatic
ThisWorkbook.Saved = True
End If
inputIsValid = result
End Function
Private Sub removePrev(ByRef rng As Range, ByVal sn As String, pn As String)
Dim v As Range
With rng
Set v = rng.Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count)
On Error Resume Next
.AutoFilter Field:=1, Criteria1:=sn
If v.SpecialCells(xlCellTypeVisible).Count > 1 Then
.AutoFilter Field:=2, Criteria1:=xlFilterThisMonth, Operator:=xlFilterDynamic
If v.SpecialCells(xlCellTypeVisible).Count > 1 Then
.AutoFilter Field:=3, Criteria1:=pn
If .SpecialCells(xlCellTypeVisible).Count > 1 Then
v.SpecialCells(xlCellTypeVisible).Rows.EntireRow.Delete
End If
End If
End If
.AutoFilter
End With
End Sub
It works on the following test file:
.
Note: The last sub (showStatus) can be replaced with 3 Conditional Formatting Rules:
I am new to Excel VBA and I really need your help. I have a code that will look for the duplicate values in Column A. This code will highlight the duplicate values. I want:
1.) This code to ONLY run when I click on a button.
2.) I would like to have (somewhere in the same worksheet), the number of duplicate results and a hyper link that when you click on it will direct you the duplicate result (this is because I have sometimes huge files that I need to validate). Here is the code I currently have:
Sub Worksheet_Change(ByVal Target As Excel.Range)
Dim C As Range, i As Long
If Not Intersect(Target, Me.[A:A]) Is Nothing Then
Application.EnableEvents = False
For Each C In Target
If C.Column = 1 And C.Value > "" Then
If WorksheetFunction.CountIf(Me.[A:A], C.Value) > 1 Then
i = C.Interior.ColorIndex
f = C.Font.ColorIndex
C.Interior.ColorIndex = 3 ' Red
C.Font.ColorIndex = 6 ' Yellow
C.Select
MsgBox "Duplicate Entry !", vbCritical, "Error"
C.Interior.ColorIndex = i
C.Font.ColorIndex = f
End If
End If
Next
Application.EnableEvents = True
End If
End Sub
I would really appreciate it if you help me with this.
Add the code to Module1 Alt+F11
Option Explicit
Sub MyButton()
Dim RangeCell As Range, _
MyData As Range
Dim MyDupList As String
Dim intMyCounter As Integer
Dim MyUniqueList As Object
Dim lngLastRow As Long, lngLoopRow As Long
Dim lngWriteRow As Long
Set MyData = Range("A1:A" & Cells(Rows.Count, "A").End(xlUp).Row)
Set MyUniqueList = CreateObject("Scripting.Dictionary")
Application.ScreenUpdating = False
MyDupList = "": intMyCounter = 0
'// Find Duplicate
For Each RangeCell In MyData
If RangeCell <> "V" And RangeCell <> "R" Then
If Evaluate("COUNTIF(" & MyData.Address & "," & RangeCell.Address & ")") > 1 Then
'// Color. Change to suit RGB(141, 180, 226).
RangeCell.Interior.Color = RGB(141, 255, 226)
If MyUniqueList.exists(CStr(RangeCell)) = False Then
intMyCounter = intMyCounter + 1
MyUniqueList.Add CStr(RangeCell), intMyCounter
If MyDupList = "" Then
MyDupList = RangeCell
Else
MyDupList = MyDupList & vbNewLine & RangeCell
End If
End If
Else
RangeCell.Interior.ColorIndex = xlNone
End If
End If
Next RangeCell
'// Move duplicate from Column 1 to Column 7 = (G:G)
lngWriteRow = 1
lngLastRow = Cells(Rows.Count, 1).End(xlUp).Row
For lngLoopRow = lngLastRow To 1 Step -1
With Cells(lngLoopRow, 1)
If WorksheetFunction.CountIf(Range("A1:A" & lngLastRow), .Value) > 1 Then
If Range("G:G").Find(.Value, lookat:=xlWhole) Is Nothing Then
Cells(lngWriteRow, 7) = .Value
lngWriteRow = lngWriteRow + 1
End If
End If
End With
Next lngLoopRow
Set MyData = Nothing: Set MyUniqueList = Nothing
Application.ScreenUpdating = False
If MyDupList <> "" Then
MsgBox "Duplicate entries have been found:" & vbNewLine & MyDupList
Else
MsgBox "There were no duplicates found in " & MyData.Address
End If
End Sub
.
Add Module
Add Button
Assign to Macro
I have a big Excel sheet containing +100k rows and have an autofilter on one column of text values with category numbers and descriptions. There are thousands of different values in column F, so updating the autofilter is very impractical via using the standard UI.
How can I create a macro that removes the currently active cell's value from the autofilter that is active on the same column?
With the help of an expert, we came to a working solution for my case.
Just posting this as solution for others:
Sub Clear_Filter_and_Value()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim w As Worksheet
Dim filterArray()
Dim currentFiltRange As String
Dim col As Integer
Dim flag As Boolean
Set w = ActiveSheet
If w.AutoFilterMode = False Then Selection.AutoFilter
flag = False
On Error GoTo exit1
With w.AutoFilter
currentFiltRange = .Range.Address
With .Filters
For f = 1 To .Count
With .Item(f)
If .On Then
If ActiveCell.Column = f Then
ReDim filterArray(1 To .Count)
If .Count = 2 Then
filterArray(1) = .Criteria1
filterArray(2) = .Criteria2
Else
filterArray(1) = .Criteria1
End If
End If
ElseIf ActiveCell.Column = f Then
tR = Cells(Rows.Count, ActiveCell.Column).End(xlUp).Row
ReDim filterArray(1 To tR - 1)
For i = 2 To tR
filterArray(i - 1) = Cells(i, ActiveCell.Column).Value
flag = True
Next i
End If
End With
Next f
End With
End With
w.AutoFilterMode = False
j = 1
ReDim newArray(1 To UBound(filterArray))
If flag = False Then
On Error GoTo 1
For i = 1 To UBound(filterArray(1))
On Error GoTo 1
If InStr(1, filterArray(1)(i), ActiveCell.Value) = 0 Then
newArray(j) = filterArray(1)(i)
j = j + 1
End If
Next i
Else
1:
Err.Clear
For i = 1 To UBound(filterArray)
If InStr(1, filterArray(i), ActiveCell.Value) = 0 Then
newArray(j) = filterArray(i)
j = j + 1
End If
Next i
End If
For col = 1 To 1
If Not IsEmpty(filterArray(1)) Then
w.Range(currentFiltRange).AutoFilter Field:=ActiveCell.Column, Criteria1:=newArray, Operator:=xlFilterValues
End If
Next col
exit1:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub