Copy data from an Excel sheet to different files - excel

I have an excel sheet which has some huge data. Data is organized as follows,
A set of 7 columns and n rows; as in a table, and 1000s of such tables are placed horizontally with an empty column to separate. A screenshot is below..
...
I just want to have data of every 'table' saved into a different file. Manually it would take ever! So, Is there a macro or something I would automate this task with.
I am not well versed with writing macros or any VBA stuff.
Thanks,

Tony has a valid point when he says
If the table starting at C1 finishes on row 21, does the next table start at C23? If the table starting at K1 finishes on row 15, does the next table start at K17 or K23?
So here is a code which will work in any condition i.e data is set horizontally or vertically.
DATA SNAPSHOT
CODE
'~~> Change this to the relevant Output folder
Const FilePath As String = "C:\Temp\"
Dim FileNumb As Long
Sub Sample()
Dim Rng As Range
Dim AddrToCopy() As String
Dim i As Long
On Error GoTo Whoa
Application.ScreenUpdating = False
Set Rng = ActiveSheet.Cells.SpecialCells(xlCellTypeConstants, xlTextValues)
If Not Rng Is Nothing Then
AddrToCopy = Split(Rng.Address, ",")
FileNumb = 1
For i = LBound(AddrToCopy) To UBound(AddrToCopy)
ExportToSheet (AddrToCopy(i))
Next i
End If
MsgBox "Export Done Successfully"
LetsContinue:
Application.ScreenUpdating = True
Exit Sub
Whoa:
MsgBox Err.Description
Resume LetsContinue
End Sub
Sub ExportToSheet(rngAddr As String)
Range(rngAddr).Copy
Workbooks.Add
ActiveSheet.Paste
ActiveWorkbook.SaveAs Filename:= _
FilePath & "Output" & FileNumb & ".csv" _
, FileFormat:=xlCSV, CreateBackup:=False
Application.DisplayAlerts = False
ActiveWorkbook.Close
Application.DisplayAlerts = True
FileNumb = FileNumb + 1
End Sub
NOTE: The above code will work for cells with only Text Values. For cells with only Numeric Values you have to use
Set Rng = ActiveSheet.Cells.SpecialCells(xlCellTypeConstants, xlNumbers)
And for AlphaNumeric Values (As in your question above), use this
Set Rng = ActiveSheet.Cells.SpecialCells(xlCellTypeConstants)
HTH
Sid

As long as there is a blank row and a blank column around any datasets, this will use the AREAS() method to put them all in separate workbooks.
As per the prior example, it saves as CSV, but of course you can save it as you wish.
Option Explicit
Sub ExportDataGroups()
Dim fPATH As String, Grp As Long, DataRNG As Range
fPATH = "C:\Path\Where\I\Want\My\Files\Saved\" 'remember the final \
Application.ScreenUpdating = False
Set DataRNG = ActiveSheet.UsedRange
For Grp = 1 To DataRNG.Areas.Count
DataRNG.Areas(Grp).Copy
Sheets.Add
Range("A1").PasteSpecial
ActiveSheet.Move
ActiveWorkbook.SaveAs Filename:=fPATH & "-" & Format(Grp, "0000") & ".csv", _
FileFormat:=xlCSV, CreateBackup:=False
ActiveWorkbook.Close
Next Grp
MsgBox "A total of " & Grp & " files were created"
Application.ScreenUpdating = True
End Sub

