Creating Multiple Workbooks from One Workbook VBA - vba

I am new to this site and this is my first question, so if I didn't set this up correctly please excuse me. Here is some background info.
We purchased a digital book with relevant company information. It came as a unformulated excel workbook which was great. This workbook has all the particulars of our current, former, and future customers. We are converting from paper to a computerized file system. Management is bent on using Excel as our Workhorse. Everyone here doesn't know how to use computers very well. So in my simplest solution I'm exporting the company names as their own folder
I solved this using,
Sub MakeFolders()
Dim xdir As String
Dim fso
Dim lstrow As Long
Dim i As Long
Set fso = CreateObject("Scripting.FileSystemObject")
lstrow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
For i = 1 To lstrow
'change the path on the next line where you want to create the folders
xdir = "E:\theFILES\" & Range("A" & i).Value
If Not fso.FolderExists(xdir) Then
fso.CreateFolder (xdir)
End If
Next
Application.ScreenUpdating = True
End Sub
*disclaimer: I found this code either on this site or another equivalent, I don't remember.
Next, I created another workbook (Company Overview Workbook) as a layout for the information from this purchased digital book (workbook) to be inputted in. There are over 5k customers and I am not going to copy and paste 20+ cells for every new workbook for each newly created folder.
This company overview workbook is needed as we have been doing business for over 40yrs and our information will have to be logged, as time progresses. Each of these newly made Company Overview Workbooks will be a log of notes.
The Question:
How can I write a VBA to go row by row selecting relevant information, inputting into the Overview Workbook (each piece of info needs to be in designated cells), Save As the Company Name.xlsm; within the corresponding folder. Then move on to the next row and repeat
Ideally, I would like to have this Overview workbook somehow linked to a master where if management needs more (or less) information I can update the formatting quick and clean. At this point, this is not that big of a deal although it will help me solve other problems down the road
I have been searching for someone else Who's solved or asked this question with no success. Any help will be much appreciated!

Related

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 from a workbook to another workbook

I am having issues developing this code. I was able to develop the code to copy new data from my workbook to an existing path but am running into issues when trying to retrieve data from the existing path work book.
The concept is that there is a workbook in my system that will be collecting data. The data comes from different users that are working on project information. Once they have completed the project this new information along with existing information gets uploaded back to the workbook collecting that data. The work book collecting the data will always have a defined path. The workbooks that users are working off of will be in multiple places across the system.
The below macro keeps failing on the "Organizer.Sheets("Partnumber_Vendor_Database").Select". I am unsure why.
"Organizer" is the local database the user will use.
"Partnumber_Vendor_File" is the local database the information is stored.
If you can see that this code could be developed better please let me know! :)
Sub Find_Partnumber_Vendor_File()
' This sub is to open the partnumber_Vendor file to update the local database.
On Error Resume Next
Dim Organizer As Workbook
Set Organizer = Application.ActiveWorkbook
Dim Partnumber_Vendor_File As Workbook
Set Partnumber_Vendor_File = Workbooks.Open("S:\Supply Chain\PURCHASING\Forms and Templates\BOM Organizer\Partnumber_Vendor_File.xlsx")
If Err.Number = 1004 Then
MsgBox "Could not open. Check path in VBA"
Exit Sub
End If
If Partnumber_Vendor_File.ReadOnly Then
MsgBox "Sorry, partnumber to vendor database was already in use, try later"
Exit Sub
End If
On Error GoTo 0
Dim Data As Long
Data = ActiveSheet.Cells(Rows.count, 1).End(xlUp).Row
Range("A1:" & "D" & Data).Copy
Organizer.Sheets("Partnumber_Vendor_Database").Select
Range("A1:D1").Select
Selection.Insert Shift:=xlDown
Partnumber_Vendor_File.Close
End Sub
Althoug it is easy to use, avoid ActiveWorkbook, ActiveSheet and Sheets(<Title of the Sheet.).
The problem with the first two is that is hard to tell if the activeworkbook is actually the workbook you are looking for, specially when there are more than 1 workbook open. To workaround this, one solution is the use the Workbooks object to select the correct work book by its NAME (property CodeName). The Same for the Sheets, change the REAL NAMES of the Sheets so you can properlly call them.
The third is basically the same principle. In general, do not use titles of Sheets as references, use the REAL NAME of the object. Use the Property window in the VBA code to change that.
The error may come from 2 situations:
1 - Your selected workbook is not the actual workbook you want to work on.
2 - The Sheet "Partnumber_Vendor_Database" had its title changed or miswritten.
Hope it helps.

Copying Data from External workbook based on headers not in order to another workbook

