Vba code works at times, and at times fails miserably - excel

I have written a pretty elaborate code to automate 2 hours of work into less than 1 min. It works, on most days, somedays like today, the code wont work, or parts of the code wont work.
Its the most obviously simple parts of the code that doesn't work.
This is frustrating me.
To get the code to work, what I have to do would be to restart the system.
Please understand, I dont change the code at all. either before or after the error happens.
the is the code, where the error happens.
Range("Table1_2[[#Headers],[Bag No]:[Batch Making]]").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("Batch Making").Delete
Sheets.Add(After:=Sheets("Sheet1")).Name = "Batch Making"
Range("A1").Select
ActiveSheet.Paste
Cells.Select
Cells.EntireColumn.AutoFit
Today the error was that it would not paste what the code had selected.
please note:
It selected the set of rows and columns
It created the new sheet and selected the first cell
It tried pasting the value also, but nothing happened.
After restarting the system, code worked like a dream.
Why does this happen?? any clue ??
EDIT: Biggest issue is replicating the error, as I mentioned on some days, the code will crash, else it will run smoothly.
Every day new data is fed to the program, and its cleaned to ensure that only what the program can take is given to it and this involves removing #N/A's, #VALUE's and #Ref (this was done today also, I double checked the data after the crash)
Yet at times it fails.
I'll remove the Error Handlers and have separate code to check for availability of sheet, incase the error pop's up again, then I'll update here.

You can try below code. Using select is not the best idea in 99% of time. Also, when referencing a cell it is always good to precisely tell VBA which worksheet to use.
I would suggest to replace on error resume next clause - it disables all errors in your code and you will not be notified if something went wrong.In this case you can write a bit more code to check whether the specific worksheet exist and then remove/add it.
Sub copytable()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("worksheet_with_table_you_want_to_copy")
On Error Resume Next
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Batch Making").Delete
ThisWorkbook.Sheets.Add(After:=Sheets("Sheet1")).Name = "Batch Making"
Application.DisplayAlerts = True
ws.ListObjects(1).Range.Copy
With ThisWorkbook.Worksheets("Batch Making")
.Range("a1").PasteSpecial xlPasteAll
.Cells.EntireColumn.AutoFit
End With
End Sub
edit: Code without on error but with check wheather worksheet "Batch Making" exists and delete it if it's true
Sub copytable()
Dim wsTable As Worksheet
Set wsTable = ThisWorkbook.Worksheets("worksheet_with_table_you_want_to_copy")
Dim ws As Worksheet
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If ws.Name = "Batch Making" Then ThisWorkbook.Worksheets("Batch Making").Delete
Next ws
Application.DisplayAlerts = True
ThisWorkbook.Sheets.Add(After:=Sheets("Sheet1")).Name = "Batch Making"
ws.ListObjects(1).Range.Copy
With ThisWorkbook.Worksheets("Batch Making")
.Range("a1").PasteSpecial xlPasteAll
.Cells.EntireColumn.AutoFit
End With
End Sub

