Copy/Paste variable dataset between workbooks without clipboard - vba

I've been trying to optimize some of my coding and managed to cut and speed it up a lot. However there are some things that are still quite clunky (and me still a noob). Backstory is that my code is opening source and target files, copies a lot of data of variable length, closes source and then does a lot of operations and finally saves target file.
One of the things Id like is to do if possible is a direct copy of data without using clipboard, activating workbooks, selecting sheets (whatever of this is possible to pack into more efficient code that I am currently having)
Windows("SOURCE.xlsm").Activate
Sheets("Data").Select
Range("A2:AX10").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Windows("TARGET.xlsm").Activate
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Is it possible to do a selection (A2:AX10 and all the way down to last row) in SOURCE file-Data sheet and directly copy it to TARGET file-Data sheet cell A2 without using clipboard.
The reason why I use A2:AX10 and then selection down is because I have a lot of blank cells in the whole data set and this way I get entire data.
I would like to be able to to that selection and use it as a range in this line
Workbooks(“SOURCE”).Worksheets("Data").Range(“A2:AX10 & ALLTHEWAYDOWN”).Copy _Workbooks(“TARGET”).Worksheets("Data").Range(“A2")
I was trying to solve this but I dont end up with desired result. When I try doing selection and setting as range then both trying copy range with activitng workbooks and in the direct copy mode I get 1004 error.
Is it possible to optimize this chunk and make it work. It would improve a lot of my VBA.
Thanks,

You need something like this:
With Workbooks("SOURCE.xlsm").Sheets("Data")
.Range("A2:AX10", .Range("A2:AX10").End(xlDown)).Copy Workbooks("TARGET.xlsm").ActiveSheet.Range("A2")
End With
You could probably also use CurrentRegion rather than End(xlDown

You can set one range's values (the range where you would want to paste values) equal to a source range's values (the range which you would previously have copied).
Sub paste_values()
Dim wb_A As Workbook, ws_A As Worksheet
Dim wb_B As Workbook, ws_B As Worksheet
Dim last_row As Long
Set wb_A = ThisWorkbook
Set ws_A = wb_A.Sheets(1)
Set wb_B = Workbooks("WorkbookB")
Set ws_B = wb_B.Sheets(1)
With ws_A
last_row = .Range("A" & .Rows.Count).End(xlUp).Row
End With
ws_B.Range("A2:AX" & last_row).Value = ws_A.Range("A2:AX" & last_row).Value
End Sub
This code is setting the new range's values equal to the original range. It prevents the need to activate sheets or workbooks, whilst also copying data to a range without filling the clipboard.
I would also recommend using last_row = .Range("A" & .Rows.Count).End(xlUp).Row to find the last row of your data. Although you do need to ensure you use this on a column which you know contains continuous data.

Related

VBA Macro: Designating Sheets() with vlaues in a worksheet

I am trying to do the following:
There is a group of files of the same layout, and I would like to extract a specific page of each file and compile them together in one file.
I have manually created the compilation workbook, with each sheet named after the corresponding data source workbook.
I have created a loop that opens all the files and copy the specific sheet ("Target sheet"), but I am not sure how to paste them correctly.
Here is what I have so far:
Dim rw As Integer, prop As String
rw = 5
Do While rw < 44
prop = wb1.Sheets("summary sheet").Cells(rw, 3).Value
Workbooks.Open Filename:= "(file address)", UpdateLinks:=False
Set wb2 = ActiveWorkbook
Set ws1 = wb2.Sheets("Target sheet")
ws1.Range("A1").Copy Range("BA150")
wb1.Sheets(prop).Cells(1, 1).Paste
wb2.Close SaveChanges:=False
rw = rw + 1
Loop
Note: the file address contains some sensitive info so I did not post it here, but it is coded as such that it can be looped.
Since the sheet names can be found in a certain location in the summary sheet in the compilation file, I tried to code the "Sheets()" with dynamic reference to that list, but I am getting error messages "Run-time error '438' Object doesn't support this property or method", with the wb1.Sheets(prop).Cells(1,1).Paste being highlighted as the faulty line. Can someone suggest a solution to this? Thank you very much in advance!
======EDIT======
I found a solution thanks to the two comments - for future reference:
ws1.Cells.Copy Destination:=wb1.Sheets(wsn).Range("A1")
I used numerical sheet reference instead. Probably needed to amend the original code to: (not tested)
ws1.Cells.Copy Destination:=wb1.Sheets(""" & prop & """).Range("A1")
To make it work.
If you are copying the entire sheet, then you can use
wb2.Sheets("Target Sheet").Copy After:=wb2
Rather than copy/paste.
It basically copies the entire sheet to the other workbook.

VBA Runtime Error 1004 “Application-defined or Object-defined error” when setting Range in macro

I'm going to preface this by saying that I am very new to VBA and this is my first project with it however, I'm trying quite hard because otherwise it is manual copy paste ~200 times.
Unfortunately, for a first project it has been difficult.
EDITED FOR CLARITY (HOPEFULLY): The main idea is that I need to start at the beginning of a drop down list, copy the first string listed, then paste that string down the column. This changes the numerical data adjacent to the right. I then want to select this newly changed numerical data and copy and paste it to a different sheet in the same workbook in the first blank space in column F. I then want the code to iterate through the drop down list and do this for all 51 strings in the drop down. However it needs to paste offset by 3 columns for each iteration to copy the data to the correct column in the other sheet.
Here is my code thus far
Option Explicit
Sub PtComp()
'
' PtComp Macro
'
'
Dim List1 As String
Dim Range1 As Range
Dim Line1 As Range
Dim i As Integer
Dim Begin As Range
ActiveWorkbook.Sheets("Sample Data Summary").Activate
List1 = Selection
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
For Each Line1 In Range1
Selection.Copy
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
ActiveSheet.Paste
ActiveCell.Offset(0, 1).Select
ActiveSheet.Range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
ActiveSheet.Selection.Copy
ActiveWorkbook.Sheets("Pt Comparison").Activate
Begin = ActiveSheet.Range("F1").End(xlDown).Offset(-1, 0)
For i = 0 To 148 Step 3
Begin.Offset(0, i).Select
ActiveSheet.PasteSpecial Paste:=xlPasteValues
Next i
Next Line1
End Sub
It is highlighting this line
Set Range1 = Evaluate(ActiveSheet.Range(List1).Validation.Formula1)
Any help would be greatly appreciated. Sorry if my code is trash, like I said, first timer hoping to get better.
EDIT: Also, I looked back at older questions with the same error and thought that it was maybe because it wasn't clear what worksheet I was trying to define the range in, hence why my code is full of 'ActiveSheet' but still no luck.
Your code assumes List1 contains a valid range address, and thus that the active cell on that "Sample Data Summary" worksheet, contains a valid range address.
Apparently that isn't always the case. Search for more details on the On Error statement for ideas about how you could go about handling that situation.
You need to read up on How to avoid using Select in Excel VBA macros, and know that clipboard operations in a tight loop is pretty much the single slowest thing you can do in Excel-VBA.
Seems you want something like this:
Set Range1 = Evaluate(Selection.Validation.Formula1)
Your code blows up on Range(List1) because List1 does not contain a valid range address.

Copying rows and columns, including blanks, in excel vba without xlDown

I'd like to copy Rows and Columns of a worksheet to a new workbook. I can open and activate the new book and new sheets, but the data I am copying is currently A1:F520 on one sheet and A1:G1031 on another. There are multiple blanks in between
and within several "groups" of data sets.
For the sake of the visual organization of our data, I want to keep those blanks in. The ranges will be changing over time, so I don't want to define something specific. I'd rather keep it general like Range("A1", Range("A1".End(xlDown)). I suppose I could just include some ridiculously large range to ensure everything is there, but I'd rather accomplish this in a more dynamic (if that is the right word) sort of way.
This is what I have so far:
Option Explicit
Public LGSheet As Worksheet
Public SGSheet As Worksheet
Public NewWorkbook As Workbook
Public UserYear As Integer
Sub DefineYear()
UserYear = Application.InputBox(Prompt:="Set Date for New Workbook", Type:=1)
Set NewWorkbook = Workbooks.Add
Set SGSheet = Worksheets.Add
Set LGSheet = Worksheets.Add
Call PasteLGTandSGT
End Sub
Sub PasteLGTandSGT()
Workbooks("Finished Products YTD Generator").Activate
Worksheets("LGT").Activate
Range("A1", Range("A1").End(xlDown)).Copy
LGSheet.Activate
Obviously I've put the xlDown bit here, and my google-fu isn't strong enough to find out anything more.
For example:
With Workbooks("Finished Products YTD Generator").Worksheets("LGT")
.Range(.Range("A1"), .Cells(Rows.Count, 1).End(xlUp).Offset(0, 7)).Copy _
LGSheet.Range("A1") 'or whatever
End With
Note that you don't need to activate sheets to copy or paste, and it's a good habit to get out of.

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 Excel error when code is moved from worksheet to module

I have a Excel file with multiple tabs. I have a worksheet with some code which is working fine. This code also refers to data on some "master" tabs. I need to duplicate this sheet so I moved the common functions from there to a module. Now I get a VBA 1004 error when trying to access a range on the same worksheet.
Dim selectedRange As Range
Set selectedRange = Worksheets(name).Range("A1", _
Range("A" & Rows.count).End(xlUp)) 'Error Line
This code worked fine till I moved it to a module. It works if I put a
Worksheets(name).Select
before it, but I will have to do it too many times. Based on this query: VBA error 1004 - select method of range class failed
the code should work fine without a .Select. And it does as long as the code is within the worksheet. Why does moving code to a module create a problem?
U use Range and Rows properties without an object qualifier. When used without an object qualifier, this properties are a shortcut for ActiveSheet.Range / ActiveSheet.Rows.
So the code does this:
Worksheets(Name).Range("A1", ActiveSheet.Range("A" & ActiveSheet.Rows.Count).End(xlUp))
But Worksheets(name) could be different from active sheet so better is:
Worksheets(Name).Range("A1", Worksheets(Name).Range("A" & Worksheets(Name).Rows.Count).End(xlUp))
In With-End With block:
With Worksheets(name)
Set selectedRange = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With
So it is ensured that the Range/Rows properties are applied on Worksheets(name) worksheet object.
When you do things on a sheet, you do not really need explicit declarations to that sheet.
However when working on a module and interacting with other sheets, you need to specify which Sheet you want to work with. So select the sheet before you can select the range. To say, SELECT PARENT BEFORE YOU SELECT THE CHILDREN :) Please note, following is just the logic explanantion. Not the exact code syntax.
So I suggest you create the following worksheet variable and set your worksheet object that you need into that.
e.g.
Dim WS as Worksheet
Dim selectedRange As Range
Set WS = Sheets("Shee1")
Set selectedRange = WS.Range("A1", _
Range("A" & Rows.count).End(xlUp)) 'Error Line
Or else if you want to refer to all sheets, you may use each sheet's index
E.g. ThisWorkBook.Sheets(i) 'i is an integer
Then loop or whatever as it deems to your programme structure.
Further you do not have to use Select on the worksheet to point to a range in that worksheet. As per above code you could set the worksheet and set the range you need to process. When optimizing VBA execution, select is usually a taboo. Also Excel 2007 does not retain the active sheet the way older versions used to.