I hope this is the right place to ask this question as I am on the verge of going crazy. I am so rusty and I have zero experience with VBA (only with C++, java)
The problem:
I am trying to copy data from one workbook to another.
Lets say I have a workbook (called DATA) with several worksheets filled with data. Each column of data has a unique heading (all headings on the same row).
On the other hand I have another workbook (called REPORT) with one worksheet that contains only the heading of the data (in one row). They are not in the same order as in DATA workbook. For example I have 3 headings in REPORT worksheet that can be found in different worksheets in DATA workbook.
I need to loop through all the worksheets in the DATA workbook and copy paste the whole column to the REPORT worksheet when the same heading is found.
This image may help to understand. Explanation
Thanks ALOT for your help in advance. I have searched alot for this code but found similar stuff but didnt manage to understand any .
First attempt at doing it, but getting an error of Run-time error '1004'.
Any help?
Dim MyFile As String
Dim ws As Worksheet
''Workbook that contains one worksheet with all the headings ONLY NO DATA
Dim TargetWS As Worksheet
Set TargetWS = ActiveSheet
Dim TargetHeader As Range
''Location of Headers I want to search for in source file
Set TargetHeader = TargetWS.Range("A1:G")
''Source workbook that contains multiple sheets with data and headings _
not in same order as target file
Dim SourceWB As Workbook
Set SourceWB = Workbooks("Source.xlsx")
Dim SourceHeaderRow As Integer: SourceHeaderRow = 1
Dim SourceCell As Range
''Stores the col of the found value and the last row of data in that col
Dim RealLastRow As Long
Dim SourceCol As Integer
''Looping through all worksheets in source file, looking for the heading I want _
then copying that whole column to the target file I have
For Each ws In SourceWB.Sheets
ws.Activate
For Each Cell In TargetHeader
If Cell.Value <> "" Then
Set SourceCell = Rows(SourceHeaderRow).Find _
(Cell.Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not SourceCell Is Nothing Then
SourceCol = SourceCell.Column
RealLastRow = Columns(SourceCol).Find("*", LookIn:=xlValues, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
If RealLastRow > SourceHeaderRow Then
Range(Cells(SourceHeaderRow + 1, SourceCol), Cells(RealLastRow, _
SourceCol)).Copy
TargetWS.Cells(2, Cell.Column).PasteSpecial xlPasteValues
End If
End If
End If
Next
Next
Your question didn't specify what part of the problem you're actually stuck on, so I'll assume you don't know how to start. Note that nobody on here is going to provide you with the full working solution to your problem - that's upto you to figure out.
A few tips to get you to start working:
The first question you're going to ask yourself with problems involving multiple workbooks is typically going to be which workbook am i going to attach my macro to?
In your case, the REPORT Workbook looks like a saner option, since you probably want someone to be clicking on something in the report in order to generate it. You could also argue the other way around though.
Once you have chosen where to put your VBA, you have to establish a reference to the other workbook.
You either have to load the other Excel file from disk using Workbooks.Open, or have both Workbooks be open at the same time in your Excel Instance, which I'd recommend for you because it's easier. In this case simply establish the reference using the Workbooks object.
Dim exampleRefToDATA As Workbook: Set exampleRefToDATA = Workbooks("data.xlsx") ' or index
Then, cycle through each Worksheet
using something like For Each ws As WorkSheet In exampleRefToDATA.WorkSheets as your For Loop
In that Loop, loop through the first column using something like
For Each allName As Range In ws.Range(... for you to figure out ...)
In this Loop, you'll have to look if that name is in your REPORTS sheet by doing another loop like
For Each thisName As Range in Range(... seriously, there's enough on stackoverflow on how to properly iterate over the used range of a row ...)
Note how this Range() call is Equivalent to ActiveWorkbook.ActiveWorkSheet.Range, which is your Reports sheet.
Then just check for equality and copy the row over if necessary. Again, copying a row has also been covered here before.
Hope this was helpful for you.

VBA Import Data

I have a problem and I think it's complicated. It's regarding importing data/information from a another Excel file and the data/information needed is on 2 sheets.
The code is working but not the way It should be it doesn't seem to import the data and down below it will explain what we cannot do in it, ("me and my friend that are working in this project that was demand by our company don't know almost nothing about this category VBA and we are just researching info about this but get always stuck").
We need to extract from the file (the link is in the description), and the file is created every week(semana) so somehow it needs to extract the newest every week.
Down below there's the Excel file that is responsible for the extraction of the data for security reason we deleted most of the information on it and changed names.
Workbook with the Macro - Used for importing The sheet is the number 2 and also It's called Dev.Pag the macro is associated to the button "IMPORT DATA" in the same file.
Source Workbook - Contains the data This is where it gets the values(exports) from once again the name and some data was erased because It might compromise the company.
If there's anything I can edited or change please tell me. Thanks in advance for any reply.
Also will post the code down below:
Option Explicit
Sub ImportData()
Application.ScreenUpdating = False
Dim Path As String, Lstrw As Long
Dim SourceWb As Workbook
Dim TargetWb As Workbook
'Change this to your company workbook path
Path = "C:\Users\DZPH8SH\Desktop\Status 496 800 semana 12 2015.xls"
Workbooks.Open (Path)
'Change "Source" to the name of your company workbook
Set SourceWb = Workbooks("Status 496 800 semana 12 2015.xls")
'Part that needs some adjustments in down below
'This part is working good but probably some error in the data
'transferance may be intrefering with the integridty
'change the file address
Set TargetWb = Workbooks("Master_Atual_2015.xlsm")
Lstrw = SourceWb.Sheets(1).Cells.Find(What:="*", SearchOrder:=xlRows, _
SearchDirection:=xlPrevious, LookIn:=xlValues).Row
With SourceWb.Sheets(1)
.Application.Union(.Range("D2:D" & Lstrw), .Range("F2:F" & _
Lstrw), .Range("I2:I" & Lstrw), .Range("M2:M" & Lstrw)).Copy _
Destination:=TargetWb.Sheets(1).Range("A3")
End With
SourceWb.Close savechanges:=False
Application.ScreenUpdating = True
End Sub
It was pretty hard to understand your code for several reasons:
You just reference the sheets by index. Thus they are hard to find. Better reference them by name
you reference ranges only by addresses, it would be better to define named ranges
Another point to make it more readable/ debuggable, set the union to an own range object to be able to watch the content and be sure that this is what you want to have.
With SourceWb.Sheets(1)
Set objTargetRange = .Application.Union(.Range("D2:D" & Lstrw), .Range("F2:F" & Lstrw), .Range("I2:I" & Lstrw), .Range("M2:M" & Lstrw))
objTargetRange.Copy Destination:=TargetWb.Sheets(1).Range("A3")
End With
When printing out the objTargetRange's addresses it looks like this (You can do that by simply pressing ctrl+g and writing ?objTargetRange.Address)
$D$2:$D$9;$F$2:$F$9;$I$2:$I$9;$M$2:$M$9
So you selected four columns, each of them has 8 cells. When adding this to A3, it will be added side by side, it doesn't have any offset.
So cells A3-D10 will be overwritten by your data, the code works. It was not visible that it does that, because comparing state before and state after was pretty complicated. You can make visible, that the changes actually happen by just
temporary removing your actual data from the sheet
temporary adding some empty rows

Take results from one sheet and move them into many other sheets

I have looked at similar answers to this question, but whatever I do I cannot get them to do what I need.
I have a daily email which has a CSV file giving call stats for our Sales team for the previous day. What I need is to put them into Excel to give trending and historical call activity for the year. Without VBA or Macros this is a very time consuming process.
The stats it gives are number of calls, and average call length (that are of any importance) I have already got VBA to calculate the total outgoing with this:
Dim Call_Number As Integer
Dim Call_Time As Date
Dim Call_Total As Date
Call_Number = .Cells(2, 6).Value
Call_Time = .Cells(2, 7).Value
Call_Total = Call_Number * Call_Time
.Cells(12, 7).Value = Call_Total
So what I need is to take the 3 cells for each sales member, and move them into the right place in their relative sheets, which are separated by name. I also need it to move into the next cell to the right if the destination cell is full, so I'm thinking I need to start the pasting process as Jan 1st and keep moving to the right until it finds blank cells. Is there a way this can be done either in a button or automatically?
I have the first sheet used as the data import sheet, where we just import the data into csv, and because its standard formatting, every day it will give it all in the right formatting.
Code I have so far. It doesn't error, but doesn't do anything:
Sub Move_Data()
Dim Dean As Worksheet
Dim Chris As Worksheet
Dim Paul As Worksheet
Dim Nigel As Worksheet
Dim Calc As Worksheet
Dim Lastrow As Long
Dim J As Long
Dim i As Long
Set Dean = ThisWorkbook.Worksheets("DEAN 822")
Set Chris = ThisWorkbook.Worksheets("CHRIS 829")
Set Paul = ThisWorkbook.Worksheets("PAULP 830")
Set Nigel = ThisWorkbook.Worksheets("NIGEL 833")
Set RUSSELL = ThisWorkbook.Worksheets("RUSSELL 835")
Set Calc = ThisWorkbook.Worksheets("Calculation Sheet")
Lastrow = Range("C" & Dean.Columns.Count).End(xlToRight).Column
J = 2
For i = 0 To Lastrow
Set Rng = Dean.Range("C5").Offset(i, 0)
If Not (IsNull(Rng) Or IsEmpty(Rng)) Then
Calc.Cells(2, 4).Copy
Dean.Range("c" & J).PasteSpecial xlPasteValues
J = J + 1
End If
Next i
Application.CutCopyMode = False
End Sub
Instead of
Lastrow = Range("C" & Dean.Columns.Count).End(xlToRight).Column
I think you want
Lastrow = Range("C" & Dean.Columns.Count).End(xlUp).Row
"I also need ... in a button or automatically?"
LastCol = WshtName.Cells(CrntRow, Columns.Count).End(xlToLeft).Column
will set LastCol to the last used column in row CrntRow.
J = 2
For i = 0 To Lastrow
Set Rng = Dean.Range("C5").Offset(i, 0)
If Not (IsNull(Rng) Or IsEmpty(Rng)) Then
Calc.Cells(2, 4).Copy
Dean.Range("c" & J).PasteSpecial xlPasteValues
J = J + 1
End If
Next i
Application.CutCopyMode = False
I am not sure what this code is attempting.
It sets Rng to C5, C6, C7, C8, ... to Cn where n is Lastrow+5. If C5, for example, if empty it copies C2 to `Calc.Cells(2, 4).
Did you mean to copy column C from worksheet Dean to column B of worksheet Calc?
If the removal of empty cells is not important then this will be faster and clearer:
Set Rng = Dean.Range(.Cells(5 ,"C"), .Cells(Lastrow ,"C"))
Rng.Copy Destination:=Calc.Cells(2, 4)
New information in response to comment
I cannot visualise either your source data or your destination data from your description so cannot give any specific advice.
Welcome to Stack Overflow. I believe this is a good place to find previously posted information and a good place to post new questions but you must follow the site rules.
Right of centre in the top bar is the Help button. Click this and read how to use this site. Learn how to post a question that will be classified as a good question and will be answered quickly and helpfully.
I believe the biggest three problems with your question are:
You ask too much. You can ask as many good questions as you wish but there should only be one issue per question.
You ask for information that is already available.
You are too vague about your requirement to permit anyone to help. You say you want to move three values per staff member. But you do not show how either the worksheet “Calculation Sheet” or the staff member worksheets are arranged. You cannot post images until you have a higher reputation but you can use the code facility to create “drawings” of the worksheets.
To avoid asking too much, you must break your requirement into small steps. The following is my attempt to identify the necessary small steps based on my guess of what you seek.
The CSV files containing staff detail arrive as attachments to a daily email. Are you manually saving those attachment? An Outlook VBA macro to save an attachment would not be difficult to write. I suggest you leave this for later but if you search Stack Overflow for “[outlook-vba] Save attachment” you will find relevant code.
The above shows how I search Stack Overflow. I start with the tag for the language and follow it with some key words or a key phrase. Sometimes it takes me a few goes to get the right search term but I rarely fail to find something interesting
How are you importing the CSV to Excel? Are you doing this manually? There are many possible VBA approaches. Try searching for “[excel-vba] xxxx” where xxxx describes your preferred approach.
I assume the structure of the CSV file is pretty simple and there is no difficulty in find information in the individual rows. You appear to know the easiest technique for finding the last row so you should have no difficulty in creating a loop that works down the rows.
How do you relate the staff member’s name in the CSV file with the name of their worksheet? In your question you have worksheet names such as "DEAN 822", "CHRIS 829" and "PAULP 830". Are these the names used in the CSV file? What happens when a new staff member joins? I doubt this happens very often but you do not want to be amending your macro when it does happen.
I do not understand your requirement for the new data to be added to the right of any existing data. There will be three values per day so with around 200 working days per year that gives 600 columns. To me that sees an awkward arrangement. I would have thought one row per day would have been more convenient.
How will you run the macro? You mention a button or automatically. I do not like buttons since I find the tool bars cluttered enough already. I prefer to use shortcut keys such as Ctrl+q. I rarely have more than one macro per workbook of this type so that works well for me. By automatically, I assume you mean the macro will run automatically when the workbook is open. I would start with the shortcut key but when you are ready look up “Events” and “Event routines”. You will find an explanation of how you can have a macro start automatically when the workbook opens.
I hope the above is of some help.