Dynamically copy a worksheet multiple times and rename using VBA in Excel - vba

I am trying to dynamically generate a custom number of worksheets based on a template that we use regularly in excel using VBA.
I have created an "Overview" page where we can input a range which will be used to name the new worksheets but then would like to use a hidden "Master" worksheet to generate the content of these new worksheets.
My code below currently generates the correct number of pages based on the range AND copies our master template page but does not combine the two and leaves them in separate pages.
Sub test()
Dim MyNames As Range, MyNewSheet As Range
Set masterSheet = ThisWorkbook.Worksheets("Master")
Set MyNames = Range("A1:A6").CurrentRegion ' load range into variable
For Each MyNewSheet In MyNames.Cells ' loop through cell range
masterSheet.Copy ThisWorkbook.Sheets(Sheets.Count) 'copy master template sheet
Sheets.Add.Name = MyNewSheet.Value
Next MyNewSheet
MyNames.Worksheet.Select ' move selection to original sheet
End Sub
As you can see, the code generates both the named (blank) worksheets AND copies my master worksheet which defaults to naming as "Master()".

So we just need to replace this line:
Sheets.Add.Name = MyNewSheet.Value
with this line:
ActiveSheet.Name = MyNewSheet.Value

Loop through the list and copy the sheet if the sheet does not already exist.
Sub CopyMaster()
Dim ws As Worksheet, sh As Worksheet
Dim Rws As Long, rng As Range, c As Range
Set sh = Sheets("Overview")
Set ws = Sheets("Master")
With sh
Rws = .Cells(Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(Rws, 1))
End With
For Each c In rng.Cells
If WorksheetExists(c.Value) Then
MsgBox "Sheet " & c & " exists"
Else:
ws.Copy After:=Worksheets(Worksheets.Count)
Worksheets(Worksheets.Count).Name = c.Value
End If
Next c
End Sub
Function WorksheetExists(WSName As String) As Boolean
On Error Resume Next
WorksheetExists = Worksheets(WSName).Name = WSName
On Error GoTo 0
End Function

Related

Macro to copy first two columns from all sheets to a master sheet is skipping sheets

I'm using this macro to copy columns A and B from all of my sheets into a new sheet named Master. What I notice is that entire sheets worth of information are missing in the master sheet and I can't figure out why. The format for my sheets is column A has a string of characters that follow this structure: M2,004,005,004,007,17,096,01:07:45,45 and column B is just a date such as 4/19/2017.
I have hundreds of these sheets in my workbook and each has 224 rows that I need to copy into a single master sheet. Could anyone help me figure out how to get this code to stop skipping sheets?
Thanks.
Sub CreateMaster()
Dim J As Integer
On Error Resume Next
Sheets(1).Select
Worksheets.Add
Sheets(1).Name = "Master"
Sheets(2).Activate
Range("A1:B1").EntireRow.Select
Selection.Copy Destination:=Sheets(1).Range("A1:B1")
For J = 2 To Sheets.Count
Sheets(J).Activate
Range("A1:B1").Select
Selection.CurrentRegion.Select
Selection.Copy Destination:=Sheets(1).Range("A65536:B65536").End(xlUp)(2)
Next
End Sub
while searching for solutions online, I came across this macro that seems to do the same thing, but also seems to skip the exact same sheets as my macro does.
Sub CopyFromWorksheets()
Dim wrk As Workbook 'Workbook object - Always good to work with object
variables
Dim sht As Worksheet 'Object for handling worksheets in loop
Dim trg As Worksheet 'Master Worksheet
Dim rng As Range 'Range object
Dim colCount As Integer 'Column count in tables in the worksheets
Set wrk = ActiveWorkbook 'Working in active workbook
For Each sht In wrk.Worksheets
If sht.Name = "Master" Then
MsgBox "There is a worksheet called as 'Master'." & vbCrLf & _
"Please remove or rename this worksheet since 'Master' would be" & _
"the name of the result worksheet of this process.", vbOKOnly + vbExclamation, "Error"
Exit Sub
End If
Next sht
'We don't want screen updating
Application.ScreenUpdating = False
'Add new worksheet as the last worksheet
Set trg = wrk.Worksheets.Add(After:=wrk.Worksheets(wrk.Worksheets.Count))
'Rename the new worksheet
trg.Name = "Master"
'Get column headers from the first worksheet
'Column count first
Set sht = wrk.Worksheets(1)
colCount = sht.Cells(1, 255).End(xlToLeft).Column
'Now retrieve headers, no copy&paste needed
With trg.Cells(1, 1).Resize(1, colCount)
.Value = sht.Cells(1, 1).Resize(1, colCount).Value
'Set font as bold
.Font.Bold = True
End With
'We can start loop
For Each sht In wrk.Worksheets
'If worksheet in loop is the last one, stop execution (it is Master worksheet)
If sht.Index = wrk.Worksheets.Count Then
Exit For
End If
'Data range in worksheet - starts from second row as first rows are the header rows in all worksheets
Set rng = sht.Range(sht.Cells(2, 1), sht.Cells(65536, 1).End(xlUp).Resize(, colCount))
'Put data into the Master worksheet
trg.Cells(65536, 1).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Value = rng.Value
Next sht
'Fit the columns in Master worksheet
trg.Columns.AutoFit
'Screen updating should be activated
Application.ScreenUpdating = True
End Sub
as a workaround, since only the most recent data is immediately pertinent, I worked around it, but deleting the first 150 sheets. that still left around 100 sheets for my macro to work on, but now the missing pieces of data seem to be there. I wonder if there's something about the quantity of sheets that is causing this to malfunction?
Comments may not get it across correctly. Restructure your loop (and add the variables mentioned).
Dim x as Long
Dim thisSht as Worksheet
For x = 1 to wrk.Worksheets.Count
set thisSht = wrk.Worksheets(x)
'Data range in worksheet - starts from second row as first rows are the header rows in all worksheets
Set rng = thisSht.Range(sht.Cells(2, 1), sht.Cells(65536, 1).End(xlUp).Resize(, colCount))
'Put data into the Master worksheet
trg.Cells(65536, 1).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Value = rng.Value
Next x

