Export sheet from Excel to CSV - vba

I am creating a spread sheet to help ease the entry of data into one of our systems. They are entering inventory items into this spread sheet to calculate the unit cost of the item (item cost + tax + S&H). The software we purchased cannot do this.
Aan invoice can have one or more lines (duh!) and I calculate the final unit cost. This is working fine. I then want to take that data and create a CSV from that so they can load it into our inventory system. I currently have a second tab that is laid out like I want the CSV, and I do an equal cell (=Sheet!A3) to get the values on the "export sheet". The problem is when they save this to a CSV, there are many blank lines that need to be deleted before they can upload it. I want a file that only contains the data that is needed.
I am sure this could be done in VBA, but I don't know where to start or know how to search for an example to start. Any direction or other options would be appreciated.

Look at Range.SpecialCells(xlBlanks).EntireRow.Delete, I think this is what you are looking for!

expanding on #dwo's answer - this code will allow you to both remove the blank rows and export to CSV:
Sub export_to_csv(sheetname As String, OutDir As String)
Sheets(sheetname).Select
Set wb = ActiveWorkbook
Set newwb = Workbooks.Add()
wb.ActiveSheet.Copy newwb.ActiveSheet 'copy sheet to new workbook
newwb.ActiveSheet.Activate
ActiveSheet.UsedRange 'refresh the used range
Range("A1:A" & ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row).Select 'select relevant cells
Selection.SpecialCells(xlBlanks).EntireRow.Delete 'remove empty rows
Application.DisplayAlerts = False 'avoid warning message when overwriting existing files
newwb.SaveAs OutDir & sheetname, xlCSVWindows 'save as CSV
newwb.Close 'close new workbook
Application.DisplayAlerts = True 'reset warning messages
End Sub
Sub test()
export_to_csv sheetname:="Sheet1", OutDir:="C:\temp\"
End Sub

The solution on this page worked best for me. I just had to modify it to allow it to work for what I needed.

Related

VBA - copy specific rows from one sheet into another sheet when user closes file

I'm new to VBA and I'm struggling a lot with a file I want to build.
I have a main Sheet that in a simple way looks like this (starting at column B - A is an empty column):
main
This is a simplified version just for the example. The first table of the sheet varies from B13 to O92, the second varies from B104 to O114 but some of those rows might be empty.
My goal is to join rows with content from the first area with rows with content from the second area in a different sheet (Sheet1), add to the left a column with 1s and "Cell 0" (content of cell B1). Using the example, the result would be something like this:
Sheet1
Sheet1 will stay hidden as I'm using it as a source of information to a different file. In fact, I may not need the 1s column if I find a way to copy information in a different way - I'm doing it like this (wsSource is Sheet1):
lRow = wsSource.Columns("A").Find(1, SearchDirection:=xlPrevious, LookIn:=xlValues, LookAt:=xlWhole).Row
wsSource.Range("B1:N" & lRow).Copy
I was trying to do it so Sheet1 is "emptied" when the file is opened and edited when file is closed - so that if new rows are added or information updated, it gets into Sheet1 every time.
I've tried several stuff I found online but couldn't make it to work. My main problem is adding the specified rows one after the others but I'm also struggling to reset Sheet1 every time the file is opened and automatically running the macro when file is closed.
Any help would be really appreciated.
Hopefully this will get you started. Both subs need to be pasted in VBE under ThisWorkBook rather module or sheet(n).
The first sub will execute when the workbook is open.
Are you sure you want to clear your sheet under these circumstances?
You will never have access to your table (without workarounds) since it will clear when opening every time.
If this is what you need, see the below method to clear a dynamic range (Col A - D down to last cell used in Col A) on Sheet1 every time the workbook that houses this code is opened.
Private Sub Workbook_Open()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim ClearRange As Range
Application.ScreenUpdating = False
With ws
.Visible = xlSheetVisible
.Range("A1:D" & .Range("A" & .Rows.Count).End(xlUp).Row).ClearContents
.Visible = xlSheetHidden
End With
Application.ScreenUpdating = True
End Sub
Next, the below sub will only execute before the book is closing. This is where the bulk of your code will go to build your table.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.ScreenUpdating = False
ThisWorkbook.Sheets(1).Visible = xlSheetVisible
'Code goes here
ThisWorkbook.Sheets(1).Visible = xlSheetHidden
Application.ScreenUpdating = True
End Sub
You will need to qualify your objects (Ranges, Cells, etc.) directly (which sheet) since the code will not be housed in a sheet. The first sub uses a With block to qualify ranges and the second sub directly qualifies all objects with ThisWorkbook.Sheets(1).
Lastly, I recommend writing your code to build your table inside a module (qualify ranges!) so you can test and debug without needing to close/open your book continuously. Once you have the code working in a module, you can copy and paste the code directly into the 2nd sub here and you are good to go!

