Merging tables and arrays from multiple sheets into one consolidated table - arrays

I am very new to VBA and struggling!
I've tried searching the forums but can't find anything close enough to my situation...
I have 30+ sheets titled 001, 002 ...0nn
I want to create a new sheet title 'Actions summary'
I want this sheet to contain compiled information from each sheet with sheet name '0nn' (or i tried limiting the code to sheet names that are integers) - -
From each sheet i want to copy the information from columns A to G, And rows 9 to last row with information in.
I would also like the heading (A8:G8) at the top of the new 'actions summary' sheet.
SCREEN SHOT typical sheet 0nn format
Been going a bit mad and would really appreciate some simple help, ideally the code required with explanations for what each bit is doing so i can learn.
My Attempt below:
Function LastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function
Function LastCol(sh As Worksheet)
On Error Resume Next
LastCol = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Column
On Error GoTo 0
End Function
Sub CopyRangeFromMultiWorksheets()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
' Delete the summary sheet if it exists.
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Actions Summary").Delete
On Error GoTo 0
Application.DisplayAlerts = True
' Add a new summary worksheet.
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "Actions Summary"
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each sh In ActiveWorkbook.Worksheets
'If LCase(Left(sh.Name, 1)) = "0" Then
If IsNumeric(sh.Name) = True Then
Debug.Print (sh.Name)
' Find the last row with data on the summary worksheet.
Last = LastRow(DestSh)
'LastRow = Cells.SpecialCells(xlCellTypeLastCell).Row
Debug.Print (Last)
' Specify the range to place the data.
Set CopyRng = sh.Range("A9").CurrentRegion
Set CopyRng = Range(Cells(9, 1), Cells(Last, 7))
' Test to see whether there are enough rows in the summary
' worksheet to copy all the data.
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the " & _
"summary worksheet to place the data."
GoTo ExitTheSub
End If
' This statement copies values and formats from each
' worksheet.
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
' Optional: This statement will copy the sheet
' name in the H column.
' DestSh.Cells(Last + 1, "H").Resize(CopyRng.Rows.Count).Value = sh.Name
End If
Next
'ExitTheSub:
Application.Goto DestSh.Cells(1)
' AutoFit the column width in the summary sheet.
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Sub selectA1_and_insertRow()
'
' selectA1_and_insertRow Macro
Worksheets("Actions Summary").Rows("1:1").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Columns("B:B").ColumnWidth = 36.43
Rows("1:1").Select
'Range.Copy to other worksheets
Worksheets("001").Range("A8:G8").Copy Worksheets("Actions Summary").Range("A1:G1")
End Sub
Many thanks in advance.
Tom
CODE:
Here's the new code:
Sub UpDate_List_v2()
Dim wb As Workbook
Dim ws As Worksheet
Dim wsSum As Worksheet
Dim rLastCell As Range
Dim lCalc As XlCalculation
Dim bHasHeaders As Boolean
'Turn off calculation, events, and screenupdating
'This allows the code to run faster and prevents "screen flickering"
With Application
lCalc = .Calculation
.Calculation = xlCalculationManual
.EnableEvents = False
.ScreenUpdating = False
End With
Set wb = ActiveWorkbook
'Check if Actions Summary sheet exists already or not
On Error Resume Next
Set wsSum = wb.Sheets("Actions summary")
On Error GoTo 0
If wsSum Is Nothing Then
'Does not exist, create it
Set wsSum = wb.Sheets.Add(Before:=wb.Sheets(1))
wsSum.Name = "Actions summary"
bHasHeaders = False
Else
'Already exists, clear previous data
wsSum.UsedRange.Offset(1).Clear
bHasHeaders = True
End If
'Loop through all sheets in the workbook
For Each ws In wb.Sheets
'Only look for worksheets whose names are numbers (e.g. "001", "002", etc)
If IsNumeric(ws.Name) Then
'Check if the "Actions Summary" sheet already has headers
If bHasHeaders = False Then
'Does not have headers yet
With ws.Range("A8:M8")
'Check if this sheet has headers in A8:G8
If WorksheetFunction.CountBlank(.Cells) = 0 Then
'This sheet does have headers, copy them over
.Copy wsSum.Range("A1")
bHasHeaders = True
End If
End With
End If
'Find the last row of the sheet
Set rLastCell = ws.Cells.Find("*", ws.Range("A1"), SearchDirection:=xlPrevious)
If Not rLastCell Is Nothing Then
'Check if the last row is greater than the header row
If rLastCell.Row > 8 Then
'Last row is greater than the header row so there is data
'Check if the "Actions Summary" sheet has enough rows to hold the data
If wsSum.Cells(wsSum.Rows.Count, "A").End(xlUp).Row + rLastCell.Row - 8 > wsSum.Rows.Count Then
'Not enough rows, return error and exit the subroutine
MsgBox "There are not enough rows in the summary worksheet to place the data.", , "Data Overflow"
Exit Sub
Else
'Does have enough rows, copy the data - Values
ws.Range("A9:M" & rLastCell.Row).Copy
With wsSum.Cells(wsSum.Rows.Count, "A").End(xlUp).Offset(1)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
End If
End If
End If
End If
Next ws
'Sheets("Actions summary").Columns("H:L").EntireColumn.Delete 'Delete unwanted columns
'Sheets("Actions summary").Columns("H:L").Hidden = True 'Hide unwanted columns
Worksheets("Actions summary").Columns("H:j").Hidden = True
Worksheets("Actions summary").Columns("L").Hidden = True
Sheets("Actions summary").Columns("H").Style = "currency" 'Set to £
Application.CutCopyMode = False 'Remove the cut/copy border
'wsSum.Range("A1").CurrentRegion.EntireColumn.AutoFit 'Autofit columns on the "Actions Summary" sheet
'Turn calculation, events, and screenupdating back on
With Application
.Calculation = lCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub

