I have an Excel file with many sheets, and I would like to filter old data at the end of the month and delete it. I can't always clear the data on the first, and sometimes users will work on the workbook before I can set it up for the current month.
This is the code I currently have:
Private Sub CommandButton4_Click()
Dim ws As Worksheet
Dim Rng As Range
Dim LastRow As Long, LastCol As Long
response = MsgBox("Tem a Certeza que quer Limpar todo os Dados?", vbYesNo)
If response = vbNo Then Exit Sub
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> "Formularios" Then
If ws.Name <> "Coordenador" Then
If ws.Name <> "LookupList" Then
With ws
.Unprotect Password:=pass
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
LastCol = .Range("A" & .Columns.Count).End(xlToLeft).Column
Set Rng = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With
With Rng
.AutoFilter Field:=1, Criteria1:=xlFilterLastMonth
.SpecialCells(xlCellTypeVisible).Offset(1, 0).Resize(.Rows.Count).Rows.Delete
End With
With ws
.AutoFilterMode = False
If .FilterMode = True Then
.ShowAllData
End If
.Protect Password:=pass
End With
End If
End If
End If
Next
End Sub
I get an Error 1004 object on this line:
.SpecialCells(xlCellTypeVisible).Offset(1, 0).Resize(.Rows.Count).Rows.Delete
This is the form I typically use.
With ws
.Unprotect Password:=pass
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
LastCol = .cells(1, .Columns.Count).End(xlToLeft).Column
Set Rng = .Range(.Cells(1, 1), .Cells(LastRow, LastCol))
End With
With Rng
.AutoFilter Field:=1, Criteria1:=xlFilterLastMonth, Operator:=xlFilterDynamic
with .resize(.rows.count-1, .columns.count).offset(1, 0)
if cbool(application.subtotal(103, .cells)) then
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
end if
end with
End With
I changed the initial range (rng) to be only the second row and took out the offset and resize. Since the range is only used in this subroutine, why is it being resized?
I tested it with 5 or 6 dates in this month and last, even putting them out of order and it worked as expected.
sub stest()
With Worksheets(1)
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set Rng = .Range(.Cells(2, 1), .Cells(LastRow, 1))
End With
With Rng
.AutoFilter Field:=1, Criteria1:=xlFilterLastMonth, Operator:=xlFilterDynamic
.offset(1,0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
End Sub
Related
I have several codes of the same. I can remove duplicates only for these ones, which have the H-column empty. If the H column contains nonempty cell, the given code must stay.
I tried to work with IsEmpty() function, but it didn't work. The behaviour was as normal.
The code looks like this:
If IsEmpty(shTarget.Range("H" & lRow)) Then
With shTarget.Range("A" & lRow)
.PasteSpecial xlPasteValuesAndNumberFormats
.PasteSpecial xlPasteFormats
.RemoveDuplicates Columns:=1, Header:=xlYes
.Sort Key1:=.Columns(1), Order1:=xlAscending, Header:=xlYes
.WrapText = True
End With
End If
The approach with:
If shTarget.Range("H" & lRow) = "" Then
was exactly the same.
How can I retain the duplicate codes, which have value in other column?
UPDATE:
With this approach:
With shTarget.Range("A" & lRow)
.PasteSpecial xlPasteValuesAndNumberFormats
.PasteSpecial xlPasteFormats
If .Range("H" & lRow).Value = "" Then
.RemoveDuplicates Columns:=1, Header:=xlYes
End If
.Sort Key1:=.Columns(1), Order1:=xlAscending, Header:=xlYes
.WrapText = True
End With
I have an error:
Sort method of Range class failed
UPDATE II
Tried also have this one:
For Each r In rng
If r.Value = "" Then
shTarget.Range("A2:H" & lRow).RemoveDuplicates Columns:=1,
Header:=xlYes
End If
Next r
it still doesn't work. Basically, no difference was observed.
My full code is:
Sub CopyData_Cables(ByRef shSource As Worksheet, shTarget As Worksheet)
Const VHead As String = "A1:H1"
Const VMBom As String = "A2:H100"
shSource.Range(VHead).Copy
With shTarget.Range("A1")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
Dim lRow As Long, lRow2 As Long
Dim i As Integer
lRow = shTarget.Cells(Rows.Count, "A").End(xlUp).Row + 1
shSource.Range(VMBom).Copy
Set Rng = shTarget.Range("H2" & lRow)
If IsEmpty(shTarget.Range("H" & lRow)) Then
With shTarget.Range("A" & lRow)
.PasteSpecial xlPasteValuesAndNumberFormats
.PasteSpecial xlPasteFormats
.RemoveDuplicates Columns:=1, Header:=xlYes
.Sort Key1:=.Columns(1), Order1:=xlAscending, Header:=xlYes
.WrapText = True
End With
End If
'If shTarget.Range("H2" & lRow) <> "" Then
'shTarget.Range("A" & lRow).Value = 0
'End If
'For Each r In Rng
' If r.Value = "" Then
'shTarget.Range("A2:A" & lRow).Value = "Kurs!"
' End If
' Next r
shTarget.Columns("A").ColumnWidth = 6.11
shTarget.Columns("B").ColumnWidth = 50
shTarget.Columns("C").ColumnWidth = 50
shTarget.Columns("D").ColumnWidth = 5.44
shTarget.Columns("E").ColumnWidth = 5.89
shTarget.Columns("F").ColumnWidth = 9
shTarget.Columns("G").ColumnWidth = 21.22
shTarget.Columns("H").ColumnWidth = 10.89
shTarget.Rows.EntireRow.AutoFit
For i = 3 To lRow Step 4
shTarget.Range(shTarget.Cells(i, 1), shTarget.Cells(i, 5)).Interior.Color = RGB(235, 235, 235)
shTarget.Range(shTarget.Cells(i, 7), shTarget.Cells(i, 8)).Interior.Color = RGB(235, 235, 235)
Next i
' Reset the clipboard.
Application.CutCopyMode = xlCopy
End Sub
Scan up the sheet deleting the duplicate rows.
Option Explicit
Sub RemoveDuplicates()
Dim ws As Worksheet, dict
Dim lastrow As Long, i As Long, n As Long
Dim key As String
Dim fso, ts
Set fso = CreateObject("Scripting.FilesystemObject")
Set ts = fso.CreateTextFile("debug.txt")
Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = lastrow To 2 Step -1
If Len(Trim(.Cells(i, "H"))) = 0 Then
key = Trim(.Cells(i, "A"))
If dict.exists(key) Then
'.Cells(i, "A").Interior.Color = vbRed
.Rows(i).Delete
n = n + 1
Else
dict.Add key, i
End If
Else
key = ""
End If
ts.writeline i & " A='" & .Cells(i, "A") & "' H='" _
& .Cells(i, "H") & "' key='" & key & "' n=" & n
Next
End With
ts.Close
MsgBox n & " rows deleted", vbInformation
End Sub
I have a number of sheets with VBA macros which transfer data after autofiltering.
When a sheet has no data after autofiltering, the macro brings up runtime error 1004 on the line
Workbooks("Predictology-Reports.xlsx").Sheets("FAL") _
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
Here is the full macro of one of them
Sub FALAYS()
Dim arr, ws As Worksheet, lc As Long, lr As Long
arr = Array("L.FAL_19_New_Summer2", "L.FA_FAL_3", "L.FAL_19_New_Summer")
Set ws = ActiveSheet
'range from A1 to last column header and last row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lr = ws.Cells.Find("*", after:=ws.Range("A1"), LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
With ws.Range("A1", ws.Cells(lr, lc))
.HorizontalAlignment = xlCenter
.AutoFilter Field:=1, Criteria1:=arr, Operator:=xlFilterValues
If .Rows.Count - 1 > 0 Then
On Error Resume Next
.Offset(1, 0).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Copy
On Error GoTo 0
Else
Exit Sub
End If
End With
Workbooks("Predictology-Reports.xlsx").Sheets("FAL") _
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
Application.CutCopyMode = False
End Sub
Try to set a range variable to the visible rows, then check to see if that got set before you copy/paste.
Sub FALAYS()
Dim arr, ws As Worksheet, lc As Long, lr As Long, rngCopy As Range
arr = Array("L.FAL_19_New_Summer2", "L.FA_FAL_3", "L.FAL_19_New_Summer")
Set ws = ActiveSheet
'range from A1 to last column header and last row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lr = ws.Cells.Find("*", after:=ws.Range("A1"), LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
With ws.Range("A1", ws.Cells(lr, lc))
.HorizontalAlignment = xlCenter
.AutoFilter Field:=1, Criteria1:=arr, Operator:=xlFilterValues
If .Rows.Count > 1 Then
On Error Resume Next
Set rngCopy = .Offset(1, 0).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rngCopy Is Nothing Then
rngCopy.Copy
Workbooks("Predictology-Reports.xlsx").Sheets("FAL") _
.Range("A" & Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues
Application.CutCopyMode = False
End If 'have anything to copy
End If
End With
End Sub
If this is a common task then pull it out into its own Sub:
'given a [filtered] table rngTable, copy visible data rows as values to rngDestination
Sub CopyVisibleRows(rngTable As Range, rngDestination As Range)
Dim rngVis As Range
If rngTable.Rows.Count > 1 Then
On Error Resume Next
Set rngVis = rngTable.Offset(1, 0).Resize(rngTable.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rngVis Is Nothing Then
rngVis.Copy
rngDestination.PasteSpecial xlPasteValues
End If
End If 'any source rows
End Sub
which reduces your original code to something like:
Sub FALAYS()
Dim arr, ws As Worksheet, lc As Long, lr As Long, tbl As Range
arr = Array("L.FAL_19_New_Summer2", "L.FA_FAL_3", "L.FAL_19_New_Summer")
Set ws = ActiveSheet
'range from A1 to last column header and last row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lr = ws.Cells.Find("*", after:=ws.Range("A1"), LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Set tbl = ws.Range("A1", ws.Cells(lr, lc))
With tbl
.HorizontalAlignment = xlCenter
.AutoFilter Field:=1, Criteria1:=arr, Operator:=xlFilterValues
If .Rows.Count > 1 Then
CopyVisibleRows tbl, Workbooks("Predictology-Reports.xlsx").Sheets("FAL") _
.Range("A" & Rows.Count).End(xlUp).Offset(1)
End If
End With
End Sub
There are a lot of improvements you could make to this code, but it should give you a starting point.
I'm assigning the filtered cells to a range, if there are cells, the range is "something".
Then copying the range to the sheet directly (you could skip the copy, paste method by transferring the values to the cells).
Tip: Try to avoid On Error Resume Next unless you know what you're doing and it is strictly necessary.
Read the comments and adjust the code to your needs.
EDIT: Added OERN as per Tim's suggestion
Code
Public Sub FALAYS()
Dim arrValues As Variant
arrValues = Array("L.FAL_19_New_Summer2", "L.FA_FAL_3", "L.FAL_19_New_Summer")
' Set the target workbook and sheet
Dim targetWorkbook As Workbook
Dim targetSheet As Worksheet
Set targetWorkbook = Workbooks("Predictology-Reports.xlsx")
Set targetSheet = targetWorkbook.Worksheets("FAL")
' Set the source sheet and range
Dim sourceSheet As Worksheet
Dim sourceRange As Range
Dim sourceColumn As Long
Dim sourceRow As Long
Set sourceSheet = ActiveSheet
'range from A1 to last column header and last row
sourceColumn = sourceSheet.Cells(1, sourceSheet.Columns.Count).End(xlToLeft).Column
sourceRow = sourceSheet.Cells.Find("*", after:=sourceSheet.Range("A1"), LookAt:=xlPart, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
With sourceSheet.Range("A1", sourceSheet.Cells(sourceRow, sourceColumn))
.HorizontalAlignment = xlCenter
.AutoFilter Field:=1, Criteria1:=arrValues, Operator:=xlFilterValues
If .Rows.Count - 1 > 0 Then
' Set the cells to the source range
On Error Resume Next
Set sourceRange = .Offset(1, 0).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error Goto 0
' Validate if the source range has cells
If Not sourceRange Is Nothing Then
sourceRange.Copy targetSheet.Range("A" & Rows.Count).End(xlUp).Offset(1)
Else
Exit Sub
End If
End If
End With
End Sub
Let me know if it works.
I am trying to sort data based on an unknown range.
When i try to sort based on 2 keys i get a Sort Method of Range Class failed
Option Explicit
Sub PostReview()
Dim tWb As ThisWorkbook, ws As Worksheet
Dim Lastrow As Integer, LastCol As Integer
Dim I As Integer, j As Integer
Dim rng As Range, rng2 As Range
Set ws = Worksheets("TR Query")
'Sort by Portfolio & Audit Date
Worksheets("TR Query").Activate
Lastrow = Cells(Rows.Count, 2).End(xlUp).Row
With ws
.Range("B1:B" & Lastrow).Copy
.Range("N:N").PasteSpecial (xlPasteValues)
Application.CutCopyMode = False
Set rng = Worksheets("TR Query").Range("N2:N" & Lastrow)
rng.Value = rng.Value
LastCol = Cells(1, Columns.Count).End(xlToLeft).Column
Set rng2 = .Range(.Cells(Lastrow, 1), .Cells(Lastrow, LastCol))
With rng2
.Cells.Sort Key1:=.Range("N1"), Order1:=xlAscending, _
Key2:=.Range("L1"), Order2:=xlDescending, _
Orientation:=xlTopToBottom, Header:=xlYes
End With
End With
i am hoping that the data is sorted first by column N from A to Z then sorted by column L from newest to oldest.
the error in my code is here:
With rng2
.Cells.Sort Key1:=.Range("N1"), Order1:=xlAscending, _ 'error happens here
Key2:=.Range("L1"), Order2:=xlDescending, _
Orientation:=xlTopToBottom, Header:=xlYes
End With
i'm not sure what i'm doing wrong.
I wish to optimize my code which loops through all rows and deletes it if a certain value exists. However, I am currently looping through > 100000 rows, so I wish to improve the speed.
Main purpose: Loop through all rows and delete it if a) cell(row, "A").value = "X1", b) cell(row, "S").value = "X2", and c) cell(row, "AW").value = "X3".
My current code is as follows:
Call FilterData("A", "X1")
Call FilterData("S", "X2")
Call FilterData("AW", "X3")
Sub FilterData(Column as String, Check as String)
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
If Not Sheets("XXX").AutoFilterMode Then
Sheets("XXX").Range("1:1").AutoFilter
End If
Sheets("XXX").Range("A2:BT1048576").Sort _
Key1:=Sheets("XXX").Range(Column & "1"), Order1:=xlAscending
With Sheets("XXX")
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, Column)
If Not IsError(.Value) Then
If .Value = Check Then .EntireRow.Delete
End If
End With
Next Lrow
End With
End Sub
Optimizing by applying a autofiler against the columns you wish to delete, if the values exist, the code deletes them. I made this really quickly, untested, but the logic works, hope this helps! :)
Code Added:
Sub Filter()
Dim ColALookup As String
Dim ColSLookup As String
Dim colAWlookup As String
Dim i As Long
ColALookup = "X1"
ColSLookup = "X2"
colAWlookup = "X3"
With Sheets("XXX")
.Range("A2", .Range("A" & .Rows.Count).End(xlUp)) _
.AutoFilter Field:=1, Criteria1:=Application.Transpose(ColALookup), Operator:=xlFilterValues
.Range("S2", .Range("S" & .Rows.Count).End(xlUp)) _
.AutoFilter Field:=1, Criteria1:=Application.Transpose(ColSLookup), Operator:=xlFilterValues
.Range("AW2", .Range("AW" & .Rows.Count).End(xlUp)) _
.AutoFilter Field:=1, Criteria1:=Application.Transpose(colAWlookup), Operator:=xlFilterValues
.Range("A2", .Range("A" & .Rows.Count).End(xlUp)) _
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
.Range("S2", .Range("S" & .Rows.Count).End(xlUp)) _
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
.Range("AW2", .Range("AW" & .Rows.Count).End(xlUp)) _
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
.AutoFilterMode = False
End With
End Sub
Here's my code below.
Sub AddExistingItemToRWP()
Dim AddRow As Integer
Dim eLastRow As Integer
AddRow = Worksheets("Recipe Workarea-Product").Range("A" & Rows.Count).End(xlUp).Row
eLastRow = Worksheets("Additional Existing Raw Mat.").Range("A" & Rows.Count).End(xlUp).Row
Dim Rng As Range
Sheets("Additional Existing Raw Mat.").Select
Set Rng = ActiveSheet.AutoFilter.Range
With Sheet12
With .Range("$A$1:K" & eLastRow)
.AutoFilter Field:=11, Criteria1:=("Y")
.SpecialCells (xlCellTypeVisible)
.Offset(1, 0) _
.Copy Destination:=Sheet8.Range("H" & AddRow + 1)
.PasteSpecial Paste = xlPasteValues
End With
End With
AutoFillCols (AddRow)
Sheets("Additional Existing Raw Mat.").Select
End Sub
The .pastespecial cells seems to be not working. What is the correct syntax for this?
Four things:
.SpecialCells(xlCellTypeVisible) returns a reference to a range, but you don't use it
You can't use both Destination:= ... and .PasteSpecial with one Copy. Choose one.
You mean .PasteSpecial Paste:=xlPasteValues not .PasteSpecial Paste = xlPasteValues
You activate and filter sheet "Additional Existing Raw Mat.", then refer to a filter on Sheet12. Are you sure thats right?
Update:
How to use Copy PasteSpecial
.Copy
Sheet8.Range("H" & AddRow + 1).PasteSpecial Paste:=xlPasteValues
I finally got the solution to my problem. Here's my code:
Sub AddExistingItemToRWP()
Dim AddRow As Integer
Dim eLastRow As Integer
AddRow = Worksheets("Recipe Workarea-Product").Range("A" & Rows.Count).End(xlUp).Row
eLastRow = Worksheets("Additional Existing Raw Mat.").Range("A" & Rows.Count).End(xlUp).Row
Dim Rng As Range
Sheets("Additional Existing Raw Mat.").Select
Set Rng = ActiveSheet.AutoFilter.Range
With Sheet12
With .Range("$A$1:K" & eLastRow)
.AutoFilter Field:=11, Criteria1:=("Y")
.SpecialCells(xlCellTypeVisible).Select
Selection.Offset(1, 0).Copy
Sheets("Recipe Workarea-Product").Select
Range("H" & AddRow + 1).Select
Selection.PasteSpecial Paste:=xlPasteValues
End With
End With
AutoFillCols (AddRow)
Sheets("Additional Existing Raw Mat.").Select
End Sub