Excel VBA Copy/Paste Between Range of Workbooks - excel

I used to code in VBA frequently, but its been a few years and I am stumped. Have an issue with the following code that seems to work fine (although very slowly) for the first 9 files it is opening / copying from, then I get a macro error and it results in an excel hang-up requiring restart. I borrowed / modified heavily an earlier post from luke_t on this forum to get this far. As far as I can tell, there is no difference in the 9th file as they are all based on a standard template, but the error could be there?
Sub copy_rng()
Dim wb As Workbook, wbDest As Workbook, ws As Worksheet, wsDest As Worksheet, wsSrc As Worksheet
Dim wbNames() As Variant
Dim destPath As String
Dim fullpath As String
Dim outputrow As Variant, i As Byte
Set wb = ThisWorkbook
Set ws = wb.Sheets("Casing")
Set wsSrc = wb.Sheets("Casing")
wbNames = ws.Range("b5:b" & lrow(2, ws))
destPath = "C:\Users\...\Daily Reports\"
outputrow = 5
Application.ScreenUpdating = False
For i = 1 To UBound(wbNames, 1)
fullpath = destPath & wbNames(i, 1)
MsgBox i & " " & fullpath
'Stop
Set wbDest = Workbooks.Open(destPath & wbNames(i, 1))
Set wsDest = wbDest.Sheets("Field Report (Internal)")
With wsDest
.Range(Cells(27, 17), Cells(27, 19)).Copy
End With
wsSrc.Cells(outputrow, 10).PasteSpecial xlPasteValues
With wsDest
.Range(Cells(28, 17), Cells(28, 19)).Copy
End With
wsSrc.Cells(outputrow, 13).PasteSpecial xlPasteValues
With wsDest
.Range(Cells(29, 17), Cells(29, 19)).Copy
End With
wsSrc.Cells(outputrow, 16).PasteSpecial xlPasteValues
Application.CutCopyMode = False
wbDest.Close False
outputrow = outputrow + 1
Next i
Application.ScreenUpdating = True
End Sub
Function lrow(ByVal col_num As Integer, sheet_name As Worksheet) As Long
lrow = sheet_name.Cells(Rows.Count, col_num).End(xlUp).Row
End Function

Ok, finally figured this one out. Cleaned the code up to make it clearer, but I believe my issue was not in the code specifically, but rather in the fact that I did not have files created yet for some of the date based information I was trying to pull, i.e. I had dates for files to be created in the future and no error checking to see if those files existed. I haven't added the error checking, rather I just deleted the future date references for now as that was faster.
Sub copy_rng()
Dim wb As Workbook, wbToOpen As Workbook, ws As Worksheet, wsSource As Worksheet
Dim wbNames() As Variant
Dim filePath As String
Dim outputrow As Variant, i As Byte
Dim srcOneRange As Range, srcTwoRange As Range, srcThreeRange As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets("Casing")
wbNames = ws.Range("b5:b" & lrow(2, ws))
filePath = "C:\Users\...\Daily Reports\" 'set path to your path
outputrow = 5
For i = 1 To UBound(wbNames, 1)
Application.ScreenUpdating = False
Set wbToOpen = Workbooks.Open(filePath & wbNames(i, 1))
Set wsSource = wbToOpen.Sheets("Field Report (Internal)")
Set srcOneRange = wsSource.Range("q27:s27")
Set srcTwoRange = wsSource.Range("q28:s28")
Set srcThreeRange = wsSource.Range("q29:s29")
ws.Activate
With ws
.Range(Cells(outputrow, 10), Cells(outputrow, 12)).Value = srcOneRange.Cells.Value
.Range(Cells(outputrow, 13), Cells(outputrow, 15)).Value = srcTwoRange.Cells.Value
.Range(Cells(outputrow, 16), Cells(outputrow, 18)).Value = srcThreeRange.Cells.Value
End With
wbToOpen.Close False
outputrow = outputrow + 1
Application.ScreenUpdating = True
DoEvents
ActiveWindow.SmallScroll down:=1
Application.WindowState = Application.WindowState
Next i
Application.ScreenUpdating = True
End Sub