Something like this should work for you. I have commented the code for clarity.
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim wsSum As Worksheet
Dim rLastCell As Range
Dim lCalc As XlCalculation
Dim bHasHeaders As Boolean
'Turn off calculation, events, and screenupdating
'This allows the code to run faster and prevents "screen flickering"
With Application
lCalc = .Calculation
.Calculation = xlCalculationManual
.EnableEvents = False
.ScreenUpdating = False
End With
Set wb = ActiveWorkbook
'Check if Actions Summary sheet exists already or not
On Error Resume Next
Set wsSum = wb.Sheets("Actions summary")
On Error GoTo 0
If wsSum Is Nothing Then
'Does not exist, create it
Set wsSum = wb.Sheets.Add(Before:=wb.Sheets(1))
wsSum.Name = "Actions summary"
bHasHeaders = False
Else
'Already exists, clear previous data
wsSum.UsedRange.Offset(1).Clear
bHasHeaders = True
End If
'Loop through all sheets in the workbook
For Each ws In wb.Sheets
'Only look for worksheets whose names are numbers (e.g. "001", "002", etc)
If IsNumeric(ws.Name) Then
'Check if the "Actions Summary" sheet already has headers
If bHasHeaders = False Then
'Does not have headers yet
With ws.Range("A8:G8")
'Check if this sheet has headers in A8:G8
If WorksheetFunction.CountBlank(.Cells) = 0 Then
'This sheet does have headers, copy them over
.Copy wsSum.Range("A1")
bHasHeaders = True
End If
End With
End If
'Find the last row of the sheet
Set rLastCell = ws.Cells.Find("*", ws.Range("A1"), SearchDirection:=xlPrevious)
If Not rLastCell Is Nothing Then
'Check if the last row is greater than the header row
If rLastCell.Row > 8 Then
'Last row is greater than the header row so there is data
'Check if the "Actions Summary" sheet has enough rows to hold the data
If wsSum.Cells(wsSum.Rows.Count, "A").End(xlUp).Row + rLastCell.Row - 8 > wsSum.Rows.Count Then
'Not enough rows, return error and exit the subroutine
MsgBox "There are not enough rows in the summary worksheet to place the data.", , "Data Overflow"
Exit Sub
Else
'Does have enough rows, copy the data - Values
ws.Range("A9:G" & rLastCell.Row).Copy
With wsSum.Cells(wsSum.Rows.Count, "A").End(xlUp).Offset(1)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
End If
End If
End If
End If
Next ws
Application.CutCopyMode = False 'Remove the cut/copy border
wsSum.Range("A1").CurrentRegion.EntireColumn.AutoFit 'Autofit columns on the "Actions Summary" sheet
'Turn calculation, events, and screenupdating back on
With Application
.Calculation = lCalc
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub

Related

Subscript out of range when trying to loop through array to read values

