VBA - Loop Pivot Table Filtering Extract - vba

I have the below code which applies a filter to a Pivot Table, then specific data is copied from the PivotTable and the filters are removed.. The issue is, this one block of code is used 22 times, the sub is waaaay too long.
Here is the code I have with only ONE of the blocks:
Option Explicit
Sub FilterPivotTable()
Dim rLastCell As Range
Dim PvtTbl As PivotTable
Dim ws1 As Worksheet, ws2 As Worksheet
Dim LastRow1 As Long
Set ws1 = ActiveWorkbook.Sheets("PivotTable")
Set ws2 = ActiveWorkbook.Sheets("Summary")
Dim rowCount As Long
LastRow1 = ws1.Cells(Rows.Count, 1)
'Microsoft Windows
Application.ScreenUpdating = False
ws1.PivotTables("P1").ManualUpdate = True
ws1.PivotTables("P1").PivotFields(" Vulnerability Name").ClearAllFilters
'---------------Block Starts Here---------------
ws1.PivotTables("P1").PivotFields(" Vulnerability Name").PivotFilters. _
Add Type:=xlCaptionContains, Value1:="Microsoft Windows"
ws1.PivotTables("P1").ManualUpdate = False
Application.ScreenUpdating = True
With ws1.PivotTables(1).TableRange1
Set rLastCell = .Cells(.Rows.Count, .Columns.Count)
Set PvtTbl = Worksheets("PivotTable").PivotTables("P1")
rLastCell.Copy
With ws2
.Cells(LastRow1 + 2, 3).PasteSpecial xlPasteValues
.Range("$B$2").Value = "Microsoft Windows"
rowCount = PvtTbl.DataBodyRange.Rows.Count
.Range("$D$2") = rowCount - 1
End With
End With
ws1.PivotTables("P1").PivotFields(" Vulnerability Name").ClearAllFilters
'---------------Block Ends Here---------------
End Sub
This block of code is repeated 22 times throughout this sub, each time only changing the vulnerability name i.e. Changing 'Microsoft Windows' to 'Adobe' and then changing the Cell Reference for where the data is to be copied to the Summary Sheet.
I am hoping to rather have one block of code that loops through the vulnerability names instead of having 22 different blocks of code performing the same function.
This is what the Pivot Table Structure looks like:
The filter is done under the rows block and done on Vulnerability Name

This is a bit of a punt in the dark I'm afraid
Option Explicit
Sub FilterPivotTable()
Dim rLastCell As Range
Dim PvtTbl As PivotTable
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ActiveWorkbook.Sheets("PivotTable")
Set ws2 = ActiveWorkbook.Sheets("Summary")
Dim rowCount As Long
Dim LastRow1 As Long
Dim pvtField As PivotField
Set PvtTbl = ws1.PivotTables("P1")
Application.ScreenUpdating = False
Set pvtField = PvtTbl.PivotFields(" Vulnerability Name") 'extend etc as required
Dim myArr()
myArr = Array("Microsoft Windows", "Adobe Reader", "Other")
'PvtTbl.ManualUpdate = False
Dim i As Long
For i = LBound(myArr) To UBound(myArr)
pvtField.ClearAllFilters
pvtField.PivotFilters. _
Add Type:=xlCaptionContains, Value1:=myArr(i)
With ws1.PivotTables(1).TableRange1
Set rLastCell = .Cells(.Rows.count, .Columns.count) 'grand total?
End With
With ws2
LastRow1 = ws2.Cells(ws2.Rows.count, 3).End(xlUp).row
rLastCell.Copy
.Cells(LastRow1 + 1, 3).PasteSpecial xlPasteValues
.Cells(LastRow1 + 1, 2).Value = myArr(i)
rowCount = PvtTbl.DataBodyRange.Rows.count
.Cells(LastRow1 + 1, 4) = rowCount - 1
End With
Next i
Application.ScreenUpdating = True
'PvtTbl.ManualUpdate = False
End Sub

Related

VBA - Remove Duplicates Across Multiple Sheets in Workbook