copy cells but not replace them

im stuck at a vba problem.
i want to copy some cells from worksheet to another
first i go through all worksheets begin with "IT*"
For Each ws In wb.Worksheets
If ws.Name Like "IT*" Then
ws.Select
Call transfer
End If
Next ws
then call transfer
Sub transferAP()
'
' transferAP Makro
'
Dim strSheetName As String
strSheetName = ActiveSheet.Name
Sheets(strSheetName).Select
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A3")
Worksheets(strSheetName).Range("E9").Copy Worksheets("Berechnung_Personal").Range("B3")
Worksheets(strSheetName).Range("G9").Copy Worksheets("Berechnung_Personal").Range("C3")
Worksheets(strSheetName).Range("G11").Copy Worksheets("Berechnung_Personal").Range("D3")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A4")
Worksheets(strSheetName).Range("E24").Copy Worksheets("Berechnung_Personal").Range("B4")
Worksheets(strSheetName).Range("G24").Copy Worksheets("Berechnung_Personal").Range("C4")
Worksheets(strSheetName).Range("G26").Copy Worksheets("Berechnung_Personal").Range("D4")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A5")
Worksheets(strSheetName).Range("E39").Copy Worksheets("Berechnung_Personal").Range("B5")
Worksheets(strSheetName).Range("G39").Copy Worksheets("Berechnung_Personal").Range("C5")
Worksheets(strSheetName).Range("G41").Copy Worksheets("Berechnung_Personal").Range("D5")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A6")
Worksheets(strSheetName).Range("M3").Copy Worksheets("Berechnung_Personal").Range("B6")
Worksheets(strSheetName).Range("O3").Copy Worksheets("Berechnung_Personal").Range("C6")
Worksheets(strSheetName).Range("O5").Copy Worksheets("Berechnung_Personal").Range("D6")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A7")
Worksheets(strSheetName).Range("M18").Copy Worksheets("Berechnung_Personal").Range("B7")
Worksheets(strSheetName).Range("O18").Copy Worksheets("Berechnung_Personal").Range("C7")
Worksheets(strSheetName).Range("O20").Copy Worksheets("Berechnung_Personal").Range("D7")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A8")
Worksheets(strSheetName).Range("M33").Copy Worksheets("Berechnung_Personal").Range("B8")
Worksheets(strSheetName).Range("O33").Copy Worksheets("Berechnung_Personal").Range("C8")
Worksheets(strSheetName).Range("O35").Copy Worksheets("Berechnung_Personal").Range("D8")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A9")
Worksheets(strSheetName).Range("U3").Copy Worksheets("Berechnung_Personal").Range("B9")
Worksheets(strSheetName).Range("W3").Copy Worksheets("Berechnung_Personal").Range("C9")
Worksheets(strSheetName).Range("W5").Copy Worksheets("Berechnung_Personal").Range("D9")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A10")
Worksheets(strSheetName).Range("U18").Copy Worksheets("Berechnung_Personal").Range("B10")
Worksheets(strSheetName).Range("W18").Copy Worksheets("Berechnung_Personal").Range("C10")
Worksheets(strSheetName).Range("W20").Copy Worksheets("Berechnung_Personal").Range("D10")
Worksheets(strSheetName).Range("C3").Copy Worksheets("Berechnung_Personal").Range("A11")
Worksheets(strSheetName).Range("U33").Copy Worksheets("Berechnung_Personal").Range("B11")
Worksheets(strSheetName).Range("W33").Copy Worksheets("Berechnung_Personal").Range("C11")
Worksheets(strSheetName).Range("W35").Copy Worksheets("Berechnung_Personal").Range("D11")
It runs at all, but if there is another worksheet ( and there is another) named "IT*" it will replace the copied files cause of the non relative output cell destination.
I want to continue with the new worksheet data at the end of the last copied data.
Hope you get what im trying to explain.
I propose you the following refactoring of your code
Sub transferAP(sourceSht As Worksheet)
With Worksheets("Berechnung_Personal") '<--| reference target sheet
With .Cells(.Rows.Count, 1).End(xlUp).Offset(1) '<--| reference its column A first empty cell after last not empty one)
sourceSht.Range("C3").Copy .Cells(1,1)
sourceSht.Range("E9").Copy .Cells(2,1)
sourceSht.Range("G9").Copy .Cells(3,1)
.... and so on: keep in mind that .Cells(1,1) syntax assumes the referenced range as the starting cell
End With
End With
End Sub
And your main sub will call it as follows:
transferAP ws
This is your new Main sub. It is basically unchanged from your earlier code, but I have specified Wb to be ThisWorkbook. You may like to specify another.
Sub Main()
Dim Wb As Workbook
Dim Ws As Worksheet
Dim R As Long
Set Wb = ThisWorkbook
For Each Ws In Wb.Worksheets
If Ws.Name Like "IT*" Then
TransferAP Ws, R ' pass the Ws to the sub
End If
Next Ws
End Sub
In your TransferAP I have also specified ThisWorkbook as the workbook where the target worksheet "Berechnung_Personal" is found. Excel presumes the ActiveWorkbook if no specification is made. Note that ThisWorkbook needs not be the ActiveWorkbook. ThisWorkbook is the Workbook that contains the code. The ActiveWorkbook is the last workbook you looked at before switching to the VBE window or the workbook you activated using code thereafter.
Sub TransferAP(Ws As Worksheet, R As Long)
' 21 Mar 2017
Dim WsTarget As Worksheet
Dim Sources() As String ' List of source cells
Dim i As Integer ' index for Sources
Set WsTarget = ThisWorkbook.Worksheets("Berechnung_Personal")
If R = 0 Then R = 3 ' row 3 is the first row to use
Sources = Split("E9,E24,E39,M3,M18,M33,U3,U18,U33", ",")
For i = 0 To UBound(Sources)
With WsTarget
.Cells(R, 1).Value = Ws.Range("C3").Value
.Cells(R, 2).Value = Ws.Range(Sources(i)).Value
.Cells(R, 3).Value = Ws.Range(Sources(i)).Offset(0, 2).Value
.Cells(R, 4).Value = Ws.Range(Sources(i)).Offset(2, 2).Value
End With
R = R + 1
Next i
End Sub
The TransferAP returns the final value of R to the Main. So, when the next source worksheet is found R will continue counting from where it left off - I hope. I didn't test the loop.

