I've been working from this article to try and consolidate data from multiple worksheets into a single summary worksheet. I've nearly got it working but I'm struggling to alter the destination worksheet.
I'm trying to have the consolidated data appear into cell B4 on the Consolidated Tracker sheet.
With CopyRng
Set DestSh = ThisWorkbook.Worksheets("Consolidated Tracker")
Set myRange = DestSh.Range("B4")
End With
Problem is myRange is always empty and nothing is copied over.
No error, seems to execute f8 as expected without copying anything over.
Full Code for reference:
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
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each sh In ActiveWorkbook.Worksheets
' Find the last row with data on the summary worksheet.
Last = LastRow(DestSh)
' Specify the range to place the data.
Set CopyRng = sh.Range("B4:B50")
' This statement copies values
With CopyRng
Set DestSh = ThisWorkbook.Worksheets("Consolidated Tracker")
Set myRange = DestSh.Range("B4")
End With
'End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(4, 2)
' AutoFit the column width in the summary sheet.
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
The issue is that the code never actually execute any type of command to move the data. The code only sets variables.
Look at the modified code below, specifically the last line before the End With.
' Specify the range to place the data.
Set CopyRng = sh.Range("B4:B50")
' This statement copies values
With CopyRng
Set DestSh = ThisWorkbook.Worksheets("Consolidated Tracker")
DestSh.Range("B4").Resize(CopyRng.Rows.Count,1).Value = CopyRng.Value
End With
Related
I have set up code to copy a filtered table into a new document, it works fine but for some reason the data ends up in Sheet 2 of the new workbook. Could someone please enlighten me as to why? I cant see any reference to sheet 2 so am very confused (also very much a novice)
Here is the code I use:
Sub CopyFilteredTable()
Dim rng As Range
Dim WS As Worksheet
Set newBook = Workbooks.Add
For Each Row In Range("Table2[#All]").Rows
If Row.EntireRow.Hidden = False Then
If rng Is Nothing Then Set rng = Row
Set rng = Union(Row, rng)
End If
Next Row
Set WS = Sheets.Add
rng.Copy newBook.Worksheets("Sheet1").Range("A1")
End Sub
Remove this line Set WS = Sheets.Add and try..
Also you can modify line rng.Copy newBook.Worksheets("Sheet1").Range("A1") as **rng.copy newbook.Worksheets(1).Range ("A1")**
I have been looking at several related questions and cant seem to get a working solution for my workbook. I am trying to make a "add new section" Macro/Button that will copy a range of data and paste it to the last row of the active worksheet.
My current code is as follows:
Sub EnterClientSection()
'
' EnterClient Section Macro
'
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = Worksheets("Zdata")
Set pasteSheet = ActiveSheet
copySheet.Range("A70:G81").Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
'
When I run the macro, it simply selects the last row on the current worksheet but doesnt seem to copy or paste anything.
"Zdata" is where the range of cells I would like to copy is stored.
Thank you for any with this :)
I got some script here to open up multiple workbooks with a worksheet and then copy it to a worksheet as a loop, but I need an additional cell (the date) from another worksheet in the multiple workbooks because the output I got cannot be changed and just added to the same sheet.
What I need is for this code to include a single cell range from another sheet on the workbook and then fill it to the bottom of the range per workbook.
I cant use UNION as it's not the same length, and I looked up merging ranges into one, but I get type mismatch errors.
VBA: How to combine two ranges on different sheets into one, to loop through I tried this but I can't figure out how to put it into my code.
Here is the code I have that works so far for just the one range. The rngdate copies over but does not leave a gap or autofill to the next loop, it just pastes under each other, so maybe this code will work but I'm missing something basic like autofill?
Dim vFileNames As Variant
Dim y As Long
Dim wbTemp As Workbook
Dim wbNew As Workbook
Dim blHeader As Boolean
Dim Rng As Range
Dim rngDate As Range
Application.ScreenUpdating = False
Set wbNew = Workbooks("master_timesheet") '.Add
blHeader = False
vFileNames = Application.GetOpenFilename(Title:="Select all workbooks to copy", _
MultiSelect:=True)
'Will not be array if no file is selected
'If user selects one or more files, files will be stored as an array
If Not IsArray(vFileNames) Then GoTo ConsolidateWB_End
For y = LBound(vFileNames) To UBound(vFileNames)
'Open each wb selected
Set wbTemp = Workbooks.Open(vFileNames(y))
Set rngDate = wbTemp.Worksheets("Communications Unlimited Inc").Range("A5").CurrentRegion
Set Rng = wbTemp.Worksheets("Export").Range("A1").CurrentRegion
'If header row already copied, then offset by 1 to exclude header
If blHeader Then
Set Rng = Rng.Offset(1, 0).Resize(Rng.Rows.Count - 1)
'If header row not already copied, keep rng as is and change blHeader to true
Else
blHeader = True
End If
'Paste to next row on new wb
Rng.Copy Destination:=wbNew.Sheets(1).Range("A65536").End(xlUp).Offset(1, 0)
rngDate.Copy Destination:=wbNew.Sheets(1).Range("P65536").End(xlUp).Offset(1, 0)
wbTemp.Close SaveChanges:=False
Next y
ConsolidateWB_End:
Application.ScreenUpdating = True
End Sub
If I read your problem correctly you want the date, rngdate, pasted adjacent to each and every line of data you have just copied. However your current code only puts the data on the first row. Below is an adaptation of how I have solved this problem myself, taking account of your existing code. (My guess is that there is a much more elegant solution than this which I'm just not aware.)
Dim pasterangefirstrow As Integer
...
pasterangefirstrow = wbNew.Sheets(1).Range("D65536").End(xlUp).Offset(1, 0).Row
...
With wbNewSheets(1)
Rng.Copy Destination:=.Range("D65536").End(xlUp).Offset(1, 0)
rngdate.Copy Destination:=.Range("P" & pasterangefirstrow & ":P" & pasterangefirstrow + Rng.Rows.Count - 1)
End With
I have a very strange problem with some Excel VBA code I created.
I won't get into the specifics (unless needed), but I have code which filters and copies data from one sheet to another.
On this second sheet it checks for empty columns and deletes them.
I have created this small macro to do the delete-part:
Public Sub deleteemptyrows()
Dim C As Integer
Range("A1").Select
Application.CutCopyMode = False
C = ActiveSheet.Cells.SpecialCells(xlLastCell).Column
Do Until C = 0
If WorksheetFunction.CountA(Columns(C)) = 1 Then
Columns(C).Delete
End If
Debug.Print C
C = C - 1
Loop
End Sub
Now this macro works perfectly and superfast (for the approx. 500 columns I'm checking every time) but the problem occurs when I call this macro in my VBA code (after the code copies the filtered data).
When it reaches the line Columns(C).Delete the memory of EXCEL.exe is going up to 6 GB in task manager, and it's running very, very slow column by column.
I have added the Application.CutCopyMode = False line because I thought it might have the copied data in it's memory, but that didn't help.
Any idea on how to fix this? Thanks!
Whilst you need to loop over the columns in the used range of the sheet - you don't need to delete them one-by-one. You can build a range - using Union - to create a non-contiguous range of columns with only headers and then delete them all in a single go. Using this technique in with disabling various properties of Application should give you an efficient method:
Option Explicit
Sub DeleteColumnsEfficiently()
Dim ws As Worksheet
Dim rngEmptyColumns As Range
Dim rngColumn As Range
Dim wsf As WorksheetFunction
Dim lngSetting As Long
' set a reference to worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
' set reference to WorksheetFunction
Set wsf = Application.WorksheetFunction
' initialise range of empty columns
Set rngEmptyColumns = Nothing
' set application settings to optimise ui change
With Application
.ScreenUpdating = False
.EnableEvents = False
lngSetting = .Calculation
.Calculation = xlCalculationManual
End With
' loop columns in usedrange
For Each rngColumn In ws.UsedRange.Columns
' check if only header populated
If wsf.CountA(rngColumn) = 1 Then
' if just header - then add to range of columns
If rngEmptyColumns Is Nothing Then
Set rngEmptyColumns = rngColumn.Offset
Else
Set rngEmptyColumns = Application.Union(rngEmptyColumns, rngColumn)
End If
End If
Next rngColumn
' delete columns with only header
rngEmptyColumns.Delete
' reset application settings
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = lngSetting
End With
End Sub
If you are trying to run the sub routine by passing the sheet string, you may try the Robin's code as below...
Remember you are supposed to place this code on a Standard Module like Module1, Module2 etc. after inserting a New Module not on ThisWorkbook Module as you did in the sample workbook.
Option Explicit
Sub DeleteColumnsEfficiently(ByVal strSheetName As String)
Dim ws As Worksheet
Dim rngEmptyColumns As Range
Dim rngColumn As Range
Dim wsf As WorksheetFunction
Dim lngSetting As Long
' set a reference to worksheet
Set ws = ThisWorkbook.Worksheets(strSheetName)
' set reference to WorksheetFunction
Set wsf = Application.WorksheetFunction
' initialise range of empty columns
Set rngEmptyColumns = Nothing
' set application settings to optimise ui change
With Application
.ScreenUpdating = False
.EnableEvents = False
lngSetting = .Calculation
.Calculation = xlCalculationManual
End With
' loop columns in usedrange
For Each rngColumn In ws.UsedRange.Columns
rngColumn.Select
rngColumn.Offset.Select
' check if only header populated
If wsf.CountA(rngColumn) = 1 Then
' if just header - then add to range of columns
If rngEmptyColumns Is Nothing Then
Set rngEmptyColumns = rngColumn
Else
Set rngEmptyColumns = Application.Union(rngEmptyColumns, rngColumn)
End If
End If
Next rngColumn
' delete columns with only header
If Not rngEmptyColumns Is Nothing Then
rngEmptyColumns.Delete
End If
' reset application settings
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = lngSetting
End With
End Sub
Sub Test()
DeleteColumnsEfficiently "Sheet1"
End Sub
I am trying to loop through some columns in a row and create new worksheets with the name of the value of the current column/row that I am in.
Sub test()
Range("R5").Select
Do Until IsEmpty(ActiveCell)
Sheets.Add.Name = ActiveCell.Value
ActiveCell.Offset(0, 1).Select
Loop
End Sub
This code creates the first one correctly starting at R5 but then it appears that the macro switches to that worksheet and doesn't complete the task.
The Sheets.Add automatically moves your selection to the newly created sheet (just like if you insert a new sheet by hand). In consequence the Offset is based on cell A1 of the new sheet which now has become your selection - you select an empty cell (as the sheet is empty) and the loop terminates.
Sub test()
Dim MyNames As Range, MyNewSheet As Range
Set MyNames = Range("R5").CurrentRegion ' load contigeous range into variable
For Each MyNewSheet In MyNames.Cells ' loop through cell children of range variable
Sheets.Add.Name = MyNewSheet.Value
Next MyNewSheet
MyNames.Worksheet.Select ' move selection to original sheet
End Sub
This will work better .... you assign the list of names to an object variable of type Range and work this off in a For Each loop. After you finish you put your Selection back to where you came from.
Sheets.Add will automatically make your new sheet the active sheet. Your best bet is to declare variables to your objects (this is always best practice) and reference them. See like I've done below:
Sub test()
Dim wks As Worksheet
Set wks = Sheets("sheet1")
With wks
Dim rng As Range
Set rng = .Range("R5")
Do Until IsEmpty(rng)
Sheets.Add.Name = rng.Value
Set rng = rng.Offset(0, 1)
Loop
End With
End Sub
Error handling should always be used when naming sheets from a list to handle
invalid characters in sheet names
sheet names that are too long
duplicate sheet names
Pls change Sheets("Title") to match the sheet name (or position) of your title sheet
The code below uses a variant array rather than a range for the sheet name for performance reasons, although turning off ScreenUpdating is likely to make the biggest difference to the user
Sub SheetAdd()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim strError As String
Dim vArr()
Dim lngCnt As Long
Dim lngCalc As Long
Set ws1 = Sheets("Title")
vArr = ws1.Range(ws1.[r5], ws1.[r5].End(xltoRight))
If UBound(vArr) = Rows.Count - 5 Then
MsgBox "sheet range for titles appears to be empty"
Exit Sub
End If
With Application
.ScreenUpdating = False
.EnableEvents = False
lngCalc = .Calculation
End With
For lngCnt = 1 To UBound(vArr)
Set ws2 = Sheets.Add
On Error Resume Next
ws2.Name = vArr(lngCnt, 1)
If Err.Number <> 0 Then strError = strError & vArr(lngCnt, 1) & vbNewLine
On Error GoTo 0
Next lngCnt
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = lngCalc
End With
If Len(strError) > 0 Then MsgBox strError, vbCritical, "These potential sheet names were invalid"
End Sub
This is probably the simplest. No error-handling, just a one-time code to create sheets
Sub test()
Workbooks("Book1").Sheets("Sheet1").Range("A1").Activate
Do Until IsEmpty(ActiveCell)
Sheets.Add.Name = ActiveCell.Value
Workbooks("Book1").Sheets("Sheet1").Select
ActiveCell.Offset(0, 1).Select
Loop
End Sub