Related

How to delete worksheets with specific names only

My Master Report in fold.xlsm has a range of file and corresponding worksheets with tab names that correspond to the client and the type of data on that tab (indicated by variables xWs_Tax, xWs_Ins, etc.)
After storing these it then opens the corresponding client workbook.(replaced with fname.xlsx below)
The code is supposed to delete all worksheets NOT matching these stored names that include the client number in them. But I can't seem to get it to work. Either it deletes all the tabs or it does nothing at all depending on how I fiddle with it. Does anything jump out at you below or am I using bad code maybe? Do I need to do more then just declare Dim xWs As Worksheet ?
Here is where the variables are stored:
Dim xWs_ins As String
Dim xWs_tax As String
Dim xWs_ucc As String
Dim xWs_loc As String
Dim rc As String
rc = Range("P40")
For i = 41 To (rc + 40)
Workbooks("Master Report in fold.xlsm").Activate
MsgBox$ Range("J" & i)
xWs_ins = Range("J" & i)
xWs_tax = Range("K" & i)
xWs_ucc = Range("L" & i)
xWs_loc = Range("M" & i)
Workbooks.Open filename:= for example "20 Investor Certification - Master Servicers.xlsx
Dim xWs As Worksheet
''   Application.ScreenUpdating = False
'' Application.DisplayAlerts = False
For Each xWs In Application.ActiveWorkbook
If xWs.Name <> xWs_ins And xWs.Name <> xWs_tax And xWs.Name <> xWs_ucc And xWs.Name <> xWs_loc Then
xWs.Delete
End If
Next
'' Application.DisplayAlerts = True
'' Application.ScreenUpdating = True
ActiveWorkbook.Save
Next i
Delete Unwanted Sheets
There are unclear 'items' addressed in OP's comments and marked with ??? in the code.
Option Explicit
Sub deleteUnwanted()
Dim swb As Workbook: Set swb = Workbooks("Master Report in fold.xlsm")
' The worksheet name is unknown??? ("Sheet1")
Dim sws As Worksheet: sws = swb.Worksheets("Sheet1")
Dim sCell As Range
Dim srg As Range
Dim dwb As Workbook
Dim dsh As Object ' There is no 'Sheet' object.
Dim dArr As Variant
Dim dshCount As Long
' The workbook and worksheet are unknown??? (sws)
Dim rc As String: rc = sws.Range("P40").Value
Application.ScreenUpdating = False
For i = 41 To (rc + 40)
n = 0
Set sCell = sws.Cells(i, "I")
Set dwb = Workbooks.Open(sCell.Value)
dshCount = dwb.Sheets.Count
ReDim dArr(1 To dshCount)
Set srg = sws.Columns("J:M").Rows(i)
For Each dsh In dwb.Sheets
If IsError(Application.Match(dsh.Name, srg, 0)) Then
n = n + 1
dArr(n) = dsh.Name
End If
Next
If n > 0 Then
ReDim Preserve dArr(1 To n)
Application.DisplayAlerts = False
dwb.Worksheets(dArr).Delete
Application.DisplayAlerts = True
End If
dwb.Close SaveChanges:=True
Next i
Application.ScreenUpdating = True
End Sub

Loop a range and skip rows in Excel Worksheet