Excel VBA - Copy Sheet to new workbook X times

I need to copy the same worksheet X times (x = sheet2 row A) into a new workbook.
For each copy I need to:
1.Change a drop down to display the next value
2.Do a Refresh (Workbook is connected to a database which pulls different information based on the value of the drop down and is not automatically refreshed)
3.Copy just the values (no formulas)
Rename the sheet to the value of the drop down.
Save all of the copied worksheets into 1 workbook
My code (below) which is called on a button press currently saves the sheet X times based on sheet2 rowA (as intended).
It is missing steps 1,2,4 and 5
The code I have at the moment (called on button click)
Dim x As Integer '~~>Loop counter
Dim WS As Worksheet
Dim LastCellA As Range, LastCellB As Range
Dim LastCellRowNumber As Long
Set WS = Worksheets("Sheet2") '~~>Sheet with names
With WS
Set LastCellA = .Cells(.Rows.Count, "A").End(xlUp) '~~>Column with names.
'~~>This needs to be changed to find the range as data may not start at A1
x = Application.WorksheetFunction.Max(LastCellA.Row)
End With
For numtimes = 1 To x
ActiveWorkbook.Sheets("Sheet1").Copy _
After:=ActiveWorkbook.Sheets(Worksheets.Count)
'~~>Copy values only
ActiveSheet.UsedRange.Value = ActiveSheet.UsedRange.Value
Next
Still... I'm not sure of the point that you "Import" different values based on a drop down. That may be a different macro for loding the data. Then you need to call that macro instead of the .RefreshAll.
Sub test()
Dim uRow As Long, lRow As Long, i As Long
Dim wb As Workbook, ws As Object
With ThisWorkbook
Set ws = .Sheets("Sheet2")
With ws
uRow = .Cells(.Rows.Count, "A").End(xlUp).End(xlUp).Row
lRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Set wb = Workbooks.Add
For i = uRow To lRow
.Sheets("Sheet1").Range("M1").Value = ws.Cells(i, 1).Value '<~~~ this should change the dropdown
Calculate
.RefreshAll
.Sheets("Sheet1").Copy , wb.Sheets(wb.Sheets.Count)
wb.Sheets(wb.Sheets.Count).Name = ws.Cells(i, 1).Value
Next
Application.DisplayAlerts = False
wb.Sheets(1).Delete
Application.DisplayAlerts = True
For Each ws In wb.Sheets
ws.UsedRange.Value = ws.UsedRange.Value
Next
End With
End Sub
EDIT:
If you get trouble with the Sheet2 Column A List (cus it contains empty cells resulting of formulas) you may try a different approach:
Sub test()
Dim wb As Workbook, ws As Worksheet
Dim xVal As Variant
With ThisWorkbook
Set ws = .Sheets("Sheet2")
Set wb = Workbooks.Add
For Each xVal In Intersect(ws.Range("A:A"), ws.UsedRange).Value
If Len(xVal) Then
.Sheets("Sheet1").Range("M1").Value = xVal
Calculate
.RefreshAll
.Sheets("Sheet1").Copy , wb.Sheets(wb.Sheets.Count)
wb.Sheets(wb.Sheets.Count).Name = ws.Cells(i, 1).Value
wb.Sheets(wb.Sheets.Count).UsedRange.Value = wb.Sheets(wb.Sheets.Count).UsedRange.Value
End If
Next
Application.DisplayAlerts = False
wb.Sheets(1).Delete
Application.DisplayAlerts = True
End With
End Sub
Based on the code you provided, I believe this is what you are looking for.
It will loop through your list, copy sheet1 to the new workbook and name the sheet.
I am not sure what you want with looping through your dropdown list.
Sub Button1_Click()
Dim wb As Workbook, Bk As Workbook
Dim WS As Worksheet, sh As Worksheet
Dim LastCellA As Long, LastCellB As Range, c As Range
Dim LastCellRowNumber As Long
Dim x As Integer '~~>Loop counter
Set wb = ThisWorkbook
Set WS = wb.Worksheets("Sheet2") '~~>Sheet with names
Set sh = wb.Sheets("Sheet1")
With WS
LastCellA = .Cells(.Rows.Count, "A").End(xlUp).Row '~~>Column with names.
'~~>This needs to be changed to find the range as data may not start at A1
Set LastCellB = .Range("A1:A" & LastCellA).SpecialCells(xlCellTypeConstants, 23)
End With
Set Bk = Workbooks.Add
For Each c In LastCellB.Cells
sh.Range("M1") = c
sh.Copy After:=Bk.Sheets(Worksheets.Count)
With ActiveSheet
'~~>Copy values only
.UsedRange.Value = .UsedRange.Value
.Name = c
End With
Next c
End Sub