Reorder selection of files

I have created an Excel Macro at work to be used for assembling consolidated reports in Excel. The macro allows you to select a number of files, it then goes through those files and renames the first tab in each file (which with the way it is used is the only tab) to match the file name (so you can rename the files without having to open all and rename tabs), and then merges all these tabs into your current workbook, creating a large consolidated report.
However, I am running into the problem that the macro defaults to do this to the selected files in the alphabetical order of the file names, which then requires us to sort the tabs after we have run the macro.
What I am looking for is an adjustment to the macro that will sort the files by creation date&time, oldest to newest, because the order the files are created generally matches the desired result in our final reports.
I figure I will need to make a separate for i = 1 to etc loop that re-orders the selected files, store the new order, and use that order for the current loop, but I am not sure how to do that. I did to some searches, but while I found some similar items, anything similar seems to use a folder selection rather than individual file selection, and there were other differences I couldn't quite translate to my macro either. Here is the current macro:
Sub Reports()
Dim numberOfFilesChosen, i As Integer, Workbookname As String, tempFileDialog As FileDialog, mainWorkbook, sourceWorkbook As Workbook
Dim tempWorkSheet As Worksheet
Set mainWorkbook = Application.ActiveWorkbook
Set tempFileDialog = Application.FileDialog(msoFileDialogFilePicker)
tempFileDialog.AllowMultiSelect = True
numberOfFilesChosen = tempFileDialog.Show
Application.ScreenUpdating = False
For i = 1 To tempFileDialog.SelectedItems.Count
Workbooks.Open tempFileDialog.SelectedItems(i)
Set sourceWorkbook = ActiveWorkbook
With sourceWorkbook
Workbookname = Left(.Name, InStr(.Name, ".") - 1)
.Sheets(1).Name = Workbookname
End With
For Each tempWorkSheet In sourceWorkbook.Worksheets
tempWorkSheet.Copy after:=mainWorkbook.Sheets(mainWorkbook.Worksheets.Count)
Next tempWorkSheet
sourceWorkbook.Close savechanges:=False
Next i
Application.ScreenUpdating = True
End Sub
I hope you can help me, thank you!

Merging multiple different worksheets into master template with weird formatting

This might seem a bit complicated, so let me know if I need to be more clear.
I receive ~20 reports from one department and I am in charge of consolidating data from a specific worksheet in each report into one master file. All the reports are the exact same and the data ranges are pretty much set. I am relatively new to VBA, but I was able to piece together a code through research to copy and paste all the data into a new workbook using a loop. It would, however, be ideal if I could put this data directly into the report template. This is where I need help. The formatting of the template is not ideal - my headers don't start until A25 and there's a totals tab and instructions on the bottom so I can't just put the values in the last empty row.
I would like to figure out how to ensure that the data from the first worksheet I pull from gets put in A26 and the data from the following worksheets get put in the next available cell.
Below is the code I currently have. I understand generally what things mean, but just keep in mind I'm a VBA noob... so be nice :)
Sub MergeData()
Dim FileName As String, FilePath As String, FolderPath As String
Dim LastCell As Range
With ThisWorkbook.Worksheets("Sheet1")
Set LastCell = .Cells(.Rows.Count, 1)
End With
FolderPath = "C:\Desktop" 'changed for privacy
FilePath = FolderPath & "*.xls*"
FileName = Dir(FilePath)
Do While FileName <> ""
With Workbooks.Open(FolderPath & FileName)
Worksheets("SBP WIP").Range("A26:AK336").Copy
LastCell.End(xlUp).Offset(1).PasteSpecial xlPasteValues
ActiveCell.Copy
.Close False
End With
FileName = Dir
Loop
End Sub
Thanks!
In your first With-End With block just add one line
With ThisWorkbook.Worksheets("Sheet1")
.Range("A25").Value = "X" ‘ make sure to hit row 25 in subsequent “xlUps”
Set LastCell = .Cells(.Rows.Count, 1)
End With
And before macro ending add:
ThisWorkbook.Worksheets("Sheet1").Range("A25").ClearContents