I have a string of predefined worksheets, that I need to run specific code for. I get a compile error.
The code is set up to copy data from one sheet to another.
How do I do the same for multiple sheets?
When I step through the code sht is showing the MHP60,MHP61,MHP62 and not just MHP60.
I get a subscript out of range error.
Sub Prepare_CYTD_Report()
Dim addresses() As String
Dim addresses2() As String
Dim SheetNames() As String
Dim SheetNames2() As String
Dim wb1 As Workbook, wb2 As Workbook
Dim my_Filename
'Declare variables for MHP60, MHP61, MHP62 Trial Balance Values
Dim i, lastcol As Long
Dim tabNames, cell As Range
Dim tabName As String
Dim sht As Variant
addresses = Strings.Split("A9,A12:A26,A32:A38,A42:A58,A62:A70,A73:A76,A83:A90", ",") 'Trial Balance string values
addresses2 = Strings.Split("G9,G12:G26,G32:G38,G42:G58,G62:G70,G73:G76,G83:G90", ",") 'Prior Month string values
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
'SheetNames2 = Strings.Split("MHP60-CYTDprior,MHP61-CYTDprior,MHP62-CYTDprior")
Set wb1 = ActiveWorkbook 'Revenue & Expenditure Summary Workbook
'*****************************Open CYTD files
my_Filename = Application.GetOpenFilename(fileFilter:="Excel Files,*.xl*;*.xm*", Title:="Select File to create CYTD Reports")
If my_Filename = False Then
Exit Sub
End If
Application.ScreenUpdating = False
Set wb2 = Workbooks.Open(my_Filename)
'*****************************Load Column Header Strings & Copy Data
For Each sht In SheetNames
lastcol = wb1.Sheets(sht).Cells(5, Columns.Count).End(xlToLeft).Column
On Error Resume Next
Set tabNames = wb1.Sheets(sht).Cells(4, 3).Resize(1, lastcol - 2).SpecialCells(xlCellTypeConstants)
'actual non-formula text values on row 4 from column C up to column lastCol'
On Error GoTo 0
If Err.Number <> 0 Then
MsgBox "No headers were found on row 4 of MHP60", vbCritical
Exit Sub
End If
For Each cell In tabNames
tabName = Strings.Trim(cell.Value2)
'dedicated variable in case of requirement for further parsing (space/comma elimination?)'
If CStr(wb1.Sheets(sht).Evaluate("ISREF('[" & wb2.Name & "]" & tabName & "'!$A$1)")) = "True" Then
'If wb2 has a tab named for the value in tabName
For i = 0 To UBound(addresses)
wb2.Sheets(tabName).Range(addresses(i)).Value2 = wb1.Sheets(sht).Range(addresses(i)).Offset(0, cell.Column - 1).Value2
'Debug.Print "data for " & wb2.Sheets(tabName).Range(addresses(i)).Address(, , , True) & " copied from " & wb1.Sheets("MHP60").Range(addresses(i)).Offset(0, cell.Column - 1).Address(, , , True)
Next i
Else
Debug.Print "A tab " & tabName & " was not found in " & wb2.Name
End If
Next cell
Next sht
MsgBox "CYTD Report Creation Complete", vbOKOnly
Application.ScreenUpdating = True
End Sub
Split by what?
SheetNames = Strings.Split("MHP60,MHP61,MHP62")
Split by comma? Then use the following instead:
SheetNames = Strings.Split("MHP60,MHP61,MHP62", ",")
Alternative
Dim SheetNames() As Variant ' needs to be Variant to work with Array()
SheetNames = Array("MHP60", "MHP61", "MHP62")
This should be quicker as your macro does not need to split the string and has it as array directly.

Compare two sheets and highlight differences on each sheet - is looping the only way?

