New in VBA and learning on my own.
The intent for the code below is to copy cell "D5" from every sheet in workbook and then paste all the data in workbook "Data", range D4:D300 (the range is pretty broad so it will have more cell available than cells copied). The problem is that the code below is not working. All the code is doing is coping cell D5 from the first sheet over the range indicated (D4:D300). Basically copying the same value 266 times. Any help is highly appreciated.
If there is a more elegant/efficient way to write this code, please advise.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim LastRow As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
' Loop through worksheets that start with the name "20"
For Each sh In ActiveWorkbook.Worksheets
' Specify the range to copy the data
sh.Range("D5").Copy
' Paste copied range into "Data" worksheet in Column D
With DestSh.Range("D4:D300")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
Next
End Sub
You don't need to specify an end range -- just 'count' the number of sheets to determine the total # of values you'll need to add to the data tab. Also added in a check to see if you're on the Data worksheet so you don't copy the D5 value from Data again into a row in the same worksheet.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim i As Integer
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
' Loop through worksheets that start with the name "20"
i = 4
For Each sh In ActiveWorkbook.Worksheets
If sh.Name = "Data" Then Exit Sub
sh.Range("D5").Copy
With DestSh.Range("d" & i)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
i = i + 1
Next
End Sub
On each pass through your ActiveWorkbook.Worksheets loop, paste into the cell below the last cell in column D unless D4 is blank, in which case paste in D4. I'm assuming column D is completely blank before running the macro but if D3 has something in it you can do away with the .Range("D4") = "" test.
Sub copycell()
Dim sh As Worksheet
Dim wb As Workbook
Dim DestSh As Worksheet
Dim LastRow As Long
On Error GoTo GracefulExit:
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wb = ThisWorkbook
Set DestSh = wb.Sheets("Data")
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> "Data" Then
sh.Range("D5").Copy
' Paste copied range into "Data" worksheet in Column D
' starting at D4
With DestSh
If .Range("D4") = "" Then
With .Range("D4")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
Else
With .Cells(.Cells(.Rows.Count, 4).End(xlUp).Row + 1, 4)
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
End With
End If
End With
End If
Application.CutCopyMode = False
Next
GracefulExit:
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
If Err <> 0 Then
MsgBox "An unexpected error no. " & Err & ": " _
& Err.Description & " occured!", vbExclamation
End If
End Sub
if you are more concerned about values, then a more concise code could be the following:
Option Explicit
Sub copycell()
Dim sh As Worksheet
Dim iSh As Long
With ThisWorkbook
ReDim dataArr(1 To .Worksheets.Count - 1)
For Each sh In .Worksheets
If sh.Name <> "Data" Then
iSh = iSh + 1
dataArr(iSh) = sh.Range("D5").Value
End If
Next
.Worksheets("Data").Range("D4").Resize(.Worksheets.Count - 1).Value = Application.Transpose(dataArr)
End With
End Sub
where you first store all sheets D5 cell values into an array and then write them in one shot into Data worksheet
Related
I need to copy the data from a specific column of all worksheets of an excel file and paste it on to specific sheet with each subjects' name as the first row of the column (which is also the sheet name) and their data underneath that.
The problem is that I get Run-time error '1004':
Application-defined or object-defined error
at the line: targetWs.Cells(2, subColumn).PasteSpecial x1PasteValues
Sub Data()
'
' Data Macro
'assign varaible to subject worksheet and target worksheet
Dim subWs As Worksheet
Dim targetWs As Worksheet
'set subject sheet and target sheet
Set targetWs = ActiveWorkbook.Sheets("Sheet1")
'Loop through all worksheets
'not really sure if I'm doing this right
'Copy subject name; paste to target sheet
Rows(1).Insert
Dim i As Integer
For i = 1 To Sheets.Count
Cells(1, i) = Sheets(i).Name
Next i
'Loop through all worksheets
'not really sure if I'm doing this right
For Each subWs In ThisWorkbook.Worksheets
'Copy subject data; paste to target sheet
subWs.Range("B2:B242").Copy
targetWs.Cells(2, subColumn).PasteSpecial x1PasteValues
subColumn = subColumn + 1
Next subWs
End Sub
As stated in the comment above, I'll try to make it clear what they meant.
First, you have a typo, PasteSpecial x1PasteValues should be PasteSpecial xlPasteValues (it's an "l" not "1").
Second, first time you enter the loop (For Each subWs In ThisWorkbook.Worksheets), since you haven't initialized subColumn to any value, it's 0. so when you try to paste targetWs.Cells(2, subColumn), the first time you enter the loop it's actually targetWs.Cells(2, 0), since there is no column 0, you get this "lovely" run-time error #1004.
Copy a range of each sheet
Note: This example use the function LastRow
This example copy the range A1:G1 from each worksheet.
Change the range in this code line
'Fill in the range that you want to copy
Set CopyRng = sh.Range("A1:G1")
Sub CopyRangeFromMultiWorksheets()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
'Delete the sheet "RDBMergeSheet" if it exist
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
On Error GoTo 0
Application.DisplayAlerts = True
'Add a worksheet with the name "RDBMergeSheet"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "RDBMergeSheet"
'loop through all worksheets and copy the data to the DestSh
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
'Find the last row with data on the DestSh
Last = LastRow(DestSh)
'Fill in the range that you want to copy
Set CopyRng = sh.Range("A1:G1")
'Test if there enough rows in the DestSh to copy all the data
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the Destsh"
GoTo ExitTheSub
End If
'This example copies values/formats, if you only want to copy the
'values or want to copy everything look at the example below this macro
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
'Optional: This will copy the sheet name in the H column
DestSh.Cells(Last + 1, "H").Resize(CopyRng.Rows.Count).Value = sh.Name
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
'AutoFit the column width in the DestSh sheet
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
https://www.rondebruin.nl/win/s3/win002.htm
I am trying to achieve the following.
When I enter a value on 'Master' worksheet in the Range A5:A50, a macro is run which creates a new worksheet with the same name as the value and then copies the template onto the new sheet.
In addition to this I would also like to copy the value adjacent to the value enter on Master worksheet to this new worksheet so it does calculations automatically.
For example I enter '1' in A5 and '2' in B5. I would like to create a new worksheet with name '1', copy the template from 'Template' worksheet and copy the value of B5 on to the new worksheet named '1'.
I have following code but it also tries to copy Template worksheet with macro is run which results in an error because a worksheet with name 'Template' already exists.
Sub CreateAndNameWorksheets()
Dim c As Range
Application.ScreenUpdating = False
For Each c In Sheets("Master").Range("A5:A50")
Sheets("Template").Copy After:=Sheets(Sheets.Count)
With c
ActiveSheet.Name = .Value
.Parent.Hyperlinks.Add Anchor:=c, Address:="", SubAddress:= _
"'" & .Text & "'!A1", TextToDisplay:=.Text
End With
Next c
Application.ScreenUpdating = True
End Sub
Right-click the Master worksheet's name tab and select View Code. When the VBE opens up, paste the following into the window titled something like Book1 - Master (Code).
Private Sub Worksheet_Change(ByVal target As Range)
If Not Intersect(target, Rows("5:50"), Columns("A:B")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
Dim r As Long, rw As Long, w As Long
For r = 1 To Intersect(target, Rows("5:50"), Columns("A:B")).Rows.Count
rw = Intersect(target, Rows("5:50"), Columns("A:B")).Rows(r).Row
If Application.CountA(Cells(rw, 1).Resize(1, 2)) = 2 Then
For w = 1 To Worksheets.Count
If LCase(Worksheets(w).Name) = LCase(Cells(rw, 1).Value2) Then Exit For
Next w
If w > Worksheets.Count Then
Worksheets("Template").Visible = True
Worksheets("Template").Copy after:=Sheets(Sheets.Count)
With Sheets(Sheets.Count)
.Name = Cells(rw, 1).Value2
.Cells(1, 1) = Cells(rw, 2).Value
End With
End If
With Cells(rw, 1)
.Parent.Hyperlinks.Add Anchor:=Cells(rw, 1), Address:="", _
SubAddress:="'" & .Value2 & "'!A1", TextToDisplay:=.Value2
End With
End If
Next r
Me.Activate
End If
bm_Safe_Exit:
Worksheets("Template").Visible = xlVeryHidden
Me.Activate
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Note that this depends on you having a worksheet named Template in order to generate the new worksheets. It also keeps the Template worksheet xlVeryHidden which means that it will not show up if you try to unhide it. Go into the VBE and use the Properties window (e.g. F4) to set the visibility to visible.
This routine should survive pasting multiple values into A2:B50 but it will discard proposed worksheet names in column A that already exists. There must be a value i both column A and column B of any row before it will proceed.
There are currently no checks for illegal worksheet name characters. You may want to familiarize yourself with those and add some error checking.
Another example relevant to the post title but not the specific application. Code updates sheets in master list with list row number creating sheet from template if it doesn't exist.
Other reference: https://stackoverflow.com/a/18411820/9410024.
Sub UpdateTemplateSheets()
' Update sheets in list created from a template
'
' Input: List on master sheet, template sheet
' Output: Updated sheet from template for each item in list
'
Dim wsInitial As Worksheet
Dim wsMaster As Worksheet
Dim wsTemp As Worksheet
Dim lVisibility As XlSheetVisibility
Dim strSheetName As String
Dim rIndex As Long
Dim i As Long
On Error GoTo Safe_Exit
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DisplayAlerts = False
' Application.Calculation = xlCalculationManual
Set wsInitial = ActiveSheet
Set wsMaster = Sheets("Summary")
Set wsTemp = Sheets("Template")
lVisibility = wsTemp.Visible ' In case template sheet is hidden
wsTemp.Visible = xlSheetVisible
For rIndex = 2 To wsMaster.Cells(Rows.Count, "A").End(xlUp).Row
' Ensure valid sheet name
strSheetName = wsMaster.Cells(rIndex, "A").Text
For i = 1 To 7
strSheetName = Replace(strSheetName, Mid(":\/?*[]", i, 1), " ")
Next i
strSheetName = Trim(Left(WorksheetFunction.Trim(strSheetName), 31))
' Ensure sheet name doesn't already exist
If Not Evaluate("IsRef('" & strSheetName & "'!A1)") Then
wsTemp.Copy after:=Sheets(Sheets.Count)
With Sheets(Sheets.Count)
.Name = strSheetName
End With
End If
With Sheets(strSheetName)
.Range("B59").Value = rIndex * 16 + 1 ' Update template block option row
End With
Next rIndex
Safe_Exit:
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayAlerts = True
'Application.Calculation = xlCalculationAutomatic
wsInitial.Activate
wsTemp.Visible = lVisibility ' Set template sheet to its original visible state
End Sub
Looking to copy rows from all sheets apart from my active sheet that meet a certain criteria in column J using VBA.
Not experienced in writing code in VBA so I have tried to frankenstein together the necessary parts from looking through other questions and answers;
below is the code I have written so far;
Sub CommandButton1_Click()
Dim lngLastRow As Long
Dim ws As Worksheet
Dim r As Long, c As Long
Dim wsRow As Long
Set Controlled = Sheets("Controlled") ' Set This to the Sheet name you want all Ok's going to
Worksheets("Controlled").Activate
r = ActiveSheet.Cells(Rows.Count, 2).End(x1up).Row
c = ActiveSheet.Cells(1, Columns.Count).End(x1ToLeft).Column
Range("J").AutoFilter
For Each ws In Worksheets
If ws.Name <> "Controlled" Then
ws.Activate
wsRow = ActiveSheet.Cells(Rows.Count, 2).End(x1up).Row + 1
Range("A" & r).AutoFilter Field:=10, Criteria1:="Y"
.Copy Controlled.Range("A3" & wsRow)
End If
Next ws
End If
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
End Sub
Where Controlled is the sheet I want the data to appear in from the other sheets, and all other sheets are searched to see if their column J meets the criteria="Y"
I won't need to copy over formatting as all Sheets will have the formatting exactly the same and if possible I want the rows that are copied over to start at row 3
Try this:
Option Explicit
Sub ConsolidateY()
Dim ws As Worksheet, wsCtrl As Worksheet
Dim lrow As Long, rng As Range
Set wsCtrl = Thisworkbook.Sheets("Controlled")
With Application
.ScreenUpdating = False
.DisplayAlerts = False
End With
For Each ws In Thisworkbook.Worksheets
If ws.Name = "Controlled" Then GoTo nextsheet
With ws
lrow = .Range("J" & .Rows.Count).End(xlUp).Row
.AutoFilterMode = False
Set rng = .Range("J1:J" & lrow).Find(what:="Y", after:=.Range("J" & lrow))
If rng Is Nothing Then GoTo nextsheet
.Range("J1:J" & lrow).AutoFilter Field:=1, Criteria1:="Y"
.Range("J1:J" & lrow).Offset(1,0).SpecialCells(xlCellTypeVisible).EntireRow.Copy
wsCtrl.Range("A" & wsCtrl.Rows.Count).End(xlUp).Offset(1,0).PasteSpecial xlPasteValues
.AutoFilterMode = False
Application.CutCopyMode = False
End With
nextsheet:
Next
With Application
.ScreenUpdating = True
.DisplayAlerts = True
End With
End Sub
I think this covers everything or most of your requirement.
Not tested though so I leave it to you.
If you come across with problems, let me know.
I'm working off of code I found via google. Originally the code was set up to create a new summary sheet, however I'd like to use one that already exists and paste the new data in the next empty row. The issue seems to happen when I set the summary worksheet. I'm getting a "Run-time error '438'" on this line of code -
Set DestSh = ActiveWorkbook.Worksheet("Tab_Upload").Activate
when I use the following code:
Sub CopyRangeFromMultiWorksheets()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Long
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
' Set Summary Worksheet.
Set DestSh = ActiveWorkbook.Worksheet("Tab_Upload").Activate
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each sh In ActiveWorkbook.Worksheets
If LCase(Left(sh.Name, 1)) = "_" Then
' Find the last row with data on the summary worksheet.
Last = DestSh.[a65536].End(xlUp).Row
' Specify the range to place the data.
Set CopyRng = sh.Rows("A23,B8:S8")
' Test to see whether there are enough rows in the summary
' worksheet to copy all the data.
If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
MsgBox "There are not enough rows in the " & _
"summary worksheet to place the data."
GoTo ExitTheSub
End If
' This statement copies values and formats from each
' worksheet.
CopyRng.Copy
With DestSh.Cells(Last + 1, "A")
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
' AutoFit the column width in the summary sheet.
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
try to change
Set DestSh = ActiveWorkbook.Worksheet("Tab_Upload").Activate
to
Set DestSh = ActiveWorkbook.Worksheets("Tab_Upload")
You have missed s in the end of Worksheets
As the title I tried this one, but it overwrites existing data, I am looking for something that
add the header row in all sheets moving the data down. I have got 50 sheets that's why I am asking :-)
Sub CopyToAllSheets()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("sheet1")
Sheets.FillAcrossSheets ws.Range("1:1")
End Sub
Thank you in advance
You could insert a line in each sheet before filling the headers:
Sub CopyToAllSheets()
Dim sheet As Worksheet
For Each sheet In Sheets
sheet.Rows("1:1").Insert Shift:=xlDown
Next sheet
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("sheet1")
Sheets.FillAcrossSheets ws.Range("1:1")
End Sub
I will be assuming that your header will be coming from another sheet. Recording a macro gives me:
Sub Macro4()
Sheets("Sheet1").Select
Rows("1:1").Select
Selection.Copy
Sheets("Sheet2").Select
Rows("1:1").Select
Selection.Insert Shift:=xlDown
Application.CutCopyMode = False
End Sub
Cleaning it up gives:
Sub InsertOnTop()
Sheets("Sheet1").Rows("1:1").Copy
Sheets("Sheet2").Rows("1:1").Insert Shift:=xlDown
Application.CutCopyMode = False
End Sub
Applying it safely across all sheets except the source sheet:
Sub InsertOnTopOfEachSheet()
Dim WS As Worksheet, Source As Worksheet
Set Source = ThisWorkbook.Sheets("Sheet1") 'Modify to suit.
Application.ScreenUpdating = False
For Each WS In ThisWorkbook.Worksheets
If WS.Name <> Source.Name Then
Source.Rows("1:1").Copy
WS.Rows("1:1").Insert Shift:=xlDown
End If
Next WS
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Let us know if this helps.
I believe you will need to loop through each sheet and insert a blank row, or just use the range.insert method on each sheet. Perhaps something like:
Option Explicit
Sub CopyToAllSheets()
Dim WS As Worksheet
For Each WS In ThisWorkbook.Worksheets
If Not WS.Name = "Sheet1" Then
If WorksheetFunction.CountA(WS.Rows(1)) > 0 Then _
WS.Rows(1).Insert
End If
Next WS
Worksheets.FillAcrossSheets Worksheets("Sheet1").Rows(1), xlFillWithAll
End Sub