I have multiple sheets in a particular workbook, and n each sheet there are Employee Numbers. The sheets have already been sorted in a way that Column A is always the Employee Number.
So what I need to do is loop through all the sheets and apply the RemoveDuplicates function to delete all duplicate Employee Numbers found in Column A.
Note - I am not trying to have the Employee Number appear on only one sheet; I am trying to have the Employee Number appear only once on each sheet.
I have it working for when I name a specific sheet, but cannot get it to work in a loop.
Test1:
Sub deleteDuplicate()
Dim ws As Worksheet
Dim wkbk1 As Workbook
Dim w As Long
Dim lRow As Long
Dim iCntr As Long
Set wkbk1 = Workbooks("3rd Party.xlsm")
wkbk1.Activate
For Each ws In ThisWorkbook.Worksheets
' Find last row in column A
lRow = ws.Range("A" & ws.Rows.count).End(xlUp).Row
For iCntr = lRow To 1 Step -1
ws.lRow.RemoveDuplicates Columns:=1, Header:=xlYes
Next iCntr
Next ws
End Sub
Test2:
Sub deleteDuplicate()
Dim ws As Worksheet
Dim wkbk1 As Workbook
Dim w As Long
Dim lRow As Long
Dim iCntr As Long
Set wkbk1 = Workbooks("3rd Party.xlsm")
wkbk1.Activate
With wkbk1
For w = 1 To .Worksheets.count
With Worksheets(w)
.UsedRange.RemoveDuplicates Columns:=1, Header:=xlYes
End With
Next w
End With
End Sub
The issue in both tests
Set wkbk1 = Workbooks("3rd Party.xlsm") - it implies the code is not in ThisWorkbook, yet
Test 1 uses ThisWorkbook - explicitly (For Each ws In ThisWorkbook.Worksheets)
Test 2 uses ThisWorkbook - implicitly (With Worksheets(w))
For this to work the file "3rd Party.xlsm" must be open at the same time
Try the versions bellow, and if the code is not running in ThisWorkbook, update wb accordingly
(ThisWorkbook is the file where the VBA code is executed from)
.
Version 1 - determine last row and last column
Option Explicit
Public Sub DeleteDuplicates1()
Dim wb As Workbook, ws As Worksheet, lr As Long, lc As Long, ur As Range
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
lr = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Set ur = ws.Range("A1", ws.Cells(lr, lc))
ur.RemoveDuplicates Columns:=Array(1), Header:=xlYes
Next
Application.ScreenUpdating = True
End If
End Sub
.
Version 2 - UsedRange
Public Sub DeleteDuplicates2()
Dim wb As Workbook, ws As Worksheet
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
ws.UsedRange.RemoveDuplicates Columns:=Array(1), Header:=xlYes
Next
Application.ScreenUpdating = True
End If
End Sub
If nothing happens when you run either of these versions, the file "3rd Party.xlsm" doesn't exist.
Either it's not open currently, or the name is different - maybe "3rd Party.xlsx" (with an x)
.
If you still have errors for Version 2, .UsedRange may not be what you expect
Try cleaning extra rows and columns with this Sub
Public Sub RemoveEmptyRowsAndColumns()
Dim wb As Workbook, ws As Worksheet, lr As Long, lc As Long, er As Range, ec As Range
On Error Resume Next 'Expected error: wb not found
Set wb = ThisWorkbook 'Workbooks("3rd Party.xlsm")
If Not wb Is Nothing Then
Application.ScreenUpdating = False
For Each ws In wb.Worksheets
lr = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
If lr > 1 And lc > 1 Then
Set er = ws.Range(ws.Cells(lr + 1, "A"), ws.Cells(ws.Rows.Count, "A"))
Set ec = ws.Range(ws.Cells(1, lc + 1), ws.Cells(1, ws.Columns.Count))
er.EntireRow.Delete 'Shift:=xlUp
ec.EntireColumn.Delete 'Shift:=xlToLeft
End If
Next
Application.ScreenUpdating = True
End If
End Sub

trying to add filter to pivot using vba