VBA Lookup in Another Workbook

I am having an vba problem with Excel. So I have this workbook, "Book Tool - Updated Feb. 2017.xlsb", that I am currently updating and will distribute to about 10 team members to use to keep track of their work. What I am trying to do is lookup data from an outside document, "Team Data", put that in Column DE of the "Book Tool - Updated Feb. 2017.xlsb" file. So I wrote the below code, where when the team member pushes a button, it opens up the lookup file, looks for the data in Column A of the "SICcode" sheet of that external file, matches it with Column B of the "Book Sheet" of the "Book Tool" file, and returns the value in Column D of the lookup file. It runs for the length of the "Book Sheet", closes the external file, and you get a popup that the data add is done.
Now when I did this code myself, it works great. Automatically opened the external document, did the lookups, returned the correct value, closes the external document, the pop up. So I sent the file with the macro to my manager to play around with before giving it to the rest of my team, but the macro does not work. When the macro runs, the external document opens, it seems like it is running through the lookups, closes the external file, and the pop up appears, but there is no value in the DE column, nor is there the lookup formula there. My manager didn't change the name of the Tool document, he didn't mess with any code. He emailed it back to me and with that copy the formula isn't working, but I checked it with my master copy formula and even though it's the same, the macro will not populate the data.
We have to keep the external data in a separate file, because otherwise the tool with the lookup data is over 2MB and takes forever to run or crashes.
Is there something about emailing the tool back and forth that messes with the file, or is there some formatting issue I need to look into that causes it not to work? With my master copy on my computer, the code always works regardless if I work in a virtual desktop, have it in a different folder, whatever.
I am just okay with vba, I don't know all of the technicalities of this process, so maybe I am overlooking some flaw with how I've set it up or limitations Excel has. Any guidance or help would be appreciated.
Sub AddData()
On Error Resume Next
'Open External Data Source
Workbooks.Open Filename:= _
"W:\USB\Reporting\Book Tool\Attachments\Team Data.xls"
'View sheet where data will go into
Windows("Book Tool - Updated Feb. 2017.xlsb").Activate
'Gets last row of Tool sheet
Sheets("Book").Select
lastrow = Cells(Rows.Count, "B").End(xlUp).Row
'Lookup in External File
Sheets("Book").Select
Range("DE2:DE" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-108],'[Team Data.xls]SICcode'!C[-109]:C[-104],5,FALSE)"
'Close External Data File
Windows("Team Data.xls").Activate
ThisWorkbook.Saved = True
Application.DisplayAlerts = False
ActiveWindow.Close
MsgBox "Data Add Done"
End Sub
Be sure to properly qualify your statements, and also it would be wise to assign the appropriate workbook to a variable. See the modified code below:
Sub AddData()
On Error Resume Next ' I also suggest removing this since it wont warn you on an error.
Dim wb as Workbook
Dim wbExternal as Workbook
Dim ws as Worksheet
Dim wsExternal as Worksheet
'Open External Data Source
Set wbExternal = Workbooks.Open Filename:= _
"W:\USB\Reporting\Book Tool\Attachments\Team Data.xls"
' Depending on the location of your file, you may run into issues with workbook.Open
' If this does become an issue, I tend to use Workbook.FollowHyperlink()
'View sheet where data will go into
' Windows("Book Tool - Updated Feb. 2017.xlsb").Activate
' Set wb = ActiveWorkbook
' As noted by Shai Rado, do this instead:
Se wb = Workbooks("Book Tool - Updated Feb. 2017.xlsb")
' Or if the workbook running the code is book tool
' Set wb = ThisWorkbook
'Gets last row of Tool sheet
Set ws = wb.Sheets("Book")
lastrow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
'Lookup in External File
Set wsExternal = wbExternal.Sheets("Book")
wsExternal.Range("DE2:DE" & lastrow).FormulaR1C1 = "=VLOOKUP(RC[-108],'[Team Data.xls]SICcode'!C[-109]:C[-104],5,FALSE)"
'Close External Data File
ThisWorkbook.Saved = True
Application.DisplayAlerts = False
Windows("Team Data.xls").Close
MsgBox "Data Add Done"
End Sub
I would also recommend browsing through SO for tips on avoiding .Select and .Activate as this can make your code unreliable and in some cases can slow down your code significantly.
Lastly, if performance is a concern you may want to look into loading your lookup values into arrays and finding the corresponding values this way. It will completely depend on what kind of data you are working with. I had a workbook using filldown vlookups that went from running in a matter of 5-10 minutes or more to consistently running in less than 20 seconds by replacing VLOOKUPS with for looping arrays.