I have an excel worksheet that accepts input from another excel file. This excel file has structured data in which I need to separate individually as sheets. I already have the following code to copy and format that data in a certain range but I need to loop this process for the whole worksheet until there's no more data.
The range currently I set is A2:P20 the next range is 4 rows below and that would be A25:P43.
Option Explicit
Public Sub CopySheetToClosedWorkbook()
Dim fileName
Dim closedBook As Workbook
Dim currentSheet As Worksheet
fileName = Application.GetOpenFilename("Excel Files (*.xls*),*xls*")
If fileName <> False Then
Application.ScreenUpdating = False
Set currentSheet = Application.ActiveSheet
Set closedBook = Workbooks.Open(fileName)
closedBook.Sheets(1).Range("A2:P20").Copy
ThisWorkbook.Worksheets("input").Range("A2").PasteSpecial xlPasteValues
closedBook.Application.CutCopyMode = False
closedBook.Close (True)
Application.ScreenUpdating = True
CopySheetAndRenameByCell2
End If
End Sub
You could do something based on the code below. I have set the last row as 1000, you will need to derrive this from your data.
Sub SplitRangeTest()
Dim lLastRow As Long
Dim lRow As Long
Dim lRangeSize As Long
Dim lSpacerSize As Long
lRangeSize = 19
lRow = 2
lSpacerSize = 4
lLastRow = 1000 ' Get the last populated row in the column of choice here
Do Until lRow > lLastRow
Debug.Print Range("A" & lRow).Resize(lRangeSize, 16).Address
lRow = lRow + lRangeSize + lSpacerSize
Loop
End Sub
Try this:
Public Sub CopySheetToClosedWorkbook()
Dim fileName As String
Dim closedBook As Workbook
Dim currentSheet As Worksheet
fileName = Application.GetOpenFilename("Excel Files (*.xls*),*xls*")
If fileName <> False Then
start_row = 2
rows_to_copy = 19
row_step = 23
Set currentSheet = Application.ActiveSheet
Set closedBook = Workbooks.Open(fileName)
last_row = Sheets(1).Cells(Sheets(1).Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
For y = start_row To last_row Step row_step
ThisWorkbook.Worksheets("input").Rows(y).Resize(rows_to_copy, 16).Value = closedBook.Sheets(1).Rows(y).Resize(rows_to_copy, 16).Value
Next
Application.ScreenUpdating = True
End If
End Sub
it's worth mentioning here that you set currentSheet but don't actually use it. Also, you shouldn't really use ThisWorkbook like that. Maybe you should be using currentSheet instead (or at least, it's parent).

Looping through Workbooks and Copy a Dynamic range to Master Workbook