I am trying to run vba on Pivot Tables since I need to update like 50+ tables for my report which would only save time if I can do this using vba.
Using vba, I can copy results from pivot tables directly into cells of another sheet of the same workbook. I got stuck trying to add filters.
I was able to run the first part where I got my summary info and now I am trying to add a "Revised Territory" filter and I want to filter for "SE" then it just didn't do anything.
I used F8 to check and it looks like it just goes through without any error but did not add any filter and so I got the same info as my summary data.
My Code
Sub InsertPivotTable()
''''''''''''''''''
'''Pivot Set Up'''
''''''''''''''''''
'Declare Variables
Dim PSheet As Worksheet
Dim DSheet As Worksheet
Dim SSheet As Worksheet
Dim PCache As PivotCache
Dim PTable As PivotTable
Dim PRange As Range
Dim LastRow As Long
Dim LastCol As Long
'Insert a New Blank Worksheet
On Error Resume Next
Sheets.Add Before:=ActiveSheet
ActiveSheet.Name = "PivotTable"
Application.DisplayAlerts = True
Set PSheet = Worksheets("PivotTable")
Set DSheet = Worksheets("PIF Data")
Set SSheet = Worksheets("Summary")
'Define Data Range
LastRow = DSheet.Cells(Rows.Count, 1).End(xlUp).Row
LastCol = 76
Set PRange = DSheet.Cells(1, 1).Resize(LastRow, LastCol)
'''''''''
'Summary'
'''''''''
'Define Pivot Cache
Set PCache = ActiveWorkbook.PivotCaches.Create _
(SourceType:=xlDatabase, SourceData:=PRange). _
CreatePivotTable(TableDestination:=PSheet.Cells(3, 1), _
TableName:="NB Summary")
'Insert Blank Pivot Table
Set PTable = PCache.CreatePivotTable _
(TableDestination:=PSheet.Cells(1, 1), TableName:="NB Summary")
Dim Pvt As PivotTable
Set Pvt = Worksheets("PivotTable").PivotTables("NB Summary")
'Add fields to rows & values, re-name title of value
With Pvt
.PivotFields("Policy Form").Orientation = xlColumnField
.PivotFields("Phone/Email").Orientation = xlRowField
.AddDataField .PivotFields("Policy Number"), "Count of Policy Number", xlCount
End With
PSheet.Range("B5:B6").Copy
SSheet.Range("E6").PasteSpecial Paste:=xlPasteValues
PSheet.Range("C5:C6").Copy
SSheet.Range("G6").PasteSpecial Paste:=xlPasteValues
''''
'SE'
''''
With Pvt
.ClearAllFilters
.PivotFields("Revised Territory").PivotFilter.Add Type:=xlCaptionContains, Value1:="SE"
End With
PSheet.Range("B5:B6").Copy
SSheet.Range("E12").PasteSpecial Paste:=xlPasteValues
PSheet.Range("C5:C6").Copy
SSheet.Range("G12").PasteSpecial Paste:=xlPasteValues
'Delete PivotTable Sheet
Application.DisplayAlerts = False
Worksheets("PivotTable").Delete
Application.DisplayAlerts = True
End Sub
Try the code below, detailed explanations in the code's comments.
Modified Code
Option Explicit
Sub InsertPivotTable()
''''''''''''''''''
'''Pivot Set Up'''
''''''''''''''''''
'Declare Variables
Dim PSheet As Worksheet
Dim DSheet As Worksheet
Dim SSheet As Worksheet
Dim PCache As PivotCache
Dim PTable As PivotTable
Dim PFld As PivotField
Dim PItm As PivotItem
Dim PRange As Range
Dim LastRow As Long, LastCol As Long
' --- Check if there's already a sheet named "PivotTable" ---
On Error Resume Next
Set PSheet = ThisWorkbook.Sheets("PivotTable")
On Error GoTo 0
If PSheet Is Nothing Then ' there's no sheet named "PivotTable" >> create one
Set PSheet = ThisWorkbook.Sheets.Add(Before:=ActiveSheet)
PSheet.Name = "PivotTable"
End If
Application.DisplayAlerts = True
Set DSheet = Worksheets("PIF Data")
Set SSheet = Worksheets("Summary")
'Define Data Range
With DSheet
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
LastCol = 76 ' <-- you have 76 Colkumns of Data ??!
Set PRange = .Cells(1, 1).Resize(LastRow, LastCol)
End With
'''''''''
'Summary'
'''''''''
' Set Pivot Cache object
Set PCache = ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=PRange.Address(False, False, xlA1, xlExternal))
' create a new Pivot Table in "PivotTable" sheet, start from Cell A1
Set PTable = PSheet.PivotTables.Add(PivotCache:=PCache, TableDestination:=PSheet.Range("A1"), TableName:="NB Summary")
' Add fields to rows & values, re-name title of value
With PTable
.PivotFields("Policy Form").Orientation = xlColumnField
.PivotFields("Phone/Email").Orientation = xlRowField
.AddDataField .PivotFields("Policy Number"), "Count of Policy Number", xlCount
End With
PSheet.Range("B5:B6").Copy
SSheet.Range("E6").PasteSpecial Paste:=xlPasteValues
PSheet.Range("C5:C6").Copy
SSheet.Range("G6").PasteSpecial Paste:=xlPasteValues
''''
'SE'
''''
' ===== Filter PivotField "Revised Territory" section according to "SE" =====
With PTable
.ClearAllFilters
' set PivotField "Revised Territory"
Set PFld = .PivotFields("Revised Territory")
With PFld
.Orientation = xlPageField
.Position = 1
' loop through PivotField "Revised Territory" pivot-items
For Each PItm In .PivotItems
If PItm.Caption = "SE" Then
PItm.Visible = True
Else
PItm.Visible = False
End If
Next PItm
End With
End With
PSheet.Range("B5:B6").Copy
SSheet.Range("E12").PasteSpecial Paste:=xlPasteValues
PSheet.Range("C5:C6").Copy
SSheet.Range("G12").PasteSpecial Paste:=xlPasteValues
'Delete PivotTable Sheet
Application.DisplayAlerts = False
PSheet.Delete
Application.DisplayAlerts = True
End Sub

