Excel VBA .SaveAs breaking in loop - vba

I have an excel workbook broken out with multiple worksheets, 1 per customer. In my code, I am trying to save each individual customer worksheet as its own excel file. However, the .SaveAs command breaks the second time it triggers in the loop. Any pointers would be fantastic.
Dim SchedWorksheet As Worksheet
Dim SchedWorkbook As Workbook
Dim SchedName As String
Set SchedWorkbook = ActiveWorkbook
Set SchedWorksheet = ActiveSheet
Application.DisplayAlerts = False
For Each Worksheet In SchedWorkbook.Sheets
If Worksheet.Name = "Instructions" Or Worksheet.Name = "Invoice_Items"
Or Worksheet.Name = "Customers" Or _
Worksheet.Name = "Terms" Or Worksheet.Name = "Dilution_Type" Or
Worksheet.Name = "Approval_Status" Or _
Worksheet.Name = "Carriers" Then
GoTo NextSched
End If
If Worksheet.Name = "Invoices" Then
'basicScheduleFileName is global set at beginning of program
SchedName = basicScheduleFileName & "ALL"
Else
SchedName = Worksheet.Name
End If
'payoutFileName is global set at beginning of program
Worksheet.SaveAs Application.ActiveWorkbook.Path & "\" & payoutFileName
& "\Basic Schedule" & "\" & SchedName, xlOpenXMLWorkbook
NextSched:
Next Worksheet
The error on the second iteration is as follows:
Run-time error 1004 'Application-defined or object-defined error'
I have also attempted to run this loop using the SchedWorksheet object in lieu of Worksheet and get the error "method .SaveAs of object _Worksheet failed" on the second iteration.
Question I have code extremely similar to his code earlier in my program that takes a similar dataset and uses an exportAsFixedFormat call to save each worksheet as a PDF. Is there an equivalent for .xlsx? (.csv would be fine as well)

I don't know what value "payOutFileName" has so I left it out of the code. I also don't know the value for basicScheduleFileName so I set it to "Something." You will have to change that to whatever you need to change it too. This works fine when saving to my dir "C\Files" Might be a little buggy for you. Hopefully it will be a start.
Sub asdfghj()
Dim SchedWorkbook As Workbook
Dim SchedName As String
Dim basicScheduleFileName As String
Dim payoutFileName As String
Dim ws As Worksheet
Dim wb As Workbook
basicScheduleFileName = "Something"
Set SchedWorkbook = ActiveWorkbook
Application.DisplayAlerts = False
For Each ws In SchedWorkbook.Sheets
Debug.Print ws.Name
If ws.Name = "Instructions" Or ws.Name = "Invoice_Items" _
Or ws.Name = "Customers" Or _
ws.Name = "Terms" Or ws.Name = "Dilution_Type" Or _
ws.Name = "Approval_Status" Or _
ws.Name = "Carriers" Then
GoTo NextSched
End If
If ws.Name = "Invoices" Then
SchedName = basicScheduleFileName & "ALL" & ".xlsx"
Else
SchedName = ws.Name & ".xlsx"
End If
ws.Activate
' SaveAs Application.ActiveWorkbook.Path & "\" & payoutFileName & "\Basic Schedule" & "\" & SchedName, xlOpenXMLWorkbook
Set wb = Workbooks.Add
ws.Copy Before:=wb.Sheets(1)
wb.Sheets("Sheet1").Delete
wb.SaveAs Filename:="C:\Files\" & SchedName, FileFormat:= _
xlOpenXMLWorkbook, CreateBackup:=False
wb.Close
NextSched:
Next ws
End Sub

