I have a worksheet that contains multiple tabs that identify different sources of data. I need to combine all the worksheets into one and add a column with the worksheet name as part of the new combined sheet.
I found the following code and if I cut/paste into my worksheet it works like a charm BUT I have several of these workbooks and I have to be able to recreate this process monthly.
My research indicates that I should create a com add in or recallable macro to do this but each time I have tried, the process fails. I would very much appreciate if somone could point me with the steps to do this in Excel (2013) and advise me if my code will work.
Thanks in advance.
Sub Combine()
Dim J As Integer, wsNew As Worksheet
Dim rngCopy As Range, rngPaste As Range
Dim Location As String
On Error Resume Next
Set wsNew = Sheets("Combined")
On Error GoTo 0
'if sheet does not already exist, create it
If wsNew Is Nothing Then
Set wsNew = Worksheets.Add(before:=Sheets(1)) ' add a sheet in first place
wsNew.Name = "Combined"
End If
'copy headings and paste to new sheet starting in B1
With Sheets(2)
Range(.Range("A1"), .Cells(1, Columns.Count).End(xlToLeft)).Copy wsNew.Range("B1")
End With
' work through sheets
For J = 2 To Sheets.Count ' from sheet 2 to last sheet
'save sheet name/location to string
Location = Sheets(J).Name
'set range to be copied
With Sheets(J).Range("A1").CurrentRegion
Set rngCopy = .Offset(1, 0).Resize(.Rows.Count - 1)
End With
'set range to paste to, beginning with column B
Set rngPaste = wsNew.Cells(Rows.Count, 2).End(xlUp).Offset(2, 0)
'copy range and paste to column *B* of combined sheet
rngCopy.Copy rngPaste
'enter the location name in column A for all copied entries
Range(rngPaste, rngPaste.End(xlDown)).Offset(0, -1) = Location
Next J
End Sub
You can add this code into your Personal Macro Workbook, and modify it so it acts on the ActiveWorkbook. That way, when you run it, it will operate on whichever workbook is selected in Excel.
Also worth qualifying all your sheet references with a workbook object reference. When you use (e.g.):
Sheets("Combined")
then by default it will refer to the ActiveWorkbook. Usually this is what you want (though it may not be), but working this way can cause problems if (for example) you open/activate a different workbook in your code, and that other workbook is now the target of your Sheets(....) reference. You resolve this by always being explicit about which workbook you're referring to: for example -
ThisworkBook.Sheets() 'the workbook containing the running code
ActiveWorkbook.Sheets() 'the selected workbook
Workbooks("test.xlsx").Sheets() 'named workbook
wb.Sheets() 'use a variable set to a workbook object
So, modifying your existing code:
Sub Combine()
Dim wb As Workbook
Dim J As Integer, wsNew As Worksheet
Dim rngCopy As Range, rngPaste As Range
Dim Location As String
Set wb = ActiveWorkbook
On Error Resume Next
Set wsNew = wb.Sheets("Combined")
On Error GoTo 0
'if sheet does not already exist, create it
If wsNew Is Nothing Then
Set wsNew = wb.Worksheets.Add(before:=wb.Sheets(1)) ' add a sheet in first place
wsNew.Name = "Combined"
End If
'copy headings and paste to new sheet starting in B1
With wb.Sheets(2)
.Range(.Range("A1"), .Cells(1, Columns.Count) _
.End(xlToLeft)).Copy wsNew.Range("B1")
End With
' work through sheets
For J = 2 To wb.Sheets.Count ' from sheet 2 to last sheet
'save sheet name/location to string
Location = wb.Sheets(J).Name
'set range to be copied
With wb.Sheets(J).Range("A1").CurrentRegion
Set rngCopy = .Offset(1, 0).Resize(.Rows.Count - 1)
End With
'set range to paste to, beginning with column B
Set rngPaste = wsNew.Cells(Rows.Count, 2).End(xlUp).Offset(2, 0)
'copy range and paste to column *B* of combined sheet
rngCopy.Copy rngPaste
'enter the location name in column A for all copied entries
wsNew.Range(rngPaste, rngPaste.End(xlDown)).Offset(0, -1) = Location
Next J
End Sub
Related
Hi I am trying to select named sheets with a variable issue level the variable comes from a cell in each sheet.
Currently I have 5 sheets (could be any number) which all have the same name and issue level but are sheet numbered 1 to 5. The code should look for sheets with the sheet name and the current issue level which is taken from a cell in each sheet, then copy and rename with the next issue number. The new name and page number and issue level for the copy sheet all come from another cell in each sheet.
I have written the following code and tried a number of variations with varying levels of success but at the moment it is not doing anything! I think the way I am defining the name the sheets to look for is failing?
Sub UpIssueAllGRnR()
'Start loop to find named sheets
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
'Define name for sheets to be duplicated (name start and current issue number)
If Left(ws.Name, 20) = "Gauge RnR Att Iss " & Cells(4, 16) Then
'Copy active sheet
ActiveSheet.Copy After:=Sheets(ActiveSheet.Index)
'Rename new sheet from defined cell (Same name and sheet number but with new issue level)
Dim NewNamex As String
NewNamex = ActiveSheet.Range("P14").Value
ActiveSheet.Name = NewNamex
End If
'Go to next defined sheet name
Next ws
End Sub
Any help would be greatly appreciated
Be careful: you are mixing implicit and explicit referencing of cells and worksheets.
I updated the code - but w/o test:
Sub UpIssueAllGRnR()
'Start loop to find named sheets
Dim ws As Worksheet, wsNew as worksheet
Dim NewNamex As String
For Each ws In ThisWorkbook.Worksheets
'-->> ws won't get activated!!!
'Define name for sheets to be duplicated (name start and current issue number)
'-->> use ws wherever you reference cells from that sheet
If Left(ws.Name, 20) = "Gauge RnR Att Iss " & ws.Cells(4, 16) Then
'Copy sheet = ws
ws.Copy After:= ws
set wsNew = activeSheet
'Rename new sheet from defined cell (Same name and sheet number but with new issue level)
NewNamex = ws.Range("P14").Value
wsNew.Name = NewNamex
End If
'Go to next defined sheet name
Next ws
End Sub
The below code is tested and seems to be working in the environment I set up.
Sub UpIssueAllGRnR()
Dim ws As Worksheet
Dim currIndex As Integer
For Each ws In ThisWorkbook.Worksheets
'Define name for sheets to be duplicated (name start and current issue number)
If Left(ws.Name, 20) = "Gauge RnR Att Iss " & Format(ws.Cells(4, 16).Value, "00") Then
currIndex = ws.Index
'Copy active sheet
ws.Copy After:=ThisWorkbook.Sheets(currIndex)
'Rename new sheet from defined cell (Same name and sheet number but with new issue level)
Dim NewNamex As String
NewNamex = ActiveSheet.Range("P14").Value
ThisWorkbook.Sheets(currIndex + 1).Name = NewNamex
End If
Next ws
End Sub
I haven't tested this code however I fixed a couple mistakes you made. Try using as much explicit code as you can. I also suggest that you use .Text instead of .Value to be sure to get a string.
Sub UpIssueAllGRnR()
'Start loop to find named sheets
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
'Define name for sheets to be duplicated (name start and current issue number)
If Left(ws.Name, 20) = "Gauge RnR Att Iss " & ws.Cells(4, 16).Text Then
'Copy active sheet
ws.Copy After:=Sheets(ws.Index)
'Rename new sheet from defined cell (Same name and sheet number but with new issue level)
ActiveSheet.Name = ActiveSheet.Name & ActiveSheet.Range("P14").Text
End If
'Go to next defined sheet name
Next ws
End Sub
In a masterfile I have the worksheet XXXX, which the range C2:C3 contains the names of two tables. I store those names in the array tba which is a variant variable.
Private Sub ORSA_REPORT_Click()
Dim rng As Range
Dim rng2 As Range
Dim SummaryWb As Workbook
Dim tba As Variant
Dim ws As Worksheet
Set SummaryWb = Workbooks.Open("I:\XXX\XXXXX.xlsx") ' <--- I open this workbook
' which contains the tables
' I need to copy
ThisWorkbook.Activate
tba = Worksheets("XXX").Range("C2:C3") ' <--- Please see below a screenshot
' with the names
SummaryWb.Activate
For i = 1 To 2
Set rng = Range(tba(i, 1)) ' <--- in the tba are names which i take them from
' the masterworkbook but i want to use them
' in the workbook whichg contains the tables
rng.Copy
SummaryWb.Worksheets("New").Cells(i, 1).PasteSpecial xlPasteAll
Next i
I want to activate the SummaryWb and use the names from the tba in the SummaryWb to define the rng which is a range variable.
I made an extensive research but I could not figure it out.
Example:
The first name range which is in the masterworkbook is Name1
The second name range which is in the masterworkbook is Name2
--> Please note that only the names are in that file.
Next the actual range is in the other workbook. For example:
In workbook2 I have the A1:B5 named as Name1 and C1:D5 named as Name2.
I store the two names from the workbook1 in an array, the tba.
I want to set the rng to be equal with the ranges represented by the entries of the tba.
Don't use .Activate instead specify workbook and worksheet for every range object. If you do that it is clear what happens.
Private Sub ORSA_REPORT_Click()
Dim SummaryWb As Workbook
Set SummaryWb = Workbooks.Open("I:\XXX\XXXXX.xlsx")
Dim tba As Variant
tba = ThisWorkbook.Worksheets("XXX").Range("C2:C3").Value
'eg tba is then:
'tba(1, 1) = "Name1"
'tba(2, 1) = "Name2"
For i = 1 To 2
Dim rng As Range
Set rng = Workbooks("Workbook2").Worksheets("SheetName").Range(tba(i, 1))
rng.Copy
SummaryWb.Worksheets("New").Cells(i, 1).PasteSpecial xlPasteAll
Next i
End Sub
So make sure for every Range object that you specify which workbook/worksheet it is in. If it is in the workbook the VBA code is in then you can use ThisWorkbook instead of Workbooks("NameOfWorkbook").
Note that if you use Set rng = Workbooks("Workbook2").Worksheets("SheetName").Range(tba(i, 1)) then the named ranges Name1 and Name2 must exist in worksheet SheetName of Workbook2.
I have the code below that works really well.
It copies the active worksheet and creates a new sheet with name based on a specific cell.
Can I modify this to not include formulas when copied? I only want Values and Formatting, so the new sheet is a static snapshot.
Sub Copyrenameworksheet()
Dim ws As Worksheet
Set wh = Worksheets(ActiveSheet.Name)
ActiveSheet.Copy After:=Worksheets(ActiveSheet.Name)
If wh.Range("C2").Value <> "" Then
ActiveSheet.Name = wh.Range("C2").Value
End If
wh.Activate
End Sub
How about the following as a general method to make a static copy of a worksheet:
Dim sht1 As Worksheet 'worksheet to copy from
Dim sht2 As Worksheet 'worksheet to paste to
Set sht1 = ThisWorkbook.Worksheets("Name of the Worksheet to copy from")
sht1.Cells.Copy 'Copy everything in the worksheet
Set sht2 = ThisWorkbook.Worksheets.Add 'create new blank worksheet
sht2.Cells.PasteSpecial xlPasteValues 'first paste values
sht2.Cells.PasteSpecial xlPasteFormats ' then paste formats
sht2.Name="Something" 'give a name to your new worksheet
Also please avoid using ActiveSheet and use explicit references to your worksheets instead.
I modified your code slightly to use variables for your original sheet and your copied sheet. I use .Value2 = .Value2 to remove formulas. Note that this will run into an error if you try to create multiple sheets using the same name in C2.
Sub Copyrenameworksheet()
Dim wsOrig As Worksheet, wsNew As Worksheet
Set wsOrig = Worksheets(ActiveSheet.Name)
wsOrig.Copy , wsOrig
Set wsNew = Worksheets(wsOrig.Index + 1)
If wsOrig.Range("C2").Value <> "" Then
wsNew.Name = wsOrig.Range("C2").Value
End If
wsNew.UsedRange.Value2 = wsNew.UsedRange.Value2
wsOrig.Activate
End Sub
I need help to create an automatic method to copy a row to a specific sheet.
I have a Tab (Sales) with a WEB api query importing data in this sheet every 5 min. I have a row within the Sales sheet with a name range identifying each item. The row has 100 different names and there are 100 sheets created with same names within the workbook.
I want to copy the entire row for each item and copy it to the sheet with the same name of the item.
This is to fire off the copy sub:
'Copy Sales data Every 10 Min
Sub test()
'Application.OnTime Now + TimeValue("00:10:00"), "my_Procedure…"
End Sub
I have seen many methods on how to copy the row automatically, but I need help in copy row and use the item name and paste to other sheet with same name.
Without further information here is an outline of what i described in the comments. Here the list of named ranges starts at cell J3 in NamesSheet. In the image, i have shown it in the same sheet (SourceSheet for simplicity). The list is read into an array and that array is looped to select the appropriate sheet to set the values in.
Rather than copy and paste it sets the target row (the next available row), in the sheet accessed by the array index, equal to the source row (copyRow). A With statement is used to avoid selecting the target sheet (more efficient).
No error handling added for missing sheets at present.
I haven't assumed there will be a list of 100 named ranges in the sheet, otherwise you could have sized the array from the start.
Named ranges in ColA of Sales tab:
List of named ranges in Names sheet (abbreviated)
Option Explicit
Private Sub myProc()
Dim wb As Workbook
Dim wsSource As Worksheet
Dim wsNames As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Sales")
Set wsNames = wb.Worksheets("Names")
Dim namesArr()
namesArr = wsNames.Range("J3:J" & wsNames.Cells(wsNames.Rows.Count, "J").End(xlUp).Row).Value
If UBound(namesArr, 1) <> wsSource.Range("ITEMName").Rows.Count Then
MsgBox "There are not a matching number of named ranges listed in Names sheet."
Exit Sub
End If
Dim i As Long
Dim currLastRow As Long
'Any optimization code could actually go in outer calling sub but consider
'some such as the following
Application.ScreenUpdating = False
Dim copyRow As Range
For i = LBound(namesArr, 1) To UBound(namesArr, 1)
With wb.Worksheets(namesArr(i, 1))
Set copyRow = wsSource.Range(namesArr(i, 1)).EntireRow
If IsEmpty(.Range("A1")) Then 'First row in sheet is available
.Rows(1).Value = copyRow.Value2
Else
currLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Rows(currLastRow + 1).Value = copyRow.Value2
End If
End With
Next i
Application.ScreenUpdating = True
End Sub
Version 2:
Looping Named Ranges in Sales sheet (assumes only 101 Named Ranges in the sheet, tested with workbook scope, and that you will ignore 1 of these which is called ITEMName, no list required in a different sheet. Approach adapted from #user1274820.
Option Explicit
Private Sub myProc2()
Dim wb As Workbook
Dim wsSource As Worksheet
Set wb = ThisWorkbook
Set wsSource = wb.Worksheets("Sales")
Dim currLastRow As Long
'Any optimization code could actually go in outer calling sub but consider
'some such as the following
Application.ScreenUpdating = False
Dim copyRow As Range
Dim nm As Variant
For Each nm In ThisWorkbook.Names
If nm.RefersToRange.Parent.Name = "Sales" And nm.Name <> "ITEMName" Then
With wb.Worksheets(nm.Name)
Set copyRow = wsSource.Range(nm.Name).EntireRow
If IsEmpty(.Range("A1")) Then 'First row in sheet is available
.Rows(1).Value = copyRow.Value2
Else
currLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Rows(currLastRow + 1).Value = copyRow.Value2
End If
End With
End If
Next nm
Application.ScreenUpdating = True
End Sub
I have a workbook with about 63 sheets. I'd like to take all filtered data (filtered by a macro) from all worksheets and paste them into a separate worksheet.
Worksheets DON'T have the same data range. They all would start on Column A Row 15 IF there is any data there at all. The filter macro filters for specific values in one of the columns hence the differentiation between rows in each sheet.
I need to copy all filtered data starting with a Range of A15 and the last row in the range would be AI. It's just a matter of how many rows if there are any rows to get the number for the AI in the range to copy over.
I got it to copy an entire sheet, not the filtered data, to another sheet but it only copied sheet 1.
Sub rangeToNew_Try2()
Dim newBook As Excel.Workbook
Dim rng As Excel.Range
Set newBook = Workbooks.Add
Set rng = ThisWorkbook.Worksheets("Sheet1").Cells.SpecialCells(xlCellTypeVisible)
rng.Copy newBook.Worksheets("Sheet1").Range("A1")
End Sub
You can use Worksheet.UsedRange to give you just the Range with data in, then you could apply your Range.SpecialsCells to give you just the filtered data.
To help debug your code, set a breakpoint and use the Immediate Window to see what the range is, i.e.:
?rng.Address
(The question mark prints out whatever follows.)
This function should do what you need:
Sub CopyFilteredDataToNewWorkbook()
Dim newBook As Excel.Workbook
Dim rng As Excel.Range
Dim sht As Excel.Worksheet
Dim rowoffsetcount As Long
Dim newsht As Excel.Worksheet
Set newBook = Workbooks.Add
' ThisWorkbook.Worksheets is the same as the Sheets or Worksheets object, but more explicit
For Each sht In ThisWorkbook.Worksheets
' Get the used rows and columns
Set rng = sht.UsedRange
' Offset the range so it starts at row 15
rowoffsetcount = 15 - rng.Row
Set rng = rng.Offset(rowoffsetcount)
' Check there will be something to copy
If (rng.Rows.Count - rowoffsetcount > 0) Then
' Reduce the number of rows in the range so it ends at the same row
Set rng = rng.Resize(rng.Rows.Count - rowoffsetcount)
' Check that there is a sheet we can copy it to
On Error Resume Next
Set newsht = Nothing
Set newsht = newBook.Worksheets(sht.Index)
On Error GoTo 0
' We have run out of sheets, add another at the end
If (newsht Is Nothing) Then
Set newsht = newBook.Sheets.Add(, newBook.Worksheets(newBook.Worksheets.Count))
End If
' Give it the same name
newsht.Name = sht.Name
' Get the range of visible (i.e. unfiltered) rows
' (can't do this before the range resize as that doesn't work on disjoint ranges)
Set rng = rng.SpecialCells(xlCellTypeVisible)
' Paste the visible data into the new sheet
rng.Copy newsht.Range("A1")
End If
Next
End Sub