how to copy & paste data value in different worksheets using VBA

I am trying to copy data from workbook1 and pasting to workbook2 as per there valves if the valve is not same as previous than create a new sheet in the workbook and start pasting valve in the new sheet and do until did not find blank row in workbook1.
Sub icopy()
Dim LastRow As Long, Limit2 As Long, c As Long, d As Long, erow As Long
Dim sh1 As Worksheet, sh2 As Worksheet, sh3 As Worksheet, wb As Workbook,
wb1 As Workbook
If Is_WorkBook_Open("test.xlsx") Then
Set wb = Workbooks("test.xlsx")
Else
Set wb = Workbooks.Open("D:\Data\test.xlsx")
End If
Set sh1 = wb.Sheets("Sheet1")
LastRow = sh1.Cells(Rows.Count, 1).End(xlUp).Row
'wb.Close
MsgBox LastRow
For i = 2 To LastRow
If sh1.Cells(i, 1) = sh1.Cells(i + 1, 1) Then
If (i = 2) Then
Set wb1 = Workbooks.Open("D:\Data\Data1.xlsx")
Sheets.Add(After:=Sheets(Sheets.Count)).Name = sh1.Cells(2, 1)
Set sh2 = wb1.ActiveSheet.Name
End If
sh1.Range(Cells(i, 1), Cells(i, 3)).Copy
erow = sh2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
'sh2.Cells(erow, 1).Select
sh2.Cells(erow, 3).Paste
sh2.Paste
ActiveWorkbook.Save
Else
MsgBox i
Sheets.Add(After:=Sheets(Sheets.Count)).Name = sh1.Cells(i + 1, 1)
End If
Next i
'erow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
'ActiveSheet.Cells(erow, 1).Select
' ActiveSheet.Paste
'ActiveWorkbook.Save
'ActiveWorkbook.Close
'Application.CutCopyMode = False
End Sub
Function Is_WorkBook_Open(ByVal strWorkbookName As String) As Boolean
Dim wb As Workbook
On Error Resume Next
Set wb = Workbooks(strWorkbookName)
If Err Then
Is_WorkBook_Open = False
Else
Is_WorkBook_Open = True
End If
End Function
since I understand your valve data are adjacent (i.e. all same valve data are within one block of adjacent rows), you could consider the following:
Option Explicit
Sub icopy()
Dim sh1 As Worksheet, sh2 As Worksheet, wb1 As Workbook
Dim iRow As Long
If Is_WorkBook_Open("test.xlsx") Then
Set sh1 = Workbooks("test.xlsx").Sheets("Sheet1")
Else
Set sh1 = Workbooks.Open("D:\Data\test.xlsx").Sheets("Sheet1")
End If
Set wb1 = Workbooks.Open("D:\Data\Data1.xlsx") ' open your target workbook
With sh1
iRow = 2
With .Range("A1", .Cells(.Rows.Count, 1).End(xlUp))
Do While iRow <= .Rows.Count
.AutoFilter field:=1, Criteria1:=.Cells(iRow, 1).Value
wb1.Sheets.Add(After:=wb1.Sheets(wb1.Sheets.Count)).name = .Cells(iRow, 1).Text
With .Resize(, 3).SpecialCells(xlCellTypeVisible)
.copy Destination:=wb1.Sheets(.Cells(iRow, 1).Text).Range("a1")
iRow = .Areas(.Areas.Count).Rows(.Areas(.Areas.Count).Rows.Count).row + 1
End With
Loop
End With
.AutoFilterMode = False
End With
End Sub