Unfortunately, you don't say what your code is supposed to do but it seems that you have a template and try to create a new worksheet with a table from this template.
The problem is that the source isn't qualified. Your code copies a "Table_2" from an unspecified source sheet, then deletes the "Batch Making" tab, creates a new sheet by that name and pastes the clipboard to this new sheet. The process is slightly illogical because if the source is a sheet by the name of "Batch Making" then it takes a lot of confidence to delete the original before the copy is safely in place. But I think you have a template. Therefore there is no danger of losing data but the question arises why you make the copy before you need it. Either way, if the copy on the clipboard is lost while deleting and inserting sheets "nothing will happen", as you say.
But what should happen? I presume that you just get a fresh copy of the template, and that means that you retain the structure of the table. Therefore my code below takes a radically different approach. It doesn't delete a sheet (with the table in it) and doesn't create a new sheet. Instead it simply deletes the content of the table in the existing sheet.
Sub Snippet()
' 295
Const WsName As String = "Batch Making"
Dim Ws As Worksheet ' Sheets(WsName)
Dim Tbl As ListObject
On Error Resume Next
Set Ws = Worksheets(WsName)
If Err Then
MsgBox "Sorry, there is no tab """ & WsName & """ in this workbook.", _
vbInformation, "Missing worksheet"
Else
Set Tbl = Ws.ListObjects(1)
If Err Then
MsgBox "Sorry, there is no table on the specified worksheet.", _
vbInformation, "Missing table"
Else
Tbl.DataBodyRange.ClearContents
End If
End If
End Sub
This is done by a single line of code, to wit, Tbl.DataBodyRange.ClearContents. You could take more or different action at that point. For example, you could delete unwanted rows or add default cell content. If there is a lot of such default you might get those data (or formulas) from a template. Otherwise just add it to the code. Headers and totals aren't deleted. The table's structure remains unchanged.
Before that, in the above code, the sheet is qualified and the table. In place of the error messages you could insert code to create the tab and/or create the table.
Please observe the name of the worksheet at the top of the code. You can change that string to any other name. The code doesn't specify the name of the table. Instead, it presumes that there is only one table on that sheet and clears that one.

Related

Issue with VBA script running between .xlsm and .xlsb formats

Problem:
Because the .xlsb (herein referred to as TheirFile.xlsb) is downloaded from a third party twice a week, the VBA script must be held by the .xlsm (MyFile.xlsm).
The process is simple:
Focus TheirFile.xlsb
Apply some filters on the data (headers at row 3)
Select the cell AW2 and copy the value (it contains a formula, this may be where the issue occurs)
Focus MyFile.xlsm
Select the cell J28 and paste with ...pastespecial xlPasteAll
However upon checking the code and hitting run, I get nothing in the cell.
Attempts:
Most of them are almost identical, and with the way I (attempt to) bug fix I honestly don't recall all of them.
I used variations on
Workbooks("TheirFile.xlsb").Activate
Range("AW2").Copy
to copy it without error, and
Workbooks("MyFile.xlsm").Activate
Range("j28").Select
ActiveCell.PasteSpecial xlPasteAll
to paste. Something here is failing without returning an error.
I have tried several ways of copying, even a clunky
Range("AW2").Select
x = Selection.Value
Workbooks("MyFile.xlsm").Activate
Range("j28").Select
Selection.Value = x
Which of course didn't work.
Current code and additional info:
Currently I have this in place
Option Explicit
Sub MyMacro() 'indentations for readability
Workbooks("TheirFile.xlsb").Activate
If ActiveSheet.FilterMode Then
ActiveSheet.ShowAllData
End If
'various filters
Dim x As Integer
Workbooks("TheirFile.xlsb").Activate
Range("AW2").Copy
Workbooks("MyFile.xlsm").Activate
Range("j28").Select
ActiveCell.PasteSpecial xlPasteAll
End Sub
The cell AW2 has a =SUBTOTAL(9,cell:cell) formula in it.
The cell j28 is a merged cell.
Questions:
Is there a quick fix for my code?
Would it be more effective to simply perform the subtotal again inside of VBA to avoid the issue?
FIXED
sheets("sheet1").range("AW2").copy
workbooks("MyFile.xlsm").activate
Range("j28").select
activecell.pastespecial xlPasteValues
range("").select appears not to work if the range is in a binary workbook but the macro is in a macro-enabled workbook.
You can/should avoid any uneccessary select/active (also copy/paste is not needed to just transfer values)
Option Explicit
Sub MyMacro()
Dim wsSrc as worksheet
Set wsSrc = workbooks("TheirFile.xlsb").worksheets(1) 'or ws name etc
If wsSrc.FilterMode Then
wsSrc.ShowAllData
End If
'various filters 'USE wsSrc not activesheet
'ThisWorkbook is the wb where your code is running...
ThisWorkbook.worksheets("sheetNameHere").range("J28").value = _
wsSrc.range("AW2").value
End Sub

VBA Code just stops in the middle execution with out completing code (NOT A HANG)

I have some code that is copying a upwards of 1K files or so from a network drive to a SharePoint site. When it has completed that task, It calls the following sub. When I step through the code it seems to work fine, and it worked fine on some of the smaller lists I uploaded. However when I just let it run it magically stops executing code and behaves as if everything has successfully been executed. I know it hasn't because The workbook I picked to be open is still open and the workbook I am running the code from is blank.
The best I can surmise is the code stops executing right around:
SourceWB.Sheets("Sheet1").Activate
Because the destination sheet is still blank, I am pretty sure the cells.copy is not executing. The only other thing I can think of is it somehow is grabbing the Destination worksheet as the source work sheet, so nothing actually gets copied and I wind up with a blank sheet. I rule that out though as at the end of my main sub a message box is supposed to appear when things are complete and no message box appears.
Can anyone spot an issue or shed some light on what may be happening. Frustrating that it works when stepping through. (as long as there is a break point afterwards)
Sub ImportIndex()
'Copies Sheet1 from a user selected workbook
'into current work book
Dim DestinationWS As Worksheet
Dim DestinationR As Range
Dim SourceWB As Workbook
Dim FilenameWB As String
'clear sheet1 of any previous data/formats etc
Clear_Worksheet ("Sheet1")
'Set the location of where the sheet is to be copied to
Set DestinationWS = ThisWorkbook.Sheets("Sheet1")
Set DestinationR = DestinationWS.Range("A1")
'Open the source workbook through file picker
'****************************************************************
'Error may occur if workbook is already open
'Look into how to deal with this in the future
'****************************************************************
FilenameWB = Application.GetOpenFilename()
Set SourceWB = Workbooks.Open(Filename:=FilenameWB)
'Ensure "sheet1" is the active worksheet
SourceWB.Sheets("Sheet1").Activate
'Copies active wrokesheet to Destination
Cells.Copy DestinationR
'close the source workbook without saving changes
SourceWB.Close savechanges:=False
End Sub
I did look at the following question, but it was related to Word. According to one comment, the most recent build seems to have solved their issue.
Clearworksheet function as requested
Sub Clear_Worksheet(Sheetname As String)
'Deletes all cells in the provide worksheet name
'currently will cause an error if the sheet does not exist
With ThisWorkbook.Sheets(Sheetname)
.Cells.Delete Shift:=xlUp
Range("A1").Activate 'probably do no need this activate
End With
End Sub
I just re ran the code with the elimination of ACTIVATE and also having removed all stepping break points. I also changed the copy line to 'SourceWB.Sheets("Sheet1").Cells.Copy` as suggested. The code still stopped executing after opening the sheet and before copying the sheet to Thisworkbook.
on a side note, I also notice sometimes while stepping through the code and I do a file pick or folder pick, the code seems to terminate unless I have a break point set somewhere slightly after it.
I've commented that not sure why it would stop... having a wild guess it could be because of the very large range you're copying (the whole sheet...).
You should either set the range of what you are copying (cell 1 to last row/column), or in this case, since you are not adding to pre-existent data, could be better off to just copy the sheet.
See if rewriting your code this way would help?
Sub ImportIndex()
'Copies Sheet1 from a user selected workbook
'into current work book
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim SourceWB As Workbook
Dim FilenameWB As String
'Open the source workbook through file picker
On Error Resume Next
FilenameWB = Application.GetOpenFilename()
Set SourceWB = Workbooks.Open(Filename:=FilenameWB)
On Error GoTo 0
If Not SourceWB Is Nothing Then
'ws.Name = "something else" 'rename this if you want to keep "Sheet1" name from the source workbook
SourceWB.Sheets("Sheet1").Copy After:=ws
ws.Delete
'close the source workbook without saving changes
SourceWB.Close savechanges:=False
Else
'Some error handling here... msgbox/debug.print etc
End If
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
End Sub
PS: Note that there are various ways to handle opening a workbook, but for simplicity reasons, this should work just fine.

Copying data from one sheet to another sheet using paste and insert rows

So I'm new to Excel VBA and I'm given a project that requires to copy data from sheet 1 to new workbook. The problems are with the copy, paste and insert new rows. (There are two subroutines but the second subroutine is about the same and it's required, please forgive), Thanks.
Sub CopyInfo()
On Error GoTo Err_Execute
wb1.Sheets("dataform").Range("L2:N2").Copy
wb2.Sheets(shtname).Range("A2:C27").Rows("1:1").Insert Shift:=xlDown
wb2.Sheets(shtname).Range("A2:C28").PasteSpecial (xlPasteValues)
wb1.Sheets("dataform").Range("B2:B28").Copy
wb2.Sheets(shtname).Range("D2").Insert Shift:=xlDown
wb1.Sheets("dataform").Range("D2:D28").Copy
wb2.Sheets(shtname).Range("F2").Insert Shift:=xlDown
update
wb1.Sheets("Setlist").Range("G2").Copy
wb2.Sheets(shtname).Range("E2:E27").Rows("1:27").Insert Shift:=xlDown
wb2.Sheets(shtname).Range("E2:E28").Paste1Special
wb2.Sheets(shtname).Columns().AutoFit
Err_Execute:
If Err.Number = 0 Then MsgBox "All have been copied!" Else _
MsgBox Err.Description
End Sub
Sub update()
wb1.Sheets("dataform").Range("D2:D28").Copy
wb1.Sheets("dataform").Range("E2:E28").PasteSpecial
wb1.Sheets("dataform").Range("F2:F28").PasteSpecial
wb1.Sheets("dataform").Range("F2:F28").Copy
wb2.Sheets(shtname).Range("G2").Insert Shift:=xlDown
End Sub
The program requires from current workbook sheet 1 copies to another workbook. The first workbook sheets 1 will have new rows add-in and the code automatically update it. As currently if current workbook sheet 1 add new rows, I have to manually update the code.
Ok so there's several steps to get to your desired result.
I'm assuming your 2nd workbook is not open yet so you need to open it in VBA first before being able to copy your ranges. There are plenty of answers on SO and google that show you how to do that.
Since you will be adding rows to the original worksheet you need a way to include this in your code. There's a few options on how to do that.
You could create a table and use Dim As ListObject to declare and then set it in VBA. That way when new rows are added to the table they will be automatically included. A second way would be to use a dynamic named range (see name Manager under formulas tab), that includes new rows when they are added.
Possibly the most important part is making the code easier by declaring your variables and objects.
Currently you write wb1.Sheets("dataform") constantly. Instead use Dim DataForm as Worksheet and Set Dataform = wb1.Sheets("dataform"). This way when use adress your sheet you can just write Dataform.Range("A1:A1"). See below for an example.
Dim Source As Workbook
Set Source = ThisWorkbook
Dim Dataform As Worksheet
Set Dataform = Source.Sheets("Dataform")
Dataform.Range("L2:N2").Copy 'See how you can just adress the sheet by name
Now if you were to also declare you ranges as tables/named ranges this would make the code even easier to process. Since you're also always adding a row during each operation a much more efficient way would be to use a for each loop to go through all your named ranges/tables, copy them, insert a new row into the destination sheet and then paste.
Hope this was some inspiration
Sub CopyInfo()
On Error GoTo Err_Execute
dataform.Range("L2:N2").Copy
wb2.Sheets(shtname).Range("A2").Rows("1:27").Insert Shift:=xlDown
wb2.Sheets(shtname).Range("A2:C28").PasteSpecial (xlPasteValues)
dataform.Range("LocationName").Copy
wb2.Sheets(shtname).Range("D2").Insert Shift:=xlDown
dataform.Range("Reading").Copy
wb2.Sheets(shtname).Range("F2").Insert Shift:=xlDown
update
wb1.Sheets("Setlist").Range("D2").Copy
wb2.Sheets(shtname).Range("E2").Rows("1:27").Insert Shift:=xlDown
wb2.Sheets(shtname).Columns().AutoFit
Err_Execute:
If Err.Number = 0 Then MsgBox "All have been copied!" Else _
MsgBox Err.Description
End Sub
Sub update()
dataform.Range("Reading").Copy
dataform.Range("PreviousReading, Usage").PasteSpecial
dataform.Range("Usage").Copy
wb2.Sheets(shtname).Range("G2").Insert Shift:=xlDown
End Sub
(There are more codes but I just add half of it, sorry for the confusion. If there's useful links that could help. Much appreciated.)

Print Preview issues after running large amount of VBA

I have an Excel workbook in which almost everything is automated. It opens other workbooks, copies data from them, closes them and then loops through the data several times to generate reports that we print and use. Almost every time after running all the VBA and then trying to print, print preview gets stuck either finding the printer or loading page sizes as seen in the picture. Closing Excel and reopening the document restores print preview to normal functionality. The only thing related to printing that the VBA does is change the print area. I have not had this issue with any other documents that run VBA. Is this just a bug or possibly something in the code?
This is the code that causes print preview to fail to load in some way. If I skip this section then it works as intended... I would like to have this code function in some way as it's still needed.
Set wb1 = Workbooks.Open(FileName)
Set wb2 = ThisWorkbook
For i = LBound(sArray) To UBound(sArray) 'Loops through array, copies available data from last report
ShtName = sArray(i, 0)
On Error Resume Next
wb1.Sheets(ShtName).Activate
If Err.Number = 0 Then
wb1.Sheets(ShtName).Activate
Columns("A:U").Copy
wb2.Sheets(ShtName).Activate
Columns("BE:BV").Select
Selection.PasteSpecial xlPasteValues
Application.CutCopyMode = False
lastrow = Cells(Rows.Count, "BE").End(xlUp).Row
Range("BA2:BC2").Select
Selection.AutoFill Destination:=Range(Cells(2, "BA"), Cells(lastrow, "BC")), Type:=xlFillDefault
End If
On Error GoTo 0
DoEvents
Next i
wb1.Close False
Sheet2.Activate
I've tried commenting out "On Error Resume Next", "On Error Goto 0", "If...", "End If", and "DoEvents". Print Preview still fails with those removed and just doing the copy and paste from the previous sheet.
It seems that removing all instances of DoEvents has fixed the issue...
Print Preview works correctly and Excel does not crash when exiting the workbook anymore.
I believe you're looking for some type of refresh action that can re-sync the preview display with the data on the sheet. You might want to try this at the end:
ActiveSheet.EnableCalculation = False
ActiveSheet.EnableCalculation = True
If that doesn't work, see if manually saving fixes the issue. You can try calling Application.Save at the end.
"Print preview occurs automatically when you choose File --> Print. Another option is to use the Page Layout view (the icon on the right side of the status bar). To get the old-style print preview, you need to use VBA. The following statement displays a print preview of the active sheet: ActiveSheet.PrintPreview "
Quoted from Microsoft Excel 2013 Power Programming with VBA by John Walkenbach, pages 956-957.
That being said, I tested your issue above by recording a relatively complex macro that creates a new sheet, performs 25 automatic actions, and shows a print preview, then closes the print preview when I click OK on a MsgBox. I iterated the program to do this 1000 times. I never had an issue with the PrintPreview.
Its kind of a shot in the dark, but I tried cleaning up your code a little bit. See if that has any affect at all.
Sub Test()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim isWS As Boolean
On Error GoTo sub_err
Set wb1 = Workbooks.Open(Filename)
Set wb2 = ThisWorkbook
For i = LBound(sArray) To UBound(sArray) 'Loops through array, copies available data from last report
ShtName = sArray(i, 0)
isWS = True
Set ws1 = wb1.Sheets(ShtName)
If isWS Then
Set ws2 = wb2.Sheets(ShtName)
ws1.Columns("A:U").Copy
ws2.Columns("BE:BV").PasteSpecial xlPasteValues
Application.CutCopyMode = False
lastrow = ws2.Cells(ws2.Rows.Count, "BE").End(xlUp).Row
ws2.Range("BA2:BC2").AutoFill Destination:=ws2.Range(ws2.Cells(2, "BA"), ws2.Cells(lastrow, "BC")), Type:=xlFillDefault
End If
DoEvents
Next i
wb1.Close False
ws2.Activate
sub_exit:
Exit Sub
sub_err:
If Err.Number = 9 Then
isWS = False
Resume Next
Else
MsgBox "Error: " & Err.Number & vbNewLine & Err.Description
Resume sub_exit
End If
End Sub
The big thing I did was split off your error handling, this way it only resumes next when you don't find the sheet in wb1 and all other errors (none error 9 errors) will still show your error message.
I also made sure all your Range(), Cells(), and Columns() were referencing the correct sheet (just incase excel is getting confused) and I assumed the active sheet was the correct sheet, but you may want to verify this in the code to make sure it's doing the correct thing in the correct sheet.
Now the copy code only runs if isWS = true, and it will always be true unless an error 9 code is thrown. The only thing I didn't know was if wb2 would always have a sheet name equal to ShtName but I'm guessing it will since it's inside your if err.number = 0
I'm not sure if this will change anything for you, but I'd be curious to hear your results other way.

VBA: Paste ceases to work (suddenly) in specific macro

I'm a very new, self-taught programmer, so please keep this in mind in your responses. I have extensively searched this and other forums and can't seem to find a similar question.
The following code has been working for weeks and has not been changed. (My macro includes more variables and code, but I know from taking it apart that those pieces work, so I've left them out for clarity). From what I can tell the PasteSpecial function is specifically not working.
Dim StimSheet As String
ActiveCell.Rows("1:290").EntireRow.Select
Selection.Copy
'Copies the data for the current stimulus
StimSheet = Application.InputBox("Enter the name of the stimulus")
'asks name of the stimulus
Sheets.Add After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = StimSheet
'adds new sheet at the end and names whatever you input as stimulus name
Sheets(StimSheet).Select
Selection.PasteSpecial Paste:=xlPasteValues
'pastes data into new sheet
At this point there is no error, the macro simply stops after copying and creating the new sheet.
Here's what I know / have tried:
The macro is successfully making and naming the new sheet and copying the selection to the clipboard, because I can manually paste it after running the macro. It seems to be getting stuck at the paste piece.
Other macros that use the exact same format of copy / paste special are still working correctly.
Another forum with a similar program suggested typing "Application.EnableEvents=True" into the immediate window. This did not change anything.
This macro has worked for several weeks with no errors. I have made new macros using previously saved code in case something inadvertently was changed in the current one, but this did not work either.
The paste option will work one time on a new file and then ceases to work again.
Thank you in advance for your suggestions.
You might find the problem is that you don't have much control over which workbook and worksheet this code applies to. It's better to avoid ActiveSheet, Select, and Sheet with no parent as much as you can.
If you only need to copy the values of cells without any formatting, then Paste isn't needed either.
Try changing your code to the following and see if you have any better luck:
Const BOOK_NAME As String = "Book1.xlsm" 'change this to your workbook name
Const SOURCE_SHEET_NAME As String = "Sheet1" 'change this to your sheet name
Dim wb As Workbook
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Dim newSheetName As String
Dim validName As Boolean
Dim rng As Range
' Set the book, sheet and range objects
Set wb = Workbooks(BOOK_NAME)
Set sourceSheet = wb.Worksheets(SOURCE_SHEET_NAME)
Set newSheet = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
' Acquire the new sheet name and check it's valid.
Do
newSheetName = InputBox("Enter the name of the stimulus")
On Error Resume Next
newSheet.Name = newSheetName
validName = (Err.Number = 0)
On Error GoTo 0
If Not validName Then MsgBox "Sheet name isn't valid. Try again."
Loop Until validName
' Write the values into the new sheet
Set rng = sourceSheet.Cells(1, 1).Resize(290, sourceSheet.UsedRange.Columns.Count)
newSheet.Range(rng.Address).value = rng.Value2
I moved this line:
StimSheet = Application.InputBox("Enter the name of the stimulus")
to the top of the method and it seems to work reliably. I wish I could tell you exactly why, but at least you can proceed. Perhaps it has something to do with the focus changing.
Also, when it failed for me (Office 2013) I got the following error:
Run-time error 1004:
Application-defined or object-defined error.
When the Sub was in a Sheet code behind, and this:
Run-time error '1004'
PasteSpecial method of Range class failed.
When pasted in a Module.

Resources