Copy data from multiple excel sheets and append that to a single excel sheet using VBScript

The scenario is as follows:
I have an excel (.xls) file with data. (eg. A.xls)
The Data on this excel file are on a single worksheet (Sheet 1).
The number of columns in this file is fixed i.e. 8
However, the number of rows containing data may vary from time to time. (This file is updated by another program from time to time)
Now, I have another excel file (eg. B.xls) with similar type of data but not same as the contents of A.xls.
The number of columns in B.xls is 8 as well. However, the number of rows containing data are unknown.
I want to copy the contents of A.xls, 2nd row onwards (excluding the 1st row containing the column headers) and append/paste the same to the B.xls file, without over-writing the existing data on B.xls.
With all these details in mind, I want to write a vbscript to automate this task.
Please help.
Thanks a lot, in advance.
It needs a lot of cleanup, but something like this should work. I'll clean it up a bit and then make an edit.
Sub CopyRows()
' Choose the name of the Second Workbook and last column.
' It must be in the same directory as your First Workbook.
secondWorkbook = "B.xls"
lastColumn = "H"
' A couple more variables
currentWorkbook = ThisWorkbook.Name
Workbooks.Open ThisWorkbook.Path & "\" & secondWorkbook
' In the First Workbook, find and select the first empty
' cell in column A on the first Worksheet.
Windows(currentWorkbook).Activate
With Worksheets(1).Columns("A:A")
Set c = .Find("", LookIn:=xlValues)
If Not c Is Nothing Then
' Select and copy from A2 to the end.
secondAddress = Replace(c.Address, "$A$", "")
Range("A2:" & lastColumn & CStr(CInt(secondAddress) - 1)).Select
Selection.Copy
End If
End With
' Activate the Second Workbook
Windows(secondWorkbook).Activate
With Worksheets(1).Columns("A:A")
Set c = .Find("", LookIn:=xlValues)
If Not c Is Nothing Then
' Select and paste the data from First Workbook
Range(c.Address).Select
ActiveSheet.Paste
End If
End With
End Sub
Update: That should do the trick. I copied from the wrong workbook the first time around, too. Let me know if you have questions.
This is something the Macro Recoder could have written for you. You would come out with different approach.
Turn on recording. Open A.xls and B.xls. Move down one row on a. Press Shift+End then →, then Shift+End+↓. Then Ctrl+C to copy your data. Switch back to B. End+↓, ↓. Ctrl+V to paste. Turn off recording.
You can record in Excel.
Alt+T,M,R
then Home key then ↑. Stop recording.
Look what Excel wrote
Selection.End(xlUp).Select
or if you had of recorded Go To dialog
Application.Goto Reference:="R1C1"
or if you had of recorded Ctrl+Home
Range("A1").Select
To convert to vbscript
Record the steps in excel macro recorder. You have to rewrite it a bit because it uses a type of syntax that vbs doesn't.
This applies (I don't have a medium9) xlRangeAutoFormatAccounting4 in vba.
Selection.AutoFormat Format:=xlRangeAutoFormatAccounting4, Number:=True, _
Font:=True, Alignment:=True, Border:=True, Pattern:=True, Width:=True
So first look up constants in vba's object browser. xlRangeAutoFormatAccounting4 = 17
Then look the function up in object browser and look at the bottom for the function definition,.
Function AutoFormat([Format As XlRangeAutoFormat = xlRangeAutoFormatClassic1], [Number], [Font], [Alignment], [Border], [Pattern], [Width])
So the vba becomes in vbs (and vbs works in vba) (and as you can see you can work out the correct way without needing to look the function up usually)
Selection.AutoFormat 17, True, True, True,True, True, True
So your code becomes
objXLWs.Range("A3").CurrentRegion.Select.AutoFormat 17, True, True, True,True, True, True