I am seeking advice in relation to improving performance for a large data set (roughly 175k lines on each sheet and 39 columns A:AM (comparing sheet1 vs sheet2). These sheets are exported from access and my VBA is written in Access. I have coding that employs a "for" loop that checks cell by cell and highlights if there is a mismatch in each relative cell.
My question - will using an array or dictionary function speed up the process? If yes, can you provide bread crumbs to shed some light on how to execute? This code currently takes approximately 3 hours to complete. Roughly 2 minutes for the export from Access to Excel and the rest of the time represents looping and highlighting.
As a note - I have written code for conditional formatting and that works incredibly fast. The main problem is that I am unable to copy/paste the sheets with highlighted cells into new sheets while leaving the conditions behind. I would be interested to hear if any have found a way to maneuver that mine field.
Code below:
DoCmd.SetWarnings False
Dim xlapp As Excel.Application
Dim xlbook As Excel.Workbook
Dim xlSheet, xlSheetPre, xlSheetPost As Excel.Worksheet
Dim SQL As String
Dim rs1 As DAO.Recordset
Dim iSheet As Long, iRow As Long, iCol As Long, cols As Long
Dim MaxLastRow As Long, MaxLastCol As Long
Dim LastRow1 As Range, LastRow2 As Range
Dim LastCol1 As Range, LastCol2 As Range
Dim i As Integer
SQL = "SELECT * From Pre"
Set rs1 = CurrentDb.OpenRecordset(SQL, dbOpenSnapshot)
Set xlapp = Excel.Application
xlapp.Visible = True
Set xlbook = xlapp.Workbooks.Add
i = 1
Do
Set xlSheet = Sheets.Add(after:=Sheets(Sheets.Count))
i = i + 1
Loop Until i = 2 ' the number 2 represents how many sheets you want to add to the
workbook
Set xlSheet = xlbook.Worksheets(1) ' Finds worksheet (1) and begins loading data from SQL
table above
With xlSheet
.Name = "Pre" ' Name the worksheet
.Range("a1:am1").Font.Bold = True 'Converts headers in row 1 to
bold font
.Range("A2").CopyFromRecordset rs1 'Copies all data from selected
table (SQL)into your worksheet
.Range("a1").AutoFilter ' Adds filter to your columns
.Cells.Columns.AutoFit ' Adjust worksheet column width to autofit
your data
.Range("a1:am1").Interior.ColorIndex = 37 ' Changes color of cell
' This loop reads all headers in your access table and places
them on worksheet
For cols = 0 To rs1.Fields.Count - 1
.Cells(1, cols + 1).Value = rs1.Fields(cols).Name
Next
End With
SQL = "SELECT * From Post"
Set rs1 = CurrentDb.OpenRecordset(SQL, dbOpenSnapshot)
Set xlSheet = xlbook.Worksheets(2)
With xlSheet
.Name = "Post" ' Name the worksheet
.Range("a1:am1").Font.Bold = True 'Converts headers in row 1 to
bold font
.Range("A2").CopyFromRecordset rs1 'Copies all data from selected
table (SQL)into your worksheet
.Range("a1").AutoFilter ' Adds filter to your columns
.Cells.Columns.AutoFit ' Adjust worksheet column width to autofit
your data
.Range("a1:am1").Interior.ColorIndex = 37 ' Changes color of cell
' This loop reads all headers in your access table and places
them on worksheet
' This loop reads all headers in your access table and places them on worksheet
For cols = 0 To rs1.Fields.Count - 1
.Cells(1, cols + 1).Value = rs1.Fields(cols).Name
Next
End With
Set xlSheetPre = xlbook.Worksheets(1)
Set xlSheetPost = xlbook.Worksheets(2)
Set LastRow1 = xlSheetPre.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
Set LastRow2 = xlSheetPost.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
If Not LastRow1 Is Nothing Then
If Not LastRow2 Is Nothing Then
If LastRow1.Row > LastRow2.Row Then
MaxLastRow = LastRow1.Row
Else
MaxLastRow = LastRow2.Row
End If
Else
MaxLastRow = LastRow1.Row
End If
Else
MaxLastRow = LastRow2.Row
End If
Set LastCol1 = xlSheetPre.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious)
Set LastCol2 = xlSheetPost.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious)
If Not LastCol1 Is Nothing Then
If Not LastCol2 Is Nothing Then
If LastCol1.Column > LastCol2.Column Then
MaxLastCol = LastCol1.Column
Else
MaxLastCol = LastCol2.Column
End If
Else
MaxLastCol = LastCol1.Column
End If
Else
MaxLastCol = LastCol2.Column
End If
For iRow = 2 To MaxLastRow 'starting loop on row 2
For iCol = 4 To MaxLastCol 'starting loop on column 4
If xlSheetPre.Cells(iRow, iCol).Value <> xlSheetPost.Cells(iRow, iCol).Value Then
xlSheetPre.Cells(iRow, iCol).Interior.ColorIndex = 4
xlSheetPost.Cells(iRow, iCol).Interior.ColorIndex = 4
End If
Next iCol
Next iRow
SubExit:
On Error Resume Next
rs1.Close
Set rs1 = Nothing
DoCmd.SetWarnings True
Exit Sub
Try and reduce the number of records you have to compare by only extracting those with differences. There are several ways you could do that in SQL but as a proof of concept this compares each column in turn creating a temporary table of keys which is used to filter the records extracted.
Option Compare Database
Option Explicit
Sub DumpToExcel()
Dim n As Integer, SQL As String, fname
' field names
fname = Array("", "F1", "F2", "F3", "F4", "F5", _
"F6", "F7", "F8", "F9", "F10")
' identify diff records
Debug.Print UBound(fname)
DoCmd.SetWarnings False
For n = 1 To UBound(fname)
If n = 1 Then ' create table
SQL = " SELECT post.ID, """ & n & """ AS Col INTO tmp"
Else
SQL = " INSERT INTO tmp" & _
" SELECT post.ID, """ & n & """ AS Col"
End If
SQL = SQL & _
" FROM Post LEFT JOIN pre ON Post.id = pre.id" & _
" WHERE NZ([pre].[" & fname(n) & "],"")<>NZ([post].[" & fname(n) & "],"");"
DoCmd.RunSQL SQL
Next
DoCmd.SetWarnings True
' extract data
Dim rs1 As DAO.Recordset
SQL = " SELECT * FROM pre" & _
" WHERE (((pre.[ID]) In " & _
" (SELECT DISTINCT(ID) FROM tmp )));"
Set rs1 = CurrentDb.OpenRecordset(SQL, dbOpenSnapshot)
' create excel
Dim xlapp As Excel.Application, xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Set xlapp = Excel.Application
xlapp.Visible = True
Set xlBook = xlapp.Workbooks.Add
'add sheets as required
Do While xlBook.Sheets.Count < 2
xlBook.Sheets.Add
Loop
' copy recordset to sheet
xlBook.Sheets(1).Range("A2").CopyFromRecordset rs1
MsgBox "Done"
End Sub
"My question - will using an array or dictionary function speed up the process?"
Speaking from experience, the answer is: No, it will not. The reason is that you will have to read the cells in the worksheet to populate an array or a dictionary in the first place, so... Looping is it, really, and you need to organize the data (usually by proper sorting of the lists, tables, ranges, whatever) to minimize searching for the matching records (rows) to make your loops run faster.
If you are in Access then you can do that directly with the recordsets, providing your company's network security does not interfere with movement withing recordset objects (mine does interfere, and very severely at that--Tanium is a real menace!)
Here's an array-based comparison.
Compiled but not tested:
Sub Tester()
Dim xlapp As Excel.Application
Dim xlbook As Excel.Workbook
Dim xlSheet, wsPre As Excel.Worksheet, wsPost As Excel.Worksheet
Dim rowsPost As Long, rowsPre As Long, rowsMax As Long
Dim colsPre As Long, colsPost As Long, colsMax As Long, flag As Boolean
Dim r As Long, c As Long, rngPre As Range, rngPost As Range, arrPre, arrPost
DoCmd.SetWarnings False
Set xlapp = New Excel.Application 'forgot "New" here?
xlapp.Visible = True
Set xlbook = xlapp.Workbooks.Add()
Do While xlbook.Worksheets.Count < 2 'how many sheets you need in the Workbook
xlbook.Sheets.Add
Loop
Set wsPre = xlbook.Worksheets(1)
Set wsPost = xlbook.Worksheets(2)
PutInWorksheet "SELECT * From Pre", wsPre, "Pre"
PutInWorksheet "SELECT * From Post", wsPost, "Post"
Set rngPre = wsPre.Range("A1").CurrentRegion 'data ranges
Set rngPost = wsPost.Range("A1").CurrentRegion
arrPre = rngPre.Value 'read data to arrays
arrPost = rngPost.Value
rowsPre = UBound(arrPre, 1) 'compare array bounds...
rowsPost = UBound(arrPost, 1)
rowsMax = xlapp.Max(rowsPre, rowsPost)
colsPre = UBound(arrPre, 2)
colsPost = UBound(arrPost, 2)
colsMax = xlapp.Max(colsPre, colsPost)
For r = 2 To rowsMax
flag = (r > rowsPre) Or (r > rowsPost) 'flag whole row if have run out of data in one set...
If flag Then
FlagRanges rngPre.Cells(r, 1).Resize(1, colsMax), _
rngPost.Cells(r, 1).Resize(1, colsMax)
Else
'have two rows to compare
For c = 1 To colsMax
flag = (c > colsPre) Or (c > colsPost) 'run out of cols in one dataset?
If Not flag Then
flag = arrPre(r, c) <> arrPost(r, c) 'compare data
End If
If flag Then
'no data to compare, or data does not match
FlagRanges rngPre.Cells(r, c), rngPost.Cells(r, c)
End If
Next c
End If
Next r
End Sub
Sub FlagRanges(rng1 As Excel.Range, rng2 As Excel.Range)
Const CLR_INDX = 4
rng1.Interior.ColorIndex = CLR_INDX
rng2.Interior.ColorIndex = CLR_INDX
End Sub
'run a query and put the results on a worksheet starting at A1
Sub PutInWorksheet(SQL As String, ws As Excel.Worksheet, _
Optional newName As String = "")
Dim f, c As Excel.Range, rs As dao.Recordset
If Len(newName) > 0 Then ws.Name = newName
Set rs = CurrentDb.OpenRecordset(SQL, dbOpenSnapshot)
Set c = ws.Range("A1")
For Each f In rs.Fields
c.Value = f.Name
c.Font.Bold = True
Next f
ws.Range("A2").CopyFromRecordset rs
rs.Close
End Sub

Object doesn't support property or method - array of sheets

I have a master file having different account details. I am trying to make a code that will send a copy of the workbook after deleting unnecessary account details and mail it. It is working fine for one sheet but when I am using array for multiple sheets it is giving me object doesn't support method in this line of code ".DisplayPageBreaks = False".
Here is my code:
Sub Mail_Sheets_Array()
'Working in Excel 2000-2016
'For Tips see: http://www.rondebruin.nl/win/winmail/Outlook/tips.htm
Dim FileExtStr As String
Dim FileFormatNum As Long
Dim Sourcewb As Workbook
Dim Destwb As Workbook
Dim TempFilePath As String
Dim TempFileName As String
Dim OutApp As Object
Dim OutMail As Object
Dim sh As Worksheet
Dim TheActiveWindow As Window
Dim TempWindow As Window
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set Sourcewb = ActiveWorkbook
'Copy the sheets to a new workbook
'We add a temporary Window to avoid the Copy problem
'if there is a List or Table in one of the sheets and
'if the sheets are grouped
With Sourcewb
Set TheActiveWindow = ActiveWindow
Set TempWindow = .NewWindow
.Sheets(Array("REC_INT", "REC_EXT")).Copy
End With
'Close temporary Window
TempWindow.Close
Set Destwb = ActiveWorkbook
'Determine the Excel version and file extension/format
With Destwb
If Val(Application.Version) < 12 Then
'You use Excel 97-2003
FileExtStr = ".xls": FileFormatNum = -4143
Else
'You use Excel 2007-2016
Select Case Sourcewb.FileFormat
Case 51: FileExtStr = ".xlsx": FileFormatNum = 51
Case 52:
If .HasVBProject Then
FileExtStr = ".xlsm": FileFormatNum = 52
Else
FileExtStr = ".xlsx": FileFormatNum = 51
End If
Case 56: FileExtStr = ".xls": FileFormatNum = 56
Case Else: FileExtStr = ".xlsb": FileFormatNum = 50
End Select
End If
End With
'Change all cells in the worksheets to values if you want
For Each sh In Destwb.Worksheets
sh.Select
With sh.UsedRange
.Cells.Copy
.Cells.PasteSpecial xlPasteValues
.Cells(1).Select
End With
Application.CutCopyMode = False
Destwb.Worksheets(1).Select
Next sh
'Save the new workbook/Mail it/Delete it
TempFilePath = Environ$("temp") & "\"
TempFileName = "Part of " & Sourcewb.name & " " & Format(Now, "dd-mmm-yy h-mm-ss")
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim prow As Long
Dim r As Long
Dim x As Long
Dim y As Long
Dim CalcMode As Long
Dim ViewMode As Long
r = 0
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
'We use the ActiveSheet but you can replace this with
With Destwb.Sheets(Array("REC_INT", "REC_EXT"))
' With ActiveSheet
'We select the sheet so we can change the window view
.Select
'If you are in Page Break Preview Or Page Layout view go
'back to normal view, we do this for speed
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
'Turn off Page Breaks, we do this for speed
.DisplayPageBreaks = False
'Set the first and last row to loop through
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
'We loop from Lastrow to Firstrow (bottom to top)
For Lrow = 9 To Lastrow Step 1
'We check the values in the A column in this example
With .Cells(Lrow, "C")
If Not IsError(.Value) Then
If Cells(Lrow, "D").Value = "Total" Then
GoTo y
End If
If .Value = Sheet1.Cells(2, 6) Then
r = r + 1
End If
If .Value <> Sheet1.Cells(2, 6) Then
If .Value = "" Then
r = 0
End If
prow = Lrow - r
If Cells(prow, "C").Value = Sheet1.Cells(2, 6) Then
r = r + 1
GoTo x
End If
.EntireRow.ClearContents
'This will delete each row with the Value "ron"
'in Column A, case sensitive.
x:
End If
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
y:
Range(Cells(9, 3), Cells(Lrow, 3)). _
SpecialCells(xlCellTypeBlanks).EntireRow.Delete
'xxxxxxxxxxxxxxxxxx
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With Destwb
.SaveAs TempFilePath & TempFileName & FileExtStr, FileFormat:=FileFormatNum
On Error Resume Next
With OutMail
.To = "hadi#siemens.com"
.CC = ""
.BCC = ""
.Subject = "This is the Subject line"
.Body = "Hi there"
.Attachments.Add Destwb.FullName
'You can add other files also like this
'.Attachments.Add ("C:\test.txt")
'.Send 'or use
.Display
End With
On Error GoTo 0
.Close savechanges:=False
End With
'Delete the file you have send
Kill TempFilePath & TempFileName & FileExtStr
Set OutMail = Nothing
Set OutApp = Nothing
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
You are trying to run a property only supported on a specified sheet, on multiple sheets at once. This is not supported, hence the error 438.
You can try to loop these sheets:
For Each ws In Destwb.Sheets
If ws.Name = "REC_INT" or ws.Name = "REC_EXT" then
Destwb.Worksheets(ws.Name).DisplayPageBreaks = False
End if
Next ws
I think you don't need to check for the sheets names, as you copy just the two of them into a new workbook.

Using an array to pull multiple variables of data and copy to another worksheet

I have a worksheet that I want to search for a certain criteria in column "A" and once I find the multiple variables I am looking to copy all of those particular rows that are in the array to another worksheet. Here is the code I have, I am having trouble with it copying only the rows from the last number of the array over (seems to me like it is copying on top of each other and only keeping the last number in the array).
Sub Copy_Changed_Rows()
Dim Lastrow As Long
With Sheets("DataDump")
If .Range("A:A").Find("397", , xlValues, xlWhole, , , False) Is Nothing Then
MsgBox "No ""Changed"" rows found. ", , "No Rows Copied": Exit Sub
Else
Application.ScreenUpdating = False
Lastrow = .Range("A" & Rows.Count).End(xlUp).Row + 1
.Range("A1:A" & Lastrow).AutoFilter Field:=1, Criteria1:=Array("397", "437", "509", "646")
.Range("A2:A" & Lastrow).SpecialCells(xlCellTypeVisible).EntireRow.Copy
Sheets("Paste").Range("A2").PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, False, False
.AutoFilterMode = False
'Position on cell A3
With Application
.CutCopyMode = False
.Goto Sheets("Paste").Range("A2")
.ScreenUpdating = True
End With
MsgBox "All matching data has been copied.", , "Copy Complete"
End If
End With
End Sub
What I found was there was one piece missing on the filter at the end of the filter line add , Operator:=xlFilterValues
Sub Copy_Changed_Rows()
Dim Lastrow As Long
With Sheets("DataDump")
If .Range("A:A").Find("397", , xlValues, xlWhole, , , False) Is Nothing Then
MsgBox "No ""Changed"" rows found. ", , "No Rows Copied": Exit Sub
Else
Application.ScreenUpdating = False
Lastrow = .Range("A" & Rows.Count).End(xlUp).Row + 1
.Range("A1:A" & Lastrow).AutoFilter Field:=1, Criteria1:=Array("397", "437", "509", "646"), Operator:=xlFilterValues
.Range("A2:A" & Lastrow).SpecialCells(xlCellTypeVisible).EntireRow.Copy
Sheets("Paste").Range("A2").PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, False, False
.AutoFilterMode = False
'Position on cell A3
With Application
.CutCopyMode = False
.Goto Sheets("Paste").Range("A2")
.ScreenUpdating = True
End With
MsgBox "All matching data has been copied.", , "Copy Complete"
End If
End With

If data doesn't exist add to bottom of list

Basically I'm working on a excel document which copies values from this workbook into another if they match. So if they have the same ID and a "yes" then a field is updated. However in some instances it may be that the ID doesn't exist in the workbook im copying to, but if there is a "yes" I would like to add it to the next empty row.
Below is what I have so far
Dim fpath As String
Dim owb As Workbook
Dim thisone As String
Dim Siteref(1000) As String, siteref2(1000) As String, sitename(1000) As String, sitename2(1000) As String
fpath = "my file path"
Set owb = Application.Workbooks.Open(fpath) 'open location and file
Dim Master As Worksheet 'declare both
Dim Slave As Worksheet
Set Slave = owb.Worksheets("Schedule") 'sheet in workbook im copying too
Set Master = ThisWorkbook.Worksheets("Tbl_Primary") 'sheet from workbook im in
For i = 1 To 1000 '(the slave sheet) 'for first 1000 cells
For j = 1 To 1000 '(the master sheet)
If Master.Cells(j, 2).Value = "" Then
GoTo lastline
End If ' if ID cell is blank jump to last line
If Master.Cells(j, 2).Value = Slave.Cells(i, 1).Value And Master.Cells(j, 65).Value = "Yes" Then
Slave.Cells(i, 4).Value = Master.Cells(j, 18).Value 'If the ID equals that in the slave sheet and there is a yes ticked the copy address
End If
lastline:
Next
Next
MsgBox ("Data Transfer Successful")
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Tbl_Primary").Delete 'delete sheet
Application.DisplayAlerts = True
ThisWorkbook.Save
ThisWorkbook.Close 'save and close it
Give this one a try and let me know if it works. I wrote it "blind" without testing. So, I am not entirely sure it will work:
Dim bolFound As Boolean
Dim lngLastRow As Long
Dim fpath As String
Dim owb As Workbook
Dim Master As Worksheet 'declare both
Dim Slave As Worksheet
fpath = ActiveWorkbook.Path
Set owb = Application.Workbooks.Open(fpath) 'open location and file
Set Master = ThisWorkbook.Worksheets("Tbl_Primary") 'sheet from workbook im in
Set Slave = owb.Worksheets("Schedule") 'sheet in workbook im copying too
'
lngLastRow = Slave.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
For j = 1 To 1000 '(the master sheet)
bolFound = False
For i = 1 To 1000 '(the slave sheet) 'for first 1000 cells
If Trim(Master.Cells(j, 2).Value2) = vbNullString Then Exit For 'if ID cell is blank jump to last line
If Master.Cells(j, 2).Value = Slave.Cells(i, 1).Value And _
Master.Cells(j, 65).Value = "Yes" Then
Slave.Cells(i, 4).Value = Master.Cells(j, 18).Value 'If the ID equals that in the slave sheet and there is a yes ticked the copy address
bolFound = True
End If
Next
If bolFound = False And _
Master.Cells(j, 65).Value = "Yes" Then
Slave.Cells(lngLastRow, 4).Value = Master.Cells(j, 18).Value 'adding the new entry to the list
lngLastRow = lngLastRow + 1
End If
Next
MsgBox ("Data Transfer Successful")
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Tbl_Primary").Delete 'delete sheet
Application.DisplayAlerts = True
ThisWorkbook.Save
ThisWorkbook.Close 'save and close it
NOT tested.
Dim fpath As String
Dim owb As Workbook
Dim thisone As String
Dim Siteref(1000) As String, siteref2(1000) As String, sitename(1000) As String, sitename2(1000) As String
Dim lastRow As Long
fpath = "my file path"
Set owb = Application.Workbooks.Open(fpath) 'open location and file
Dim Master As Worksheet 'declare both
Dim Slave As Worksheet
Set Slave = owb.Worksheets("Schedule") 'sheet in workbook im copying to
Set Master = ThisWorkbook.Worksheets("Tbl_Primary") 'sheet from workbook im in
For i = 1 To 1000 '(the slave sheet) 'for first 1000 cells
For j = 1 To 1000 '(the master sheet)
If Master.Cells(j, 2).Value = "" Then
Exit For
End If ' if ID cell is blank jump to last line
If Master.Cells(j, 2).Value = Slave.Cells(i, 1).Value And Master.Cells(j, 65).Value = "Yes" Then
'If the ID equals that in the slave sheet and there is a yes ticked the copy address
Slave.Cells(i, 4).Value = Master.Cells(j, 18).Value
End If
If Master.Cells(j, 65).Value = "Yes" Then
lastRow = Slave.Cells(ActiveSheet.Rows.Count, "D").End(xlUp).Row
'if yes found, copy value
Slave.Cells(lastRow + 1, 4).Value = Master.Cells(j, 18).Value
End If
Next
Next
MsgBox ("Data Transfer Successful")
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Tbl_Primary").Delete 'delete sheet
Application.DisplayAlerts = True
ThisWorkbook.Save
ThisWorkbook.Close 'save and close it

Resources