First off, thanks to everyone who took time and brainpower trying to figure out my issue. I finally figured out a fix that works.
First I made sure to get rid of ActiveWorkbook and ActiveSheet references to avoid any confusion in Excel.
Second As #NickSlash pointed out, it was likely that even if my code did work, it would save multiple copies of the same file under different names. So, to solve that while fixing my original issue, I changed my code to copy the worksheets that I need into a new workbook and save them that way:
Dim WS As Worksheet
Dim WB As Workbook
Dim NWB As Workbook
Dim SchedName As String
Set WB = Workbooks("Basic_Schedule-.xls")
WB.Activate
'Application.DisplayAlerts = False
For Each WS In WB.Sheets
WB.Activate
If WS.Name = "Instructions" Or WS.Name = "Invoice_Items" Or WS.Name = "Customers" Or _
WS.Name = "Terms" Or WS.Name = "Dilution_Type" Or WS.Name = "Approval_Status" Or _
WS.Name = "Carriers" Then
GoTo NextSched
End If
If WS.Name = "Invoices" Then
SchedName = basicScheduleFileName & "ALL" & ".xlsx"
Else
SchedName = WS.Name & ".xlsx"
End If
'Copy sheet to another WB
Set NWB = Workbooks.Add
WB.Activate
Sheets(WS.Name).Copy After:=NWB.Sheets(NWB.Sheets.Count)
NWB.Sheets("Sheet1").Delete
NWB.SaveAs filename:=basicScheduleFilePath & "\" & payoutFileName & "\Basic Schedule" & "\" & SchedName
NWB.Close
WB.Activate
NextSched:
Next WS
Instead of this:
'Copy sheet to another WB
Set NWB = Workbooks.Add
WB.Activate
Sheets(WS.Name).Copy After:=NWB.Sheets(NWB.Sheets.Count)
NWB.Sheets("Sheet1").Delete
NWB.SaveAs filename:=basicScheduleFilePath & "\" & payoutFileName & "\Basic Schedule" & "\" & SchedName
NWB.Close
WB.Activate
Do this -- you can avoid the "Activate" method call, and also if you have a reference to WS as an object, it's redundant to do WB.Sheets(WS.Name) when WS already refers to the same Worksheet.
'Copy sheet to another WB
WS.Copy '## Creates a new workbook with the copied sheet.
Set NWB = ActiveWorkbook
NWB.SaveAs filename:=basicScheduleFilePath & "\" & payoutFileName & "\Basic Schedule" & "\" & SchedName
NWB.Close

Related

Excel VBA - save as file with content from a specific sheet