VBA copy entire row of List

I have the following code:
Sub test()
Dim r As Range, rng As Range
Set r = Range("a6", Range("a6").End(xlDown))
For Each rng In r
If rng <> rng.Offset(-1) Then 'if range is not
Dim ws As Worksheet
Set ws = Worksheets.Add
ws.Name = rng
Else
End If
Next rng
End Sub
This would go through the range in A6 to AXX and create a worksheets for different names. I somehow can't figure out however how to copy the content of every row into every worksheet created.
So I want all the Ticker changes being copied into the new created worksheet ticker changes.
I know there is some way with the following:
Range(Cells(rng, 1), Cells(rng, 10)).Copy
But I don't know how to paste those to different worksheet.
Can someone please advice or guide. Thanks
Also when I try to run this macro it sometimes says:
That name is already taken try a different one.
However there is no worksheet with that name.
You only need to reference/specify the sheet that you want to use.
Try this (I included an inputbox to correct the name of the sheet if it is already taken :
Sub test_Nant()
Dim r As Range, rng As Range, ws As Worksheet, aWs As Worksheet
Set aWs = ActiveSheet
Set ws = Worksheets.Add
On Error GoTo SheetRename
ws.Name = "Changes list"
GoTo KeepLooping
SheetRename:
ws.Name = InputBox("Choose another name for that sheet : ", , rng.Value)
Resume Next
KeepLooping:
With aWs
Set r = .Range(.Range("a6"), .Range("a6").End(xlDown))
For Each rng In r
If rng <> rng.Offset(-1) Then 'if range is not
.Range(.Cells(rng.Row, 1), .Cells(rng.Row, 10)).Copy Destination:=ws.Range("A1")
Else
End If
Next rng
End With
End Sub

AdvancedFilter CopyToRange:= First empty row

I am trying to use AdvancedFilter in VBA, but instead of setting copy to range to a fixed value I want to copy it to the first empty row.
I am trying to append two tables from two separate AdvancedFilter steps, is there an easier way? E.g. first copy the two tables to separate location and then merge them? Both table have the same columns.
My code as of now is:
Set rngCriteria_v = Sheets("1").Range("filter")
Set rngExtract_v = Sheets("2").Range("**Here first empty row**")
Set rngData_v = Sheets("3").Range("Input")
rngData_v.AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=rngCriteria_v, _
CopyToRange:=Sheets("Stocks_5_control").Columns("AG").Find(vbNullString, Cells(Rows.Count, "AG")), _
Unique:=False
Change your advanced filter line to this:
rngData_v.AdvancedFilter xlFilterCopy, rngCriteria_v, Sheets("Stocks_5_control").Cells(Sheets("Stocks_5_control").Rows.Count, "AG").End(xlUp)(2)
The following merges the all the worksheets in to a new sheet called Master. Hope that helps :)
Dim wrk As Workbook 'Workbook object - Always good to work with object variables
Dim sht As Worksheet 'Object for handling worksheets in loop
Dim trg As Worksheet 'Master Worksheet
Dim rng As Range 'Range object
Dim colCount As Integer 'Column count in tables in the worksheets
Dim wd As Object 'used for word document
Dim WDoc As Object
Dim strWorkbookName As String
Set wrk = ActiveWorkbook 'Working in active workbook
For Each sht In wrk.Worksheets
If sht.Name = "Master" Then
MsgBox "There is a worksheet called as 'Master'." & vbCrLf & _
"Please remove or rename this worksheet since 'Master' would be" & _
"the name of the result worksheet of this process.", vbOKOnly + vbExclamation, "Error"
Exit Sub
End If
Next sht
'Add new worksheet as the last worksheet
Set trg = wrk.Worksheets.Add(After:=wrk.Worksheets(wrk.Worksheets.Count))
'Rename the new worksheet
trg.Name = "Master"
'Get column headers from the first worksheet
'Column count first
Set sht = wrk.Worksheets(1)
colCount = sht.Cells(1, 255).End(xlToLeft).Column
'Now retrieve headers, no copy&paste needed
With trg.Cells(1, 1).Resize(1, colCount)
.Value = sht.Cells(1, 1).Resize(1, colCount).Value
'Set font as bold
.Font.Bold = True
End With
'We can start loop
For Each sht In wrk.Worksheets
'If worksheet in loop is the last one, stop execution (it is Master worksheet)
If sht.Index = wrk.Worksheets.Count Then
Exit For
End If
'Data range in worksheet - starts from second row as first rows are the header rows in all worksheets
Set rng = sht.Range(sht.Cells(2, 1), sht.Cells(65536, 1).End(xlUp).Resize(, colCount))
'Put data into the Master worksheet
trg.Cells(65536, 1).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Value = rng.Value
Next sht
'Fit the columns in Master worksheet
trg.Columns.AutoFit