I have an vba macro that should (after updating some values from an online xml) save one sheet to a CSV file. This works, but if I open the CSV file, I see this:
CHF,Swiss Franc,1.2352,,,
CNY,Yuan Renminbi,8.1803,,,
EUR,Euro,1,,,
GBP,Pound Sterling,0.8585,,,
HKD,Hong Kong Dollar,10.3617,,,
SGD,Singapore Dollar,1.7097,,,
USD,US Dollar,1.3361,,,
,,,,,
,,,,,
So the problem is that three empty colomns and two empty rows are also saved. I know this raises no problems after opening the CSV file in Excel, but in the program I import it, it does.
I did some research and found that this probably has to do with the UsedRange. But i could find no way to set the usedRange to a new value, or only save a small part of the sheet.
I probably can copy the range I want, open a new workbook, paste this range and save this to a file, but this seems a bit harder than it should be. And it does not guarantee that my UsedRange in this new workbook is not also to big.
Does anyone know how to set the usedrange or do the things I want another way? I am an absolute VBA amateur, so if I did strange things, thats the reason.
The rest of my code works fine, so the problem is only in the extra comma's in the saved file.
My VBA code is below:
Sub updateCurrencies()
'
' updateCurrencies Macro
'
' Keyboard Shortcut: Ctrl+e
'
Application.DisplayAlerts = False
Dim wb As Workbook
Dim ws As Worksheet
Dim file As String
file = "\\SBS2008\RedirectedFolders\jasper\Desktop\currencies.csv"
Sheets("Sheet1").Select
ActiveWorkbook.XmlMaps("Envelope_Map").DataBinding.Refresh
Set ws = Sheets("currencies")
ws.Select
ActiveWorkbook.RefreshAll
ws.SaveAs file, FileFormat:=6
Sheets("info").Select
Set wb = Workbooks.Open(file)
wb.Save
Sheets("info").Select
Call CloseAllWorkbooks
End Sub
Public Sub CloseAllWorkbooks()
Dim wb As Workbook
For Each wb In Workbooks
If (wb.Name = "currencies") Then
wb.Close True
Else
wb.Close False ' Or True if you want changes saved
End If
Next wb
End Sub
See the answer here by Daniel Cook
Convert xls File to csv, but extra rows added?
Sub CorrectUsedRange()
Dim values
Dim usedRangeAddress As String
Dim r As Range
'Get UsedRange Address prior to deleting Range
usedRangeAddress = ActiveSheet.UsedRange.Address
'Store values of cells to array.
values = ActiveSheet.UsedRange
'Delete all cells in the sheet
ActiveSheet.Cells.Delete
'Restore values to their initial locations
Range(usedRangeAddress) = values
End Sub
Related
Thank you for taking the time to help. I have a macro that looks up a workbook. From the recalled workbook, I want cell A1 in "Book1" to = cell A1 in the recalled workbook. I then want to auto fill over to K1 and down to K20. However, the range of data that I want to transfer isnt doing so.
My goal is to have the range on "book1" = the range on the recalled workbook- that way when another parties edits the recalled workbook, "book1" will reflect those edits.
I know PQ could be a good option for this but I want to try this avenue first.
My macro:
Sub copydata()
Dim path As String
path = InputBox("Please input path")
Application.ScreenUpdating = False
Dim actualfile As Workbook
Set actualfile = ActiveWorkbook
Dim script As Object
Set script = CreateObject("Scripting.FileSystemObject")
Dim catalogue As Object
Set catalogue = script.GetFolder(path)
Application.DisplayAlerts = False
Application.AskToUpdateLinks = False
Dim textfile As Object
For Each textfile In catalogue.Files
Workbooks.Open textfile
Dim loadedfile As Workbook
Set loadedfile = ActiveWorkbook
Range("A1").Select
ActiveCell.FormulaR1C1 = "='loadedfile.Worksheets(1)'!RC"
Selection.AutoFill Destination:=Range("A1:K1"), Type:=xlFillDefault
Range("A1:K1").Select
Selection.AutoFill Destination:=Range("A1:K20"), Type:=xlFillDefault
Range("A1:K20").Select
Next textfile
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.AskToUpdateLinks = True
End Sub
I tried setting "book1" as an active workbook and no success.
Edit: Replying to some questions-------------------------------------------
There is a workbook containing this code. Then there is the ActiveWorbook actualfile. Are these two the same?
No they are different. The macro linked is native to book1 (open through entire process)
What are the recalled workbook and Book1?
Excel workbooks
Where should these formulas refer to and where should they be written to i.e. there is no mention of the worksheets?
worksheet one for both workbooks
If you're writing to the same worksheet, then the only remaining references will be references to the last opened file.
I am writing to book1. In other words I want to type "=" in A1 on book1, and then double click A1 on the recalled workbook and hit enter. Then, on book1 cell A1, I want to remove $$ so i can autofill a range. That way any edits from the recalled worksheet will be reflected on book1.
Also, you need to close the files. Please do clarify. You can edit your post at any time.
I am a newbie- thank you for taking the time to help me see these issues with my code
I wrote a simple VBA to copy paste sheet content from another workbook. However, that sheet contains Bloomberg formulas which need to be refreshed before copying. How do I refresh the Bloomberg formulas on the other workbook before copying it to my current workbook, without opening it?
Code is below:
Sub foo()
Dim wb As Workbook
Dim sht1 As Worksheet
Dim current_sht1 As Worksheet
Dim FilePath As String
Dim shtName1 As String
Application.ScreenUpdating = False
Application.DisplayAlerts = False
FilePath = Range("Path") & "FILENAME"
shtName1 = "SHEETNAME"
Set current_sht1 = ThisWorkbook.Worksheets(shtName1)
current_sht1.Cells.Clear
Set wb = Application.Workbooks.Open(FilePath)
Set sht1 = wb.Worksheets(shtName1)
sht1.UsedRange.Copy
current_sht1.Range("A1").PasteSpecial xlPasteValuesAndNumberFormats
current_sht1.Range("A1").PasteSpecial xlPasteFormats
Application.CutCopyMode = False
wb.Close SaveChanges:=False
Application.ScreenUpdating = True
End Sub
Also the file I am working with contains a ton of Bloomberg real time formulas, which is hard to work with during market hour. Is there any way to make the data feed more efficient? And I don't want to uncheck the real time option as we kinda want it to be real time...
Thank you!
By your code I assume sht1 is the sheet with the Bloomberg formulas on it. Do a recalulate of the sheet befory copying like that
sht1.Calculate
I'm looking for help on a VBA Macros. This is my current code. Where the **** are I need some code to insert a row at the end of the table on the active worksheet, and then paste the values copied in the above code with the range of ("E1:R8") into the range (E?:R?") of the newly created row.
Sub Workbook()
Dim wb As Workbook
Set wb = Workbooks.Add
ThisWorkbook.Sheets("RFP Form").Copy Before:=wb.Sheets(1)
ThisWorkbook.Sheets("DataHelperSheet").Copy After:=wb.Sheets(1)
Application.DisplayAlerts = False
wb.SaveAs "Z:\Temp\test3.xlsx"
Application.DisplayAlerts = True
ActiveWorkbook.SaveAs FileName:="Z:\Temp\" & Range("I1").Value
Worksheets("DataHelperSheet").Activate
Range("E1:R8").Select
Selection.Copy
Workbooks("Proposal Quote Master List(LB).xlsm").Activate
Worksheets("Master List").Activate
'***
Range("E1:R298").PasteSpecial Paste:=xlPasteValues
End Sub
Don't name your sub Workbook it is a reserved word because VBA uses this for worbook objects (see at Dim wb As Workbook) and this can be very confusing for humans and VBA.
Don't mix ThisWorkbook and ActiveWorkbook and avoid using Activate, ActiveWorkbook and .Select. ThisWorkbook is the workbook the code is written in (it never changes. ActiveWorkbook is the workbook that has focus (is on top) and it can easily change by a single mouse click (therefore it is not a very reliable reference). Instead always try to use a fix reference like you did with wb.SaveAs.
Make sure all your Range objects have a workbook and worksheet specified. If you write Range("I1").Value VBA does not definitely know which workbook or worksheet you mean. It guesses you mean the active ones. But again this is not very reliable because this can change by a single mouse click. Make sure you tell VBA exactly what you mean by using something like wb.Workbooks("Sheet1").Range("I1").Value so there is no room for VBA to start guessing.
Stop using .Select. Instead of
Worksheets("DataHelperSheet").Activate
Range("E1:R8").Select
Selection.Copy
just write
wb.Worksheets("DataHelperSheet").Range("E1:R8").Copy
again specify the workbook wb if working with more than one workbook.
To find the last used cell in column E for example use
wsMasterList.Cells(wsMasterList.Rows.Count, "E").End(xlUp)
and use .Offset(RowOffset:=1) to move one row down to the next empty cell to paste at.
So you end up with something like:
Option Explicit
Public Sub CreateWorkbook()
Dim wb As Workbook
Set wb = Workbooks.Add
ThisWorkbook.Sheets("RFP Form").Copy Before:=wb.Sheets(1)
ThisWorkbook.Sheets("DataHelperSheet").Copy After:=wb.Sheets(1)
Application.DisplayAlerts = False
wb.SaveAs "Z:\Temp\test3.xlsx"
Application.DisplayAlerts = True
wb.SaveAs Filename:="Z:\Temp\" & wb.Workbooks("SPECIFY YOUR SHEET").Range("I1").Value '‹~~ specify sheet name
wb.Worksheets("DataHelperSheet").Range("E1:R8").Copy
Dim wsMasterList As Worksheet
Set wsMasterList = Workbooks("Proposal Quote Master List(LB).xlsm").Worksheets("Master List")
wsMasterList.Cells(wsMasterList.Rows.Count, "E").End(xlUp).Offset(RowOffset:=1).PasteSpecial Paste:=xlPasteValues
End Sub
You can find the last row in a table by using this after you've selected the first cell in the table: (Try it like this)
Range("E1").Columns.End(xlDown).Offset(1,0).EntireRow.Insert
Or you can paste the data with:
.PasteSpecial Paste:=xlPasteFormats
You should look at ExcelCampus and this stack overflow question How to insert copied cells instead of paste
Above should give you all you need to do what you are asking for.
I have a set of versioned Excel documents that I am trying to get to auto-update when there is a new version available. What fails is that the .close method is not just closing one of the workbooks but also exiting the sub.
The process:
The sub gets called from Worksheet_Activate and immediately checks to see if an upgrade is needed. If needed, it collects all of the names of the sheets (except the "Count" sheet which is a copy from a template), creates a new workbook with the same sheets as the old one, copies the data over to the proper sheets, closes the old workbook, deletes the old workbook, saves the new workbook with the same name as the old workbook.
Pretty straight forward and it worked great until it didn't. I'm not sure why, but now when the wkbFrom.Close command is executed it also exits the procedure.
I've been digging around and the only answer I could find that seemed to address my issue was to give some delay before/after the close so that Excel will have time to finish and not collide with itself. So I tried putting in a 5 second delay before the close command but to no avail.
Excel doesn't crash, it's still up and running properly. I checked the Event Viewer and Excel is not throwing any errors. The sub simply closes the workbook and then exits the sub.
Here is the full code for the sub.
Sub UpgradeHWWorkbook(Optional HWSheetVersion As Double)
'--------------------------------
'This sub upgrades a hardware tracking
'workbook to the newest version based on
'version in the variable HWSheetVersion
'--------------------------------
'Before anything else, Check to see if upgrade is needed.
'If sheet version is equal or larger than the plugin version
'OR the name of the sheet is wrong, exit without upgrading
'---------------------------------------------------------------------
If HWSheetVersion >= HWPlugInVersion Or _
Not ActiveSheet.CodeName Like "BaseHWSheet_*" Then
Exit Sub
End If
'---------------------------------------------------------------------
'VAR declarations----------------
Dim wkbFrom As Workbook 'Holds the original workbook
Dim wkbTo As Workbook 'Holds the new workbook
Dim sWKB As Workbook 'Holds Workbook where Count sheet is kept
Dim sWKS As Worksheet 'Holds Count sheet
Dim wks As Worksheet 'Holds worksheets
Dim wksNames() As String 'Holds the names of all the worksheets
Dim wkbFromName As String 'Holds the name of the original workbook
Dim wkbFromPath As String 'Holds the path of the original workbook
Dim wkbToPath As String 'Holds the path where the new workbook will be saved
Dim rng As String 'Holds the range of cells that will be copied
Dim x As Byte 'Holds counter
Dim wksName As Variant 'Holds the name of the current worksheet
'--------------------------------
'Sub Settings--------------------
Set wkbFrom = ActiveWorkbook 'Set the active workbook as the one that the data comes from
wkbFromPath = wkbFrom.Path 'Grabs the path of the original workbook
wkbFromName = wkbFrom.Name 'Grab the original workbook name
wkbToPath = wkbFrom.FullName 'Grab the path path and name in another var so we don't have to do it by hand
ReDim wksNames(0) 'Starts off the array that will hold the worksheet names
x = 0 'Flush the counter
rng = "A2:D18" 'The range of cells that will be copied and pasted
Application.DisplayAlerts = False 'Turn off annoying pop-ups
Set sWKB = Workbooks("StockroomAddins.xlam") 'Workbook with Count sheet to copy to new workbook
Set sWKS = sWKB.Worksheets("Count") 'Count sheet to copy to new workbook
'--------------------------------
'Get all of the worksheet names (except Count) in the workbook
'-----------------------------------------------------------------------
For Each wks In wkbFrom.Worksheets 'itenerate through the book
If Not wks.Name = "Count" Then 'If the worksheet isn't the "Count" sheet...
wksNames(x) = wks.Name 'add the sheet name to the array wksName()
x = 1 + UBound(wksNames) 'Increase the array by 1
ReDim Preserve wksNames(x) 'Increase the size of the array by 1
End If
Next wks
'-----------------------------------------------------------------------
'Create new workbook & add Count sheet
'-----------------------------------------------------------------------
Set wkbTo = Workbooks.Add 'Create the new workbook
wkbTo.Activate 'Make sure new book is active book
sWKS.Copy Before:=Sheets("Sheet1") 'Add the Count sheet to workbook
'-----------------------------------------------------------------------
'Iterate through the sheets in the original workbook, add sheets with the same name to the new book, copy data from the old sheet to the new sheet
'-----------------------------------------------------------------------
For Each wksName In wksNames 'Loop through all of the worksheet names and...
If Not wksName = "" Then 'If it isn't blank...
Call NewHardwareTrackingSheet(wksName, wkbTo) 'Call the sub that creates a new tracking sheet
wkbFrom.Worksheets(wksName).Range(rng).Copy 'Copy the data from the old sheet
wkbTo.Worksheets(wksName).Range(rng).PasteSpecial _
Paste:=xlPasteValues 'Paste the data (Values only) into the new sheet
End If
Next wksName
wkbTo.Worksheets("Sheet1").Delete 'Delete the default "Sheet 1" that every new workbook has
wkbFrom.Close Savechanges:=False 'close the original workbook
'-----------------------------------------------------------------------
'Delete the old workbook and save the new one in the same place with the same name as the old one
'-----------------------------------------------------------------------
Kill wkbToPath 'Kill the original
wkbTo.SaveAs Filename:=wkbToPath, FileFormat:=52 'Save the new as the original
Application.DisplayAlerts = True 'Turn annoying pop-ups back on
'-----------------------------------------------------------------------
'Clean up-------------------------------------
Set wkbFrom = Nothing: Set wkbTo = Nothing: Set sWKB = Nothing
Set wks = Nothing: Set sWKS = Nothing
'---------------------------------------------
End Sub
Any ideas on what I've messed up? I figured that since it worked at one point and now doesn't, that I've probably messed up the code somewhere but I'm not seeing it.
OK, I found my answer and I feel a bit stupid about it. Thanks to the folks who asked me some questions because they caused the thought process that worked.
It seems that the spreadsheet I was using to test the code must have gotten corrupted. I tried it on a couple of other files and it worked correctly. No wonder I couldn't find a code issue: there isn't one.
Goes to show the old adage "Measure twice, cut once." I should have tested on multiple files and not assumed my single test file was right.
Much thanks to those who read, thought about, and commented on my post. It is appreciated.
EDIT: Or not......
Came in this morning and it's not working again. There's got to be something in my code that is causing the issue on some and not on others. TBH, I have no idea what it is.
This is really causing me to bang my head on the wall.
OK, so I think I've figured this out.
I am calling this Sub to check the version each time a sheet is activated with this:
Public Sub Worksheet_Activate()
Application.Run "StockroomBarcodeSheets.UpgradeHWWorkbook", HWSheetVersion
End Sub
To do some other testing, I set up another sub inside my plug-in that just called the UpgradeHWWorkbook sub with a fake HWSheetVersion so I could force a workbook to upgrade. Lo, and behold, this setup worked perfectly every time.
So, when I call from the Worksheet_Activate() it exits on the .close command. When I call it from a sub inside the add-in, it works perfectly.
Because the UpgradeHWWorkbook is in a plug-in I thought that the restriction upon closing the calling workbook wouldn't come into affect. I was wrong.
I have a simple macro that opens a csv file and supposed to copy a cell in the working Workbook:
Sub macro1()
Dim build_w As Workbook
Dim build_s As Worksheet
Dim folder_st As String
Application.ScreenUpdating = False
folder_st = "c:\file.csv"
Set build_w = Application.Workbooks.Open(folder_st)
Set build_s = build_w.Sheets("build")
build_s.Range("A1").Copy
ActiveSheet.Paste Range("A284")
build_w.Close True
Application.ScreenUpdating = True
End Sub
If I comment out the line build_s.Range("A1").Copy everything is fine, but If I leave this in, Excel crashes every single time.
Any suggestions?
Are you aware that the ActiveSheet at the moment you paste is itself the build_s worksheet? This is the problem when working with stuff like Activesheet. It is always preferable to specify worksheet and workbook objects precisely, without counting on what is active at a given moment.
Eventually, to get the behavior you want, you should do:
build_s.Range("A1").Copy ThisWorkbook.ActiveSheet.Range("A284")
Have you tried handling any possible errors with:
On Error GoTo MyHandler
MyHandler:
PFB for the require code. CSV file cannot have multiple sheets so that's why it must be crashing. CSV files can have only one sheet in it, so no need to specify sheet name.
Sub macro1()
'Declared variables
Dim build_w As Workbook
Dim folder_st As String
'Disabling screen updates
Application.ScreenUpdating = False
'Initializing the file name
folder_st = "c:\file.csv"
'Opening the workbook
Set build_w = Workbooks.Open(folder_st)
'Copying the value of cell A1
Range("A1").Copy
'Selecting the cell A284
Range("A284").Select
'Pasting the copied value
ActiveSheet.Paste
'Saving the workbook by saving the .CSV file
build_w.Close True
'Enabling screen updates
Application.ScreenUpdating = True
End Sub
it's because upon opening csv file it becomes the Active workbook and its only worksheet the Active worksheet
you can exploit this at your advantage like follows:
Option Explicit
Sub macro1()
Dim folder_st As String
Application.ScreenUpdating = False
folder_st = "c:\file.csv"
With ActiveSheet '<--| reference your currently active sheet before opening csv file
Application.Workbooks.Open(folder_st).Sheets("build").Range("A1").Copy '<--| open csv file (and it becomes the Active Workbook) and reference its "build" sheet range "A1" and copy it...
.Range("A284").PasteSpecial '<--| paste it to your referenced sheet range A284
Application.CutCopyMode = False '<--| release clipboard
ActiveWorkbook.Close False '<--| close Active workbook, i.e. the csv file
End With
Application.ScreenUpdating = True
End Sub