In your response to my comment you state: "File name, I never thought about it. Could be anything for now." From bitter experience I can tell you that dealing with thousands of files with system generated names is a nightmare. You need to fix the name problem now.
I am also nervous about AddrToCopy = Split(Rng.Address, ","). Rng.Address will be of the form: "$C$1:$I$16, $K$1:$Q$16, $S$1:$Y$16, $C18$I$33, $K$18:$Q$33, $S$18:$Y$33, ...". If you search the internet you will find sites that tell you that Rng.Address has a maximum length of 253 characters. I do not believe this is correct. In my experience, Rng.Address is truncated at a complete sub-range. My experimentation was with Excel 2003 but I have found noting on the internet to suggest this limitation has been fixed in later versions of Excel. You much check Rng.Address with your version of Excel! I am not familar with Jerry Beaucaire, although he offers an interesting solution. Sid Rout always produces excellent code. If there is a problem, I am sure they will be able to fix it.
However, the real purpose of this "answer" is to say I would split this problem into three. This has lots of advantages and no disadvantages of which I am aware.
Step 1. Create a new worksheet, TableSpec, with the following columns:
A Worksheet name. (If tables are spread over more than worksheet)
B Range. For example: C1:I16, K1:Q16
C - I Headings from table. For example, AAPL, Open, High, Low, Close, Volume, AdjClose
Step 2. Check worksheet TableSpec; for example, are all table listed? Think about the file name and add column H to contain it. I read one of your comments to mean you would "AAPL" as the filename for the first table in which case you could set H2 to "=C2". Is "AAPL" unique? You could had a sequence number. There are lots of choices which you can think about before you generate any files.
Step 3. Worksheet TableSpec now gives all the information necessary to generate your files. You could delete most of the contents and test the file creation code on a couple rows.
I hope you can see advantages of this stepped approach, partcularly if your VBA is weak. Best of luck.

Related

Adding conditions to excel export worksheets loop

Currently learning VBA in bits and pieces.
Confused on where to insert a condition in the following piece to check each worksheet respectively on cell address E8 for example for ANY entry other than “”.
Sub SaveWorkshetAsPDF()
Dim ws As Worksheet
timestamp = Format(Date, "mmddyyyy ")
For Each ws In Worksheets
ws.Select
ws.ExportAsFixedFormat xlTypePDF, Filename:= _
ActiveWorkbook.Path & "\" & timestamp & ws.Name & ".pdf"
Next ws
End Sub
Any assistance would be amazing.
Want it to stop exporting if a value is present in a specified cell.
I think this should get you what you need. I included some comments that might help out a little and give you a method to have a condition to check.
A couple notes to improve:
Always good to define variable such as timestamp.
No need to actively select the sheet, you can get the file's workbook path using the parent property.
For items that are hard-coded, I'm a fan of putting the values at the top of the macro as constants. It makes changing things easier.
Hope this helps.
Sub SaveWorkshetAsPDF()
Const theValueToStop As String = "Stop" 'or whatever, if it's a number change to Long
Const theAdddress As String = "E8" 'makes it easier to find and change if needed.
Dim ws As Worksheet, timestamp As String
timestamp = Format(Date, "mmddyyyy ")
For Each ws In Worksheets
'no neeed to select use parent property for address.
'ws.Select
If ws.Range(theAdddress).Value <> theValueToStop Then
ws.ExportAsFixedFormat xlTypePDF, Filename:= _
ws.Parent.Path & "\" & timestamp & ws.Name & ".pdf"
End If
Next ws
End Sub

Referencing Variables in a Different Sub Statement. Subscript Out of Range