I'm trying to save as my Excel file into multiple xlsx files, soemthing like this:
I would like to save as it into multiple xlsx files with each file will content 1 line range("Ax:Dx"). I have written the code as below to do that
Sub split_file()
Dim wb As Workbook
Dim ws As Worksheet
Dim i As Long
Dim lastrow1 As Long
Dim lastrow2 As Long
Set wb = ThisWorkbook
On Error Resume Next
'Dim filename As String
Path = "C:\test"
For i = 2 To Sheet2.Range("A" & Rows.Count).End(xlUp).Row
'wb.Worksheets(3).Copy 'create new active workbook
Sheets.Add.Name = Sheet2.Range("A" & i).Value
With Worksheets(Sheet2.Range("A" & i).Value)
Range("A1:D1").Value = Sheet2.Range("A" & i & ":D" & i).Value
.SaveAs filename:=Path & "\" & Sheet2.Range("A" & i).Value, FileFormat:=xlOpenXMLWorkbook, Password:="Welcome1"
.Close savechanges:=False
End With
Next i
On Error GoTo 0
End Sub
The result I got is shown in this screenshot:
Once I open the file after save as with proper data, it include some unwanted sheets in that :( .
Like this:
I wish it save as only the file with the same name. Can anybody help look for this problem ?
Very appreciated for each support of you all.
Please, try the next way:
Sub split_file()
Dim wb As Workbook, ws As Worksheet, wsNew As Worksheet, wbNew As Workbook
Dim path As String, i As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets(Sheet2.Name)
path = "C:\test"
For i = 2 To ws.Range("A" & rows.count).End(xlUp).row
Set wbNew = Workbooks.Add(xlWBATWorksheet)
Set wsNew = wbNew.Sheets(1): wsNew.Name = ws.Range("A" & i).value
wsNew.Range("A1:D1").value = ws.Range("A" & i & ":D" & i).value
wbNew.saveas FileName:=path & "\" & wsNew.Name, FileFormat:=xlOpenXMLWorkbook, password:="Welcome1"
wbNew.Close savechanges:=False
Next i
End Sub
I assumed that Sheet2 is a code name...

How to run VBA in excel, when Excel filename got changed

I have a Workbook (1) contains 2 sheets. In my program, I would like to generate a workbook (2) which Create 2 sheets. Then the program will filter the table and copy values from workbook 1 to workbook 2.
But my problem is my workbook (1) name will get changed every time. I tried to use ActiveWorkbook.Name. But when the program is running, it will create a new workbook then suddenly it became an active workbook.
I named my main Workbook (1) as Filevalue. But not working. How to solve this problem. I need to run this program eventhough when the name get changed. Help me
Sub createlandDE()
Filepath = ActiveWorkbook.path
FileValue = ActiveWorkbook.Name 'Problem With Activeworkbook
NameValue = Format(Date, "yymmdd") & "-DE"
Dim wb As Workbook
Set wb = Workbooks.add
Dim path As String
Dim FSO As Object
path = Filepath & "\" & NameValue & ".xlsx"
Set FSO = CreateObject("Scripting.FileSystemObject")
If FSO.FileExists(path) Then
On Error Resume Next
Workbooks(NameValue & ".xlsx").Close False
Kill path
wb.SaveAs path
Sheets(3).Delete
Else
wb.SaveAs path
Sheets(3).Delete
End If
Application.ScreenUpdating = False
Dim ws, ws1, ws2 As Worksheet
Dim table1, table2 As ListObject
Dim rng1 As Range
Sheets(1).Name = "Main view"
Sheets(2).Name = "Overall view"
Set ws1 = Workbooks(NameValue & ".xlsx").Worksheets("Main view")
ws1.ListObjects.add(xlSrcRange, ws1.Range("A$1:$J$1"), , xlYes).Name = "MainTable"
Set table1 = ws1.ListObjects(1)
Set ws = Workbooks(FileValue).Worksheets("Main") 'Problem With Activeworkbook
ws.PivotTables("MainTable").PivotFields("Dealer Country Code").CurrentPage = "DE"
With ws
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng1 = Range(.Range("A4"), .Range("J" & LastRow))
End With
rng1.Copy
ws1.Range("A1").PasteSpecial Paste:=xlPasteAllUsingSourceTheme, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Set ws2 = Sheets("Overall view")
ws2.ListObjects.add(xlSrcRange, ws2.Range("A$1:$Q$1"), , xlYes).Name = "OverallTable"
Set table2 = ws2.ListObjects(1)
Worksheets("Overall view").ListObjects("OverallTable").TableStyle = "Table Style 1"
Workbooks(FileValue).Activate 'Problem With Activeworkbook
Sheet2.ListObjects("DataTable").Range.AutoFilter Field:=1
Sheet2.ListObjects("DataTable").Range.AutoFilter Field:=12
ActiveWorkbook.Save
Application.ScreenUpdating = True
End Sub

break external links not working when used directly after creating a file

I have a code that copies two worksheets from one workbook to a new one.
Since those two worksheets contain graphs where the data is on the sheet itself, but the datacells refer to a different worksheet, I copy the values only, to avoid external links.
However I found out that there is still an external link to my original workbook.
I don't know where it is though, since there are no formulas anymore.
I thought about names and deleted them as well, since there were a lot of names, that didn't even exist in the original file. That didn't help either.
I can delete the external, when using the menu in the ribbon.
And the code below also works, when I use it in the new workbook itself when opening it and running it in there.
Sub BreakLinks()
Dim wb As Workbook
Set wb = Application.ActiveWorkbook
If Not IsEmpty(wb.LinkSources(xlExcelLinks)) Then
For Each link In wb.LinkSources(xlExcelLinks)
wb.BreakLink link, xlLinkTypeExcelLinks
Next link
End If
End Sub
However, if I want to use that code in conjunction with the copying, it does not do the trick. I saved it on purpose before breaking the link, because I thought it might not be able to do it, but it didn't help.
Does anybody know why it doesn't work or can point me to a solution?
Here's the complete code:
Sub ACTION_Export_Capex()
Dim Pfad As String
Dim Dateiname As String
Dim ws As Worksheet
Dim wb As Workbook
Pfad = "D:\#Inbox\"
Dateiname = Format(Date, "YYYY-MM-DD") & " " & Format(Time, "hhmm") & " " & "monthly Report-" & Format(DateSerial(Year(Date), Month(Date) - 1, 1), "yyyy-mm") & " Capex" & ".xlsx"
'Copy Sheets without formulas
Sheets(Array("Capex_monthly", "Capex_YTD")).Copy
For Each ws In Worksheets
ws.UsedRange = ws.UsedRange.Value
Next
'get rid of macrobuttons and hyperlinks
For Each ws In Worksheets
ws.Rectangles.Delete
ws.Hyperlinks.Delete
Next
ActiveWorkbook.SaveAs Filename:=Pfad & Dateiname, FileFormat:=xlOpenXMLWorkbook
'delete external links
If Not IsEmpty(ActiveWorkbook.LinkSources(xlExcelLinks)) Then
For Each link In ActiveWorkbook.LinkSources(xlExcelLinks)
ActiveWorkbook.BreakLink link, xlLinkTypeExcelLinks
Next link
End If
ActiveWorkbook.Save
ActiveWorkbook.Close
'go back to main menu in Cockpit
Sheets("Menu").Select
End Sub
Thanks a lot in advance.
EDIT:
In the end brettdj got the solution, I just had to tweak it a bit to get it done in my workbook.
Here's the code:
Sub ACTION_Export_Capex()
Dim Pfad As String
Dim Dateiname As String
Dim ws As Worksheet
Dim wb As Workbook
Pfad = "D:\#Inbox\"
Dateiname = Format(Date, "YYYY-MM-DD") & " " & Format(Time, "hhmm") & " " & "monthly Report-" & Format(DateSerial(Year(Date), Month(Date) - 1, 1), "yyyy-mm") & " Capex" & ".xlsx"
'Copy Sheets without formulas
Sheets(Array("Capex_monthly", "Capex_YTD")).Copy
For Each ws In Worksheets
ws.UsedRange = ws.UsedRange.Value
Next
'get rid of macrobuttons and hyperlinks
For Each ws In Worksheets
ws.Rectangles.Delete
ws.Hyperlinks.Delete
Next
'get rid of external link
ActiveWorkbook.ChangeLink ThisWorkbook.Name, ActiveWorkbook.Name, xlLinkTypeExcelLinks
ActiveWorkbook.SaveAs Filename:=Pfad & Dateiname, FileFormat:=xlOpenXMLWorkbook
ActiveWorkbook.Close
Sheets("Menu").Select
End Sub
If I use this code the links are gone when the new worbook is opened again.
I am still puzzled why the original creation builds in a phantom link that exists even when the two copied sheets are deleted.
code
Sub Test()
Dim wb As Workbook
Dim wb2 As Workbook
Dim Pfad As String
Dim Dateiname As String
Dim ws As Worksheet
With Application
.ScreenUpdating = False
.DisplayAlerts = falser
End With
Pfad = "D:\#Inbox\"
'Pfad = "c:\temp\"
Dateiname = Format(Date, "YYYY-MM-DD") & " " & Format(Time, "hhmm") & " " & "monthly Report-" & Format(DateSerial(Year(Date), Month(Date) - 1, 1), "yyyy-mm") & " Capex" & ".xlsx"
Set wb = ThisWorkbook
Set wb2 = Workbooks.Add(1)
wb.Sheets(Array("Capex_monthly", "Capex_YTD")).Copy After:=wb2.Sheets(1)
wb2.Sheets(1).Delete
wb2.SaveAs Filename:=Pfad & Dateiname, FileFormat:=xlOpenXMLWorkbook
wb2.ChangeLink wb.Name, wb2.Name, xlLinkTypeExcelLinks
wb2.Close
With Application
.ScreenUpdating = True
.DisplayAlerts = True
.Goto wb.Sheets("Menu").[a1]
End With
Set wb2 = Workbooks.Open(Pfad & Dateiname)
End Sub

Use VBA Macro to Save each Excel Worksheet as Separate Workbook

Hi I am trying to use this code to save each sheet of Excel to a new workbook. However, it is saving the entire workbook to the new filename
Dim path As String
Dim dt As String
dt = Now()
path = CreateObject("WScript.Shell").specialfolders("Desktop") & "\Calendars " & Replace(Replace(dt, ":", "."), "/", ".")
MkDir path
Call Shell("explorer.exe" & " " & path, vbNormalFocus)
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets 'SetVersions
If ws.name <> "How-To" And ws.name <> "Actg_Prd" Then
ws.SaveAs path & ws.name, xlsx
End If
Next ws
What is the quick fix?
Keeping the worksheet in the existing workbook and creating a new workbook with a copy
Dim path As String
Dim dt As String
dt = Now()
path = CreateObject("WScript.Shell").specialfolders("Desktop") & "\Calendars " & Replace(Replace(dt, ":", "."), "/", ".")
MkDir path
Call Shell("explorer.exe" & " " & path, vbNormalFocus)
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets 'SetVersions
If ws.Name <> "How-To" And ws.Name <> "Actg_Prd" Then
Dim wb As Workbook
Set wb = ws.Application.Workbooks.Add
ws.Copy Before:=wb.Sheets(1)
wb.SaveAs path & ws.Name, Excel.XlFileFormat.xlOpenXMLWorkbook
Set wb = Nothing
End If
Next ws
I recommend introducing some error checking so as to ensure the folder you'll ultimately try to save workbooks to, actually exists. This will also create the folder relative to wherever you've saved your macro-enabled excel file.
On Error Resume Next
MkDir ThisWorkbook.path & "\Calendars\"
On Error GoTo 0
I also highly recommend closing the newly created workbook as soon as it's saved. If you are trying to create a large number of new workbooks, you'll quickly find how much it lags your system.
wb.Close
Moreover, Sorceri's code will not save an excel file with the appropriate file extension. You must specify that in the file name.
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets 'SetVersions
If ws.Name <> "How-To" And ws.Name <> "Actg_Prd" Then
Dim wb As Workbook
Set wb = ws.Application.Workbooks.Add
ws.Copy Before:=wb.Sheets(1)
wb.SaveAs path & ws.Name & ".xlsx", Excel.XlFileFormat.xlOpenXMLWorkbook
wb.Close
Set wb = Nothing
End If
Next ws

Running multiple macros to create separate workbooks

I have a macro written to take selected sheets from one workbook, and copy those to another workbook, saving it under a new name. I need to run this same query repeatedly until I create about 6 separate files. Each individual macro works, and I can call them each up one at a time, but they will not run sequentially. I believe I know that the problem lies in the fact that the code I have written will not reference back to the source workbook, and I don’t know how to write code to do it.
The attached code is what I am using, and it may seem a bit sloppy – I put together pieces from several different macros to get this to work. Gqp Master is the name of the master workbook that all the other workbooks are being created from.
Sub Snuth()
'This will prevent the alet from popping up when overwriting graphs, etc
Application.DisplayAlerts = False
Dim FName As String
Dim FPath As String
Dim NewBook As Workbook
Dim strFileName As String
Dim WS As Worksheet
Dim WBk As Workbook
Set WBk = ("Gap Master")
For Each WS In Worksheets
WS.Visible = True
Next
For Each WS In Worksheets
If WS.Range("C4") <> "Snuth, John" Then
WS.Visible = False
End If
If WS.Range("C4") = "Snuth, John" Then
WS.Visible = True
End If
Next WS
FPath = "C:\Users\mmarshall\Documents\GAP\GAP Development"
FName = "Snuth GAP " & Format(Date, "yyyy-mm-dd") & ".xlsx"
Set NewBook = Workbooks.Add
ThisWorkbook.Sheets.Copy Before:=NewBook.Sheets(1)
Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Select
ActiveWindow.SelectedSheets.Delete
If Dir(FPath & "\" & FName) <> "" Then
MsgBox "File " & FPath & "\" & FName & " already exists"
Else
NewBook.SaveAs Filename:=FPath & "\" & FName
End If
Application.DisplayAlerts = True
End Sub
I am assuming you have several other macros that do, more or less, the exact same thing, just for different manager names.
You can create a master subroutine that will invoke other subs/functions. What this does is send some arguments/parameters to a subroutine, these are
WBk: the workbook you're copying from
lastName: the manager's last name
firstName: the manager's first name
Here is the code:
Sub CreateCopies()
Dim WBk As Workbook
Set WBk = Workbooks("Gap Master")
'# Run the CopyForName for each of your manager names, e.g.:
CopyForName WBk, "Snuth", "John"
CopyForName WBk, "Zemens", "David"
CopyForName WBk, "Bonaparte", "Napoleon"
CopyForName WBk, "Mozart", "Wolfgang"
End Sub
Now, some revisions to your subroutine so that it is generic enough to perform the function for all managers:
Sub CopyForName(wkbkToCopy as Workbook, lastName as String, firstName As String)
'This will prevent the alert from popping up when overwriting graphs, etc
Application.DisplayAlerts = False
Dim FName As String
Dim FPath As String
Dim NewBook As Workbook
Dim strFileName As String
Dim WS As Worksheet
FPath = "C:\Users\mmarshall\Documents\GAP\GAP Development"
FName = lastName & " GAP " & Format(Date, "yyyy-mm-dd") & ".xlsx"
'## I consolidated your 3 loops in to 1 loop
For Each WS In wkbkToCopy.Worksheets
WS.Visible = (WS.Range("C4") = lastName & ", " & firstname)
Next
Set NewBook = Workbooks.Add
'Copies sheets from your Gap Master file:
wkbkToCopy.Sheets.Copy Before:=NewBook.Sheets(1)
'## I think you're trying to delete the default sheets in the NewBook:
NewBook.Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Delete
If Dir(FPath & "\" & FName) <> "" Then
MsgBox "File " & FPath & "\" & FName & " already exists"
Else
NewBook.SaveAs Filename:=FPath & "\" & FName
NewBook.Close
End If
Application.DisplayAlerts = True
End Sub
Try this:
After your line:
NewBook.SaveAs Filename:=FPath & "\" & FName
insert:
NewBook.Close
This should cause you to "fall back" to the original workbook.
Try this:
Step1:
Change
Set WBk = ("Gap Master")
To
Set WBk = ActiveWorkbook
Step 2:
Also add another line:
Set NewBook = Workbooks.Add
WBk.Activate '''''add this line''''''
ThisWorkbook.Sheets.Copy Before:=NewBook.Sheets(1)
Here is what I came up with, cobbling together several different pieces of code:
Sub VPFiles()
Dim WBk As Workbook
Set WBk = ThisWorkbook
'# Run the CopyForName for each of your manager names, e.g.:
CopyForName WBk, "Doe", "Christopher"
CopyForName WBk, "Smith", "Mark"
CopyForName WBk, "Randall", "Tony"
CopyForName WBk, "Jordan", "Steve"
CopyForName WBk, "Marshall", "Ron"
End Sub
Followed By This:
Sub CopyForName(wkbkToCopy As Workbook, lastName As String, firstName As String)
'This will prevent the alert from popping up when overwriting graphs, etc
Application.DisplayAlerts = False
Dim FName As String
Dim FPath As String
Dim NewBook As Workbook
Dim strFileName As String
Dim WS As Worksheet
FPath = "\\filesrv1\department shares\Sales"
FName = lastName & " GAP " & Format(Date, "yyyy-mm-dd") & ".xlsx"
'## I consolidated your 3 loops in to 1 loop
For Each WS In wkbkToCopy.Worksheets
WS.Visible = (WS.Range("K4") = lastName & ", " & firstName)
Next
Set NewBook = Workbooks.Add
'Copies sheets from your Gap Master file:
wkbkToCopy.Sheets.Copy Before:=NewBook.Sheets(1)
'This delets all unnecessary sheets in the NewBook:
NewBook.Sheets(Array("Sheet1", "Sheet2", "Sheet3")).Delete
For Each WS In Worksheets
If WS.Visible <> True Then WS.Delete
Next
NewBook.SaveAs Filename:=FPath & "\" & FName
NewBook.Close
Application.DisplayAlerts = True
End Sub