Copy data from one worksheet to another based on column

I am trying to write a macro that will copy data from one worksheet to another based on column headers. Lets say in ws1 there are three columns: "product", "name", "employer" and the ws2: "product", "name", "region".
So i want the macro to do all the copying as in my original file i have over 100 column headers and it will be very time consuming for to do it myself.
I have written two macros without succes. VBA is something I cant understand for quite some time. but still managed to write something, hope you can tell me if i am going in the right direction.
this is v1
Sub Copy_rangev1()
Dim Ws1 As Worksheet, Ws2 As Worksheet
Dim SourceRange As Range, CopyRange As Range
Dim lastrow As Long
Dim i As Integer
Set Ws1 = ThisWorkbook.Worksheets("Sheet1")
Set Ws2 = ThisWorkbook.Worksheets("sheet2")
lastrow = Cells(Rows.Count, 1).End(xlUp).Row + 1
Set SourceRange = Ws2.Range("A1").CurrentRegion
Set CopyRange = Ws1.Range("A1").CurrentRegion
For i = 1 To lastrow
If SourceRange.Cells(i, 1).Value = CopyRange.Cells(i, 1) Then
SourceRange.Cells(i + 1 & lastrow, 1).Copy Destination:=CopyRange.Range("a" & lastrow)
End If
Next i
End Sub
this v2:
Sub Copyrangev2()
Dim SourceRange As Worksheet
Dim CopyRange As Worksheet
Dim lastrow As Integer
Set SourceRange = Worksheets("Sheet2")
Set CopyRange = ThisWorkbook.Worksheets("sheet1")
Dim i As Integer
lastrow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 1 To 100
If SourceRange.Range(1, i).Value = CopyRange.Range(1, i) Then
SourceRange.Range(1, i).Offset(1, 0).Copy Destination:=CopyRange.Range(1, i)
End If
Next i
End Sub
My code is a mess, but if you want me to provide any more details leave a comment, i dont expect you to given a fully workable code, a good explanation and few suggestions will do. Thanks
How about this? This code works as follows
Iterate across each column header in ws1 and see if a matching
header exists in ws2
If a match is found, copy the column contents across to the relevant column in ws2
This will work irrespective of column order. You can change the range references to suit.
Sub CopyHeaders()
Dim header As Range, headers As Range
Set headers = Worksheets("ws1").Range("A1:Z1")
For Each header In headers
If GetHeaderColumn(header.Value) > 0 Then
Range(header.Offset(1, 0), header.End(xlDown)).Copy Destination:=Worksheets("ws2").Cells(2, GetHeaderColumn(header.Value))
End If
Next
End Sub
Function GetHeaderColumn(header As String) As Integer
Dim headers As Range
Set headers = Worksheets("ws2").Range("A1:Z1")
GetHeaderColumn = IIf(IsNumeric(Application.Match(header, headers, 0)), Application.Match(header, headers, 0), 0)
End Function
Sub CustomColumnCopy()
Dim wsOrigin As Worksheet
Dim wsDest As Worksheet
Dim rngFnd As Range
Dim rngDestSearch As Range
Dim CalcMode As Long
Dim ViewMode As Long
Dim cel As Range
Dim rownum As Range
Set wsOrigin = Sheets("Sheet1")
Set wsDest = Sheets("Sheet2")
Const ORIGIN_ROW_HEADERS = 1
Const DEST_ROW_HEADERS = 1
If ActiveWorkbook.ProtectStructure = True Or _
wsOrigin.UsedRange.Parent.ProtectContents = True Then
MsgBox "Sorry, not working when the workbook or worksheet is protected", _
vbOKOnly, "Copy to new worksheet"
Exit Sub
End If
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
For Each rownum In wsOrigin.UsedRange
Set rngDestSearch = Intersect(wsDest.UsedRange, wsDest.Rows(DEST_ROW_HEADERS))
For Each cel In Intersect(wsOrigin.UsedRange, wsOrigin.Rows(ORIGIN_ROW_HEADERS))
On Error Resume Next
Set rngFnd = rngDestSearch.Find(cel.Value)
If Not rngFnd Is Nothing Then
wsDest.Cells(rownum.Cells.row, rngFnd.Column).Value = wsOrigin.Cells(rownum.Cells.row, cel.Column).Value
End If
On Error GoTo 0
Set rngFnd = Nothing
Next cel
Next rownum
ActiveWindow.View = ViewMode
Application.GoTo wsDest.Range("A1")
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
Dim keyRange As Range
Set keyRange = Range("A1")
wsDest.Range("A" & LastRow(wsDest) + 1).Sort Key1:=keyRange, Header:=xlYes
End Sub