I have some tables from Excel that will be updated every month or so, what I am trying to do is to copy and paste those ranges from a "master workbook" to some several sheets. The way this works is I have 20 plus workbooks with those ranges "tables" already there, but I am having to manually open those workbooks then copy and paste the new values from the master workbook and close it.
Sub openwb()
Dim wkbk As Workbook
Dim NewFile As Variant
Dim ws As Worksheet
Dim rngCopy As Range, aCell As Range, bcell As Range
Dim strSearch As String
Dim StrFile As Variant
Dim wb2 As Excel.Workbook
Application.DisplayAlerts = True
Application.ScreenUpdating = True
StrFile = Dir("C:\temp\*.xlsx*")
Do While Len(StrFile) > 0
Set wb = Workbooks.Open(StrFile)
'NewFile = Application.GetOpenFilename("microsoft excel files (*.xl*), *.xl*")
'
'If NewFile <> False Then
'Set wkbk = Workbooks.Open(NewFile)
'''**********************
strSearch = "Descitption"
Set ws = Worksheets("TestCases")
With ws
Set aCell = .Columns(4).Find(What:=strSearch, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not aCell Is Nothing Then
Set bcell = aCell
If rngCopy Is Nothing Then
Set rngCopy = .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2))
Else
Set rngCopy = Union(rngCopy, .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2)))
End If
Do
Set aCell = .Columns(4).FindNext(After:=aCell)
If Not aCell Is Nothing Then
If aCell.Address = bcell.Address Then Exit Do
If rngCopy Is Nothing Then
Set rngCopy = .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2))
Else
Set rngCopy = Union(rngCopy, .Rows((aCell.Row + 1) & ":" & (aCell.Row + 2)))
End If
Else
Exit Do
End If
Loop
Else
MsgBox SearchString & " not Found"
End If
'~~> I am pasting to Output sheet. Change as applicable
Set wb2 = Workbooks.Open("C:\temp\Bulk tool\test1.xlsm")
If Not rngCopy Is Nothing Then rngCopy.Copy 'paste to another worksheet Sheets("Output").Rows(1)
End With
'**************************
ActiveWorkbook.Close SaveChanges:=False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
StrFile = Dir
Loop
End Sub
The range is dynamic, it can change from 2 rows to 20, but to give an example A1:K20 and it will go to the same range to another workbook.
first off let me thank everyone helping me on this.
here is what I have so far (see code)
when I run it I am getting error 1004 not sure what I changed but it was working fine, also what I am trying to do, is to copy to another worksheet.
Copying and pasting values in a worksheet uses the Range.Copy and Range.PasteSpecial.
An example code is as follows:
Sub CopyThis()
Dim Sht1 As Worksheet, Sht2 As Worksheet
Set Sht1 = ThisWorkbook.Sheets(1)
Set Sht2 = ThisWorkbook.Sheets(2)
Sht1.Range("A1:D4").Copy
Sht2.Range("A1:D4").PasteSpecial xlPasteAll
End Sub
Alternatively, you can also loop through values. I usually do this out of preference because I often do "If Then" in loops
Sub CopyThis2()
Dim Sht1 As Worksheet, Sht2 As Worksheet
Set Sht1 = ThisWorkbook.Sheets(1)
Set Sht2 = ThisWorkbook.Sheets(2)
Dim i As Long, j As Long
For i = 1 To 4
For j = 1 To 4
Sht2.Cells(i, j).Value = Sht1.Cells(i, j).Value
Next j
Next i
End Sub
Perhaps you can do little tricks with coding to make it faster. Like in this Answer below
Looping through files in a Folder
You can Also use Application.Screenupdating = False before the loop & True after the loop, so that your process would be way faster. In the Loop you can put the Code suggested by Parker.R ....
Also, there is no other way to copy data from workbooks without opening them in VBA.All you can do it play with the way files are being opened and closed so that the process becomes faster.
Other than Screenupdating few more properties you can Set As per this Link
Code to loop Using FSO
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim objFSO As Object
Dim objFolder, sfol As Object
Dim objFile As Object
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.getFolder(f_add) ''''f_add is the Address of the folder
'''' Loop For Files in That Folder
For Each objFile In objFolder.Files
''''Your Code
Next
'''' Loop for All the Subfolders in The Folder
For Each sfol In objFolder.subfolders
''' Your Code Here
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True

Is there a better way to copy a workbook and hide irrelevant columns?