First time programmer here, started teaching myself VBA a few days ago to write this. The goal is to have the code be able to reference two workbooks that are not constants. One is selected by the user and the other is running the macro. I have defined the workbooks in a sub statement previous, but when I try to reference it in a sub statement further down the line I get error '9' "subscript out of range." I have tried using call but it also came up with undefined errors (it could be that I don't understand the 'call' statement).
If you have an additional moment to look over my formula and make sure it is formatted correctly that would be a big help as well. I just know it is going to be a huge problem when I get there.
P.S. I just noticed that I have been spelling reference wrong in my code this entire time. Go ahead, laugh.
'''
Sub Openfile()
Dim FileToOpen As Variant, wbRefrence As Workbook
Dim wbOracle As Workbook
Set wbOracle = ThisWorkbook
FileToOpen = Application.GetOpenFilename(FileFilter:="Excel Workbooks (*.xls*),*.xls*", Title:="Open Database File")
If FileToOpen = False Then
MsgBox "No file selected, cannot continue." 'If the user does not open a file this message is displayed
Exit Sub 'If no file is selected the program stops running
End If
Set wbRefrence = Workbooks.Open(FileToOpen)
Workbooks.Open (FileToOpen) 'If a file is selected it opens that file.
Call LoopTest1
End Sub
Sub LoopTest1()
Dim BlankCell As Boolean
Dim i As Long
'Loop until a blank cell is encountered
Do While BlankCell = False
i = i + 1
If Cells(i, "C").Value = "" Then
BlankCell = True 'When it reaches a blank cell BlankCell will now be true which ends the do while formula.
End If
Application.Workbooks("wbOracle").Sheets("Cancel Requisition Lines").Range("C16").Select
'Formula for "do while" condition
Selection.Formula = "=IF(INDEX(['wbRefrence']Sheet1!'A2000:M2000',MATCH(1,(['wbRefrence']Sheet1!'D:D'=['wbOracle']'Cancel Requisition Lines'!'C16')*(['wbRefrence']Sheet1!'E:E'=['wbOracle']'Cancel Requisition Lines'!'I16')*(['wbRefrence']Sheet1!'F:F'=['wbOracle']'Cancel Requisition Lines'!'J16'),0),9)>=['wbOracle']'Cancel Requisition Lines'!M:M, ""materials supplied"","""")"
Loop
End Sub
'''
You've got a great start to your code, so here are a few things to help get you on your way...
Always use Option Explicit.
Try to define your variables as close as possible to its first use (your current code is short enough to not matter much, its just a habit to get into).
The Call usage has been deprecated and it's not needed. If you want to call a function or sub, just use the name of that routine.
Also, if you have a sub call that is by itself in a single statement, the parens are NOT required to enclose the parameters. If you're making the call in a compound or assignment statement, you MUST use the parens.
A good habit is to always make it clear what workbook, worksheet, and range you are referencing with a fully qualified reference every single time. This one thing trips up so many VBA users.
For example, in your LoopTest1 code, you are referring to Cells. Without any qualifying reference, the VBA code assumes you are referring to the currently active worksheet (whichever and whereever that is). So define some intermediate variables and make it clear (see example below).
To help clear up any confusion in your LoopTest1 sub, I added some parameters so that you can work on any two workbooks you choose.
My own preference is to build up a complicated formula in a separate string variable so that I can examine it in the debugger and make sure it's exactly right. So you can see I defined a formulaText string and built up your formula.
I "corrected" a few things I found in the formula (but I cannot tell you it will work), including:
Using the FullName property of both workbooks in the formula (so you never have it hard-coded)
Using the Name property of the worksheet (so you never have it hard-coded)
Properly arranging the single-tick marks for the proper workbook/worksheet reference (overall, you were using too many single-ticks in your formula)
Only you can determine if the formula is actually what you want and if it works. But that might be a separate question :)
Option Explicit
Sub Openfile()
Dim wbOracle As Workbook
Set wbOracle = ThisWorkbook
Dim FileToOpen As Variant
FileToOpen = Application.GetOpenFilename( _
FileFilter:="Excel Workbooks (*.xls*),*.xls*", _
Title:="Open Database File")
If FileToOpen = False Then
MsgBox "No file selected, cannot continue."
Exit Sub
End If
Dim wbReference As Workbook
Set wbReference = Workbooks.Open(FileToOpen)
Workbooks.Open FileToOpen
LoopTest1 wbOracle, wbReference, "Cancel Requisition Lines"
End Sub
Sub LoopTest1(ByRef wbOracle As Workbook, _
ByRef wbReference As Workbook, _
ByVal oracleSheetName As String)
Dim wsOracle As Worksheet
Set wsOracle = wbOracle.Sheets(oracleSheetName)
Dim wsReference As Worksheet
Dim referenceCell As Range
Set wsReference = wbReference.Sheet1
Set referenceCell = wsReference.Range("C1")
Dim formulaText As String
Do While Not IsEmpty(referenceCell)
formulaText = "=IF(INDEX('[" & wbReference.Name & _
"]Sheet1'!A2000:M2000,MATCH(1,(['" & wbReference.FullName & _
"]Sheet1'!D:D=['" & wbOracle.FullName & _
"]" & wsOracle.Name & "'!C16)*('[" & wbReference.FullName & _
"]Sheet1!E:E=[" & wbOracle.FullName & _
"]" & wsOracle.Name & "'!'I16')*([" & wbReference.FullName & _
"]Sheet1!F:F=[" & wbOracle.FullName & _
"]" & wsOracle.Name & "'!'J16'),0),9)>=[" & wbOracle.FullName & _
"]" & wsOracle.Name & "'!M:M, ""materials supplied"","""")"
wsOracle.Range("C16").Formula = formulaText
Set referenceCell = ReferenceCell.Offset(1, 0)
Loop
End Sub

run out of memory by repeatedly exporting worksheets using VBA in 64-bit Excel

I need to export processed data from a master file to a large number of ".xlsx" ouput files.
In the master file, I run VBA code to repeat the following:
1). insert a new worksheet.
2). put processed output data in that newly inserted worksheet.
3). move the worksheet to a new workbook and save that workbook.
After a little over 2400 worksheets have been exported this way, Excel displays an error message, mentioning that "there isn't enough memory to complete this action", and suggesting the use of 64-bit Excel.
I changed to 64-bit Excel. The same message appeared after more or less the same number of output files had been produced.
Since 64-bit software allows a much larger memory space, if the 64-bit version and the 32-bit version exhaust memory at the same point of progress, it seems to me that the problem might not have been caused by normal memory usage.
May be it is caused by something like calling fopen() repeatedly without calling fclose() in C.
The skeleton of my code is like:
Cur_Path = ActiveWorkbook.Path
Application.ScreenUpdating = False
For r = 12 To 4653
' Add Blank sheet
Set ws = Sheets.Add(After:=Sheets(Sheets.Count))
' Export Sheet
Export_fname = Cur_Path & "\" & ws.Name & ".xlsx"
ws.Move
ActiveWorkbook.SaveAs Filename:=Export_fname, FileFormat _
:=xlOpenXMLWorkbook, CreateBackup:=False
ActiveWindow.Close
Next r
Application.ScreenUpdating = True
The debugger showed that the problem arose when running the line "ws.Move".
Would anyone please let me know what is wrong with my code, or suggest a work-around to get over that (seemingly) 2433 worksheets limit?
This may work better - each workbook only has 1 sheet and none are stored in the original book.
You haven't said how you put the processed data on the sheet so I've just populated a few cells with data.
Sub Test1()
Dim Cur_Path As String
Dim r As Long
Dim wrkBk As Workbook
Dim wrkSht As Worksheet
Cur_Path = ThisWorkbook.Path
For r = 12 To 4653
Set wrkBk = Workbooks.Add(xlWBATWorksheet) 'Create workbook with 1 sheet.
Set wrkSht = wrkBk.Worksheets(1) 'Set reference to worksheet.
With wrkSht
.Name = wrkSht.Name & " - " & r 'Ensure a unique name.
'Populate the sheet with some data.
.Range("A1") = wrkSht.Name
.Range("B1:D1") = Array(ThisWorkbook.Name, wrkBk.Name, Cur_Path)
End With
wrkBk.SaveAs Filename:=Cur_Path & "\" & wrkSht.Name & ".xlsx", _
FileFormat:=xlOpenXMLWorkbook
wrkBk.Close
Next r
End Sub

Error when creating new workbook with vba, copying 2 of many sheets

The following code results in an .xls with the 2 worksheets I want. Only I don't end up with just values.. the formatting is in there (and I don't think it should be. paste. values. dammit.), and the .xls has a unbreakable link to the original document that doesn't need to be there (and I'm thinking shouldn't be there). All the cells only contain values and do not contain any of the equations contained in the source workbook.
When I open the newly created .xls I receive the message "the file format and extension of [ws name].xls don't match. The file could be corrupted or unsafe. Unless you trust its source, don't open it. do you want to open it anyway?"
I loathe the lack of trust.. :)
What am I doing wrong?
Sub QUOTE_ITEM_OUTPUT()
Dim ws As Worksheet
Dim Filename As String
Dim Filelocation As String
Dim UserName As String
Dim Password As String
Filename = Worksheets("CALCULATION PAGE").Range("ITEMNUM").Value & "_" & Worksheets("CALCULATION PAGE").Range("PDFSAVEREV").Value & ".xls"
Filelocation = "\\GSWGS\Apps\Global\FILES\Import\GWS-Upload-TST\"
With Application
.ScreenUpdating = False
' Copy specific sheets
Sheets(Array("ITEM OUTPUT", "ROUTING")).Copy
' Paste sheets as values
For Each ws In ActiveWorkbook.Worksheets
ws.Cells.Copy
ws.[A1].PasteSpecial Paste:=xlValues
Application.CutCopyMode = False
Cells(1, 1).Select
ws.Activate
Next ws
Cells(1, 1).Select
ActiveWorkbook.SaveCopyAs Filelocation & Filename
ActiveWorkbook.Close SaveChanges:=False
.ScreenUpdating = True
End With
End Sub
You are saving as .xls file, but have not specified that file format in the saveAs method. That's why you are getting security warnings...
You need to specify that parameter in the SaveAs method.
ActiveWorkbook.SaveAs Filename:=Filelocation & Filename, FileFormat:=56
Here is a link to MSDN page for the various fileFormat parameters:
https://msdn.microsoft.com/en-us/library/office/ff198017.aspx
EDIT - for second problem you face:
As for the fact that formats are being carried across, that is because you are not using the correct Enumeration value.
ws.[A1].PasteSpecial Paste:=xlValues
should be:
ws.[A1].PasteSpecial Paste:=xlPasteValues
Use another sub to 'cleanse' the sheet
Sub ApplyValuesTo(ByVal sh As Excel.Worksheet)
For Each cell In sh.UsedRange.Cells
With cell
.Value = .Value
'// This may take a while; the next line will allow you to manually
'// break if needed (e.g. If you have a lot of data in the sheet)
DoEvents
End With
Next
End Sub

excel macro for vlookup

I have 2 different workbooks with a set of parameters, e.g. car parts number, sales prices, etc. The 2 different workbooks will always have the same car parts numbers but they are not in order. So I was thinking of using a vlookup to match the parameters on one workbook to the other related to the respective parts' numbers.
Thus, I used vlookup to perform this task. It works, but I want to implement this using a macro, so I would not need to manually do the vlookup every time. Is it possible to create such a macro given that the workbooks (file names) would be different every time?
I actually tried recording the macro and the vlookup records the parameters it needs relating to the file name.
EDIT: code from comment:
Sub Macro1()
ActiveCell.FormulaR1C1 = "=VLOOKUP('[TI_DBP_effective_06 May 2013.xls]NON SLL'!C1,'[TI_DBP_effective_06 May 2013.xls]NON SLL'!C1:C3,3,FALSE)"
Range("I1").Select Selection.AutoFill Destination:=Range("I1:I9779")
Range("I1:I9779").Select
End Sub
Try something like this. You will have to place this macro in your Personal macro workbook, so that it is available all the time, no matter what workbooks are open. It will prompt you for two files, and then open them, and should insert the formula. Let me know if it gives you any trouble since I am not able to test it right now.
NOTE: This looks up the value one column to the LEFT of the cell you select, and then looks in columns 1:3 of the other file. Modify as needed.
Sub Macro1()
Dim file1 As String
Dim file2 As String
Dim wbSource As Workbook
Dim wbLookup As Workbook
Dim startRange As Range
file1 = Application.GetOpenFilename(Title:="Select the file to update")
If Len(Dir(file1)) = 0 Then Exit Sub
file2 = Application.GetOpenFilename(Title:="Select the LOOKUP file")
If Len(Dir(file2)) = 0 Then Exit Sub
Set wbLookup = Workbooks.Open(file2)
Set wbSource = Workbooks.Open(file1)
On Error Resume Next
Set startRange = Application.InputBox("Select the first cell for the formula", "Autofill VLOOKUP", Type:=8)
On Error GoTo 0
If Not startRange Is Nothing Then
Application.Goto startRange
startRange.FormulaR1C1 = "=VLOOKUP('[" & wbSource.Name & "]NON SLL'!RC[-1],'[" & wbLookup.Name & "]NON SLL'!C1:C3,3,FALSE)"
startRange.AutoFill Destination:=startRange.End(xlDown)
End If
End Sub

Resources