As said, this is take 2 (see linked for Take 1 for my massively beginner code: https://codereview.stackexchange.com/questions/223236/)
As an overview:
I manage the bookkeeping for 40+ companies in an excel workbook. All data is added to a central sheet "Amalgamated Data" and from there data for all transactions for each Company has to be transferred to a sheet for each Company. The single company sheets are then sent to various people at various periods.
All references to the company throught the workbpook are to them as they appear as companyName.
The Code (tested and working - time scale for 40 companies on 400 rows approx 1 min) will be used at least once a day every day. It does the following:
- Checks if there have been any transactions for that Company since the start of the financial year (list of Company’s is held in a separate continuous Column)
If there have been no transactions
If there is an existing tab, clear any transactions from it (clears out any misbookkept entries)
If there are no transactions, check the next company.
- If there have been transactions:
- Check if a sheet exists for the Company
- If no Sheet, set up new tab by copying veryhidden Template preformatted and formula’d
- If a sheet exists (including if set up in previous Step)
Check that a Balance Download Record Exists, if not create one
Check that an Overview Record exists, if not create one
Copy all transactions for that Company to the Company Sheet
I have set this in a loop as the recommendation from Iven Bach of a
Dim companyName as Range For Each companyName created an error13 mismatch in the Worksheet(companyName) type with the Watch window show this as integer instead of Worksheet. I have used loop as this allows me to
Dim companyName as String
Option Explicit SUB UPDATE_BACKUP_SHEETSFIXED() 'This Sub does the following: ' Filter Amalgamated Data by companyName from table list on General Sheet ' Then ' 1. If no data: ' a. Check if a company Tab exists ' i. If not, move on to next company ' ii. If so: ' 1. If there is existing data clear and move to next company ' 2. If no existing data move to next company ' 2. Check if Company tab exists ' a. If tab does not exist, create: ' i. Tab ' ii. Balance Download Record ' iii. Overview Record ' b. If tab does exist (or has just been created above) ' i. If there is data, Clear existing ' ii. Copy transactions from Amalgamated Data Filter Dim amalgamatedDateSheet As Worksheet Set amalgamatedDateSheet = Sheets("Total Data") Dim sourceTable As ListObject Set sourceTable = amalgamatedDateSheet.ListObjects("TableFullData") Dim generalSheet As Worksheet Set generalSheet = Sheets("General") Dim templateSheet As Worksheet Set templateSheet = Sheets("Template") Dim balanceDownloadSheet As Worksheet Set balanceDownloadSheet = Sheets("Balance Download") Dim overviewSheet As Worksheet Set overviewSheet = Sheets("Overview") Dim X As Long X = 4 Application.DisplayAlerts = False Application.ScreenUpdating = False 'Get the Company name from the Company Tab Do Dim companyName As String With generalSheet companyName = .Range("A" & X).Value End With 'Clear all filter from table sourceTable.AutoFilter.ShowAllData 'Filter by Company Name sourceTable.DataBodyRange.AutoFilter Field:=2, Criteria1:="=" & companyName 'Check if transactions exist Dim firstColumnContainsNoVisibleCells As Boolean Dim companySheet As Worksheet On Error Resume Next Set companySheet = Sheets(companyName) On Error Resume Next firstColumnContainsNoVisibleCells = sourceTable.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).count <= 1 On Error GoTo 0 If firstColumnContainsNoVisibleCells Then 'If no transactions If Not companySheet Is Nothing = True Then 'If no transactions but Tab exists for Company Dim targetTable As ListObject Set targetTable = companySheet.ListObjects(1) Dim firstTargetColumnContainsVisibleCells As Boolean On Error Resume Next firstTargetColumnContainsVisibleCells = targetTable.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).count > 1 'If Data present, clear it If firstTargetColumnContainsVisibleCells Then With targetTable .DataBodyRange.Offset(1).Resize(.DataBodyRange.Rows.count - 1, .DataBodyRange.Columns.count).Rows.Delete .DataBodyRange.ClearContents End With End If Call CheckRecordsPresent(balanceDownloadSheet, companyName, overviewSheet) 'If no data present move to next company End If Else 'If transactions exist If Not companySheet Is Nothing = False Then 'If tab for Company does not exist If templateSheet.Visible = xlSheetVeryHidden Then templateSheet.Visible = xlSheetVisible 'Create and rename sheet highlight it yellow templateSheet.Copy After:=Sheets(5) ActiveSheet.Range("A20").ListObject.Name = "Table" & (companyName) ActiveSheet.Name = (companyName) With ActiveSheet.Tab .Color = XlRgbColor.rgbYellow .TintAndShade = 0 End With Set companySheet = Sheets(companyName) 'Hide template templateSheet.Visible = xlSheetVeryHidden 'Confirmation Message MsgBox "Worksheet for " & (companyName) & " created" End If 'If tab and data exist Call CheckRecordsPresent(balanceDownloadSheet, companyName, overviewSheet) 'Clear existing data and resize table Set targetTable = companySheet.ListObjects(1) On Error Resume Next firstTargetColumnContainsVisibleCells = targetTable.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).count > 1 If firstTargetColumnContainsVisibleCells Then With targetTable .DataBodyRange.Offset(1).Resize(.DataBodyRange.Rows.count - 1, .DataBodyRange.Columns.count).Rows.Delete .DataBodyRange.ClearContents End With End If 'Find first row of table (last row of sheet as data previously cleared) Dim lastTargetRow As Long lastTargetRow = companySheet.Range("B" & Rows.count).End(xlUp).Row With sourceTable.DataBodyRange.SpecialCells(xlCellTypeVisible).Copy With companySheet .ListObjects(1).AutoFilter.ShowAllData .Range("A" & lastTargetRow).PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:=xlNone Application.CutCopyMode = False End With End With End If 'Loop back to get a new Company's name in Company Table Set companySheet = Nothing X = X + 1 'Loop back to get a new Company's name in Employee Roster Loop While generalSheet.Range("A" & X).Value <> vbNullString 'At end of loop turn screen refresh etc back on Application.DisplayAlerts = True Application.ScreenUpdating = True amalgamatedDateSheet.Select 'Clear all filter from table sourceTable.AutoFilter.ShowAllData MsgBox "All Sheets Updated" End Sub Private Sub CheckRecordsPresent(ByVal balanceDownloadSheet As Worksheet, ByVal companyName As String, ByVal overviewSheet As Worksheet) 'Check Balance Download Records - create if there isn't one Dim lastBalanceRow As Long lastBalanceRow = balanceDownloadSheet.Range("a" & Rows.count).End(xlUp).Row Dim rangeBalanceDownloadFound As Range Set rangeBalanceDownloadFound = balanceDownloadSheet.Range(balanceDownloadSheet.Range("A4"), balanceDownloadSheet.Range("A" & lastBalanceRow)).Find(companyName) If rangeBalanceDownloadFound Is Nothing Then With balanceDownloadSheet .ListObjects(1).ListRows.Add .Rows(lRow).Copy .Range("A" & lastBalanceRow + 1).PasteSpecial Paste:=xlPasteValuesAndNumberFormats, Operation:=xlNone Application.CutCopyMode = False .Range("a" & lRow + 1).Value = companyName End With End If 'Check if front page record exists Dim lastOverviewRow As Long lastOverviewRow = overviewSheet.Range("a" & Rows.count).End(xlUp).Row Dim rangeOverviewFound As Range Set rangeOverviewFound = overviewSheet.Range(overviewSheet.Range("A6"), overviewSheet.Range("A" & lastOverviewRow)).Find(companyName) If rangeOverviewFound Is Nothing Then With overviewSheet .Range("A53:E53").Copy .Range("A53:E53").Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove .Range("A53").Value = companyName End With End If End Sub
Massive thanks to IvenBack, AJD and Mathieu Guindon for unravelling my (miraculously working) ridiculously messy previous code attempt, below is take 2 that I hope is much more streamlined and removes all (?!) of the redundant lines. Hopefully this is much improved and not too much of a bastardisation of the brilliant recommendations and codes you wrote.
All help gratefully received as I still have a long way to go.