I'm trying to make the following code more efficient. It currently works as I'd like it to, but it takes a while and I'm wondering if I really need to save the copied workbook before opening it again. I've read that it's good to do that, but it puts a lot of clutter on screen.
Dim ws1 As Worksheet, ws2 As Worksheet
Dim wb1 As Workbook, wb2 As Workbook, NewBook As String
Dim newValue As Variant, i As Long, n As Long
newValue = InputBox("Statement for input box")
folderPath = Application.ActiveWorkbook.path
Set wb1 = ActiveWorkbook
Worksheets(Array("Sheet names")).Copy
With ActiveWorkbook
NewBook = folderPath & "\" & newValue & ".xlsm"
.SaveAs Filename:=NewBook, FileFormat:=xlOpenXMLWorkbookMacroEnabled
.Close SaveChanges:=True
Set wb2 = Workbooks.Open(NewBook)
With wb2
Set ws1 = wb2.Worksheets("Sheet1")
With ws1
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
LastRow = .Cells(.Rows.Count, lastColumn).End(xlUp).Row
stopColumn = lastColumn - 12
i = 4
While i <= stopColumn
n = i + 1
ColumnName = ws1.Cells(2, i).Value
If ColumnName <> newValue Then
ws1.Cells(2, i).EntireColumn.Hidden = True
ws1.Cells(2, n).EntireColumn.Hidden = True
End If
ColumnName = ""
i = i + 2
Wend
End With
End With
End With
The first suggestion I would make without testing your code, is that you can do all the changes in your initial workbook, then SaveAs at the end... No need to close and reopen for that purpose.
When you do SaveAs, changes are only saved in the new copy.
This will require a bit of refactoring of your code (just use one wb instead of two).
Then, you can use application.screenupdating = false at start (and = false at the end), which should significantly increase the speed of processing of your script, as Excel doesn't need to draw the changes on screen.
Some other minor changes... You can set your wb immediately after you declare it, and then reuse the variable for things like :
folderPath = wb.path
Or
With wb
.....
'instead of With ActiveWorkbook
Hope this helps.
EDIT:
Added an improved version - or so i hope.
Option Explicit 'Is always advisable to use Option Explicit, it will identify any variables that haven't been declared or possible mispelling in some
Sub test()
With Application
.ScreenUpdating = False
.DisplayAlerts = False
'.Calculation = xlCalculationManual 'If you have lots of formulas in your spreadsheet, deactivating this could help as well
End With
'Uncomment the below when you are confident your code is working as intended
'On Error GoTo errHandler 'if any error, we need to reactivate the above
'Declaring the variables - i would always start with the workbook, as you can declare and initialize immediately (if known)
Dim wb As Workbook: Set wb = ActiveWorkbook
Dim ws As Worksheet: Set ws = wb.Sheets("Sheet1")
Dim newValue As Variant: newValue = InputBox("Statement for input box")
Dim newBook As String: newBook = wb.Path & "\" & newValue & ".xlsm"
Dim i As Long, lastColumn As Long, lastRow As Long, stopColumn As Long
With wb
With ws
lastColumn = .Cells(1, .Columns.Count).End(xlToLeft).Column
lastRow = .Cells(.Rows.Count, lastColumn).End(xlUp).row
stopColumn = lastColumn - 12
For i = 4 To stopColumn Step 2
If .Cells(2, i).Value <> newValue Then
.Range(.Cells(2, i), .Cells(2, i + 1)).EntireColumn.Hidden = True
End If
Next i
End With 'ws
.SaveAs Filename:=newBook, FileFormat:=xlOpenXMLWorkbookMacroEnabled
.Close SaveChanges:=True
End With 'wb
GoTo finish 'If no errors, skip the errHandler
errHandler:
MsgBox "An error occured, please step through code or comment the 'On Error GoTo errHandler"
finish:
With Application
.ScreenUpdating = True
.DisplayAlerts = True
'.Calculation = xlCalculationAutomatic
End With
End Sub

i want to be able to set workbook from a cell value, it doesn't seem to work for some reason

I have the following code:
Sub export_toFEP2()
Dim wb As Workbook, wb2 As Workbook
Dim ws As Worksheet, ws2 As Worksheet
Dim x As String, lastrow As String
Dim lRow As Long, kRow As Long, i As Long
Dim u As String
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
ThisWorkbook.Activate
Sheets("FEP Selection").Activate
u = Sheets("FEP Selection").Range("File_Name").Value2
Set wb = Workbooks(u)
Set ws = wb.Worksheets("Ship Arrivals")
Set wb2 = ThisWorkbook
Set ws2 = wb2.Worksheets("FEP copy")
lastrow = ws2.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow
If ws2.Range("D" & i).Value = "TRUE" Then
lRow = Application.WorksheetFunction.Match(ws2.Range("A" & i).Value2, ws.Range("A2:CS2"), 0)
kRow = Application.WorksheetFunction.Match(CLng(ws2.Range("B" & i).Value), ws.Range("A1:A145"), 0)
If lRow > 0 And kRow > 0 Then
MsgBox lRow
MsgBox kRow
ws.Cells(kRow, lRow).Value = ws2.Range("C" & i).Value
End If
End If
Next i
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
The problem i am having is that it does not do anything but does not give any errors either.
the variable should pick up a value like "A.xls" (that's the value of file name range), it changes every time, hence, i have a range with the file name.
if i change to the
Set wb = Workbooks(u)
to
Set wb = Workbooks("A1.xls")
it seems to work, but that defeats the purpose as the file name is variable.
thank you for your help :)
If the workbook in question is open, omit the .xls when you set the value of wb.
Something like:
Set wb = Workbooks(Replace(u, ".xls", ""))

Resources