How to copy a row to another sheet based on if then

I'm trying to write a macro that will copy a row to another sheet if certain values are met. There are multiple possible destinations. This is what I've pieced together, but I'm sure it's messy. Basically, if in column 14 there is "N/A" and in column 8 there is "APP" then copy that to the APP tab. And so on for Angie, Cathy, etc.
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Reconciliation")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Sheets("APP")
Dim ws3 As Worksheet: Set ws3 = ThisWorkbook.Sheets("Angie")
Dim ws4 As Worksheet: Set ws4 = ThisWorkbook.Sheets("Cathy")
Dim ws5 As Worksheet: Set ws5 = ThisWorkbook.Sheets("Cory")
Dim ws6 As Worksheet: Set ws6 = ThisWorkbook.Sheets("Curt")
For Each i In ws1.Range("A1:A1000")
If ws1.Cells(i, 14) = "#N/A" Then
If ws1.Cells(i, 8) = "APP" Then
ws1.Rows(i).Copy ws2.Rows(ws2.Cells(ws2.Rows.Count, 2).End(xlUp).Row + 1)
End If
End If
Next i
This will copy the row if there's a sheet with a matching name:
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Sheets("Reconciliation")
Dim ws
For Each i In ws1.Range("A1:A1000").Cells
If ws1.Cells(i.Row, 14).Value = cverr(2042) Then
Set ws = Nothing
On Error Resume Next
Set ws = ThisWorkbook.Sheets(ws1.Cells(i.Row, 8).Value)
on error goto 0
If Not ws Is Nothing Then
i.EntireRow.Copy ws.Rows(ws.Cells(ws.Rows.Count, 2).End(xlUp).Row + 1)
End If
on error goto 0
End If
Next i