How to move rows from one workbook to another (no select) - excel

My goal is to take an excel document with variable row size, copy it and then paste it onto the bottom row of a new document.
Longer story, I need to take monthly sales reports and stack them into a larger excel file. Each month we make a variable number of sales. I need to aggregate all of these months together so we can process them.
I have some code that I thought worked below. It was able to move variable rows within different work sheets, but could not do the same for different work books.
Private Sub MoveRowToEndOfTable()
Dim LastRow As Long
LastRow = Cells.Find(What:="*", SearchOrder:=xlByRows,SearchDirection:=xlPrevious).Row
Sheets(1).Range("A2:A" & LastRow, "G2:G" & LastRow).Copy
Workbooks("BRN report Aggregator.xlsx").Worksheets("New shares EOM").Range("a6000").End(xlUp).Offset(1, 0).Cells.Insert
End Sub

I guess that your workbook is closed, check it before paste values (if workbook is closed ~> open it) :
Private Sub MoveRowToEndOfTable()
Dim LastRow As Long
LastRow = Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Sheets(1).Range("A2:A" & LastRow, "G2:G" & LastRow).Copy
Dim wb As Workbook, wb_target As Workbook
'check if workbook is open already
For Each wb In Workbooks
If wb.Name = "BRN report Aggregator.xlsx" Then
Set wb_target = Workbooks("BRN report Aggregator.xlsx")
Exit For
End If
Next wb
'if not then open it
If wb_target Is Nothing Then
Set wb = Workbooks.Open("Path_to_file/BRN report Aggregator.xlsx")
End If
wb.Worksheets("New shares EOM").Range("a6000").End(xlUp).Offset(1, 0).PasteSpecial xlPasteAll 'or xlPasteValues --depends on your needs
wb.Close True 'save and close if required
End Sub

Related

Want to Activate previous workbook in VBA

I have 1 active workbook and adding another multiple workbooks basis on column data
and same saving with Basis on Next function and giving value of column
Need to activate new added workbook but problem is every time workbook name is different basis on column hence unable to activate the same basis on name
Help to activate another workbook
Activate the another workbook (previous workbook) without declaring name
If you're adding new workbooks, they're normally activated, then you can use ActiveWorkbook.Name, if you're however opening workbooks depending on a cell's value, you can use that when setting it to a Workbook object.
In this example, the paths to workbooks are in the A-column:
Sub openWorkbooksFromVariables()
Dim Lastrow As Long, i As Long
Dim wbQ As Workbook, wbB As Workbook
Dim qPath As String
Lastrow = Range("A" & Rows.Count).End(xlUp).Row
Set wbB = ActiveWorkbook 'current workbook is now accessible through wbB
For i = 2 To Lastrow
qPath = "" & Range("A" & i).Value & ""
Set wbQ = Workbooks.Open(qPath)
wbQ.Activate
wbQ.Save
wbQ.Close
Next i
End Sub
If there's anything more needed, please update your question with an example.

Dynamically Copy Range of Cells from Closed Workbook?

I would like to copy a range of cells in a closed notebook that does not have a static set of rows. I would like to copy it into an active workbook.
I am trying to dynamically copy all entries under the column of F from file 'test.xlsx' from the 'exception' worksheet. The macro runs without issue if there I use static referencing instead. Here is the code that I am running, it gives me a runtime error for the line that copies the data.
Sub GetClassID()
Dim App As New Excel.Application
Dim wsActive As Worksheet
Set wsActive = ThisWorkbook.ActiveSheet
Dim wbImport As Workbook
Set wbImport = App.Workbooks.Open(Filename:="C:\Test.xlsx",
UpdateLinks:=True, ReadOnly:=True)
wbImport.Worksheets("Exception").Range("F2",Range("F2").end(xldown)).Copy
wsActive.Range("A2").PasteSpecial Paste:=xlPasteFormats
wsActive.Range("A2").PasteSpecial Paste:=xlPasteValues
App.CutCopyMode = False
wbImport.Close SaveChanges:=False
App.Quit
End Sub
Error I get is runtime erorr '1004': Interface not registered
Assuming you run this in an Excel VBA? You don't need to open the other workbook as an Excel.Application, just remove the app out of it and open the workbook normally:
Sub GetClassID()
Dim wsActive As Worksheet
Set wsActive = ThisWorkbook.Sheets("Another Sheet Name")
Dim wbImport As Workbook
Set wbImport = Workbooks.Open(Filename:="C:\Test.xlsx", UpdateLinks:=True, ReadOnly:=True)
With wbImport.Worksheets("Exception")
.Range("F2", .Range("F2").End(xlDown)).Copy
End With
wsActive.Range("A2").PasteSpecial Paste:=xlPasteFormats
wsActive.Range("A2").PasteSpecial Paste:=xlPasteValues
App.CutCopyMode = False
wbImport.Close SaveChanges:=False
App.Quit
End Sub
In my experience, the most effective way to copy a dynamic range is to create a variable as an integer and assign the row of the last cell to be copied (or column if needing to select a row of data across to a certain point. I usually accomplish it with something like this:
Dim R as Integer
With ThisWorkbook.Worksheets
R = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
Then you can plug in 'R' for the row number in a range to make it dynamic each time the macro is ran. For instance: .Range("A1:A" & R).Copy would copy the used range in Column A. It also makes it really easy to reference the last row for loops and such continuously throughout your code. Hope this helps!

Using data from another workbook (other than the active one)

Ignoring what my code actually does (it's not important to my question):
I want to be able to open my excel file, press a button, have the code use data in that workbook and another opened workbook (so I would have two workbooks opened at the same time, the macro runs in one of them but can take data from both of them).
The trick here is that I can't seem to find code to access the other workbook that I've opened up, so I can only take info from the active workbook.
For example,
Private Function GetLastRow() As Integer
Dim myLastRow As Integer
Set ws = ThisWorkbook.Sheets("Sheet1")
myLastRow = Range("C" & Rows.count).End(xlUp).Row
GetLastRow = myLastRow
End Function
This code lets me access the active workbook (the one running the code), using ThisWorkbook.
Is there another function capable of allowing me to access another opened workbook?
You could change your function to be more flexible.
Private Function GetLastRow(InWorksheet As Worksheet, InColumn As Variant) As Long
GetLastRow = InWorksheet.Cells(InWorksheet.Rows.Count, InColumn).End(xlUp).Row
End Function
So you can call it …
Sub Test()
Dim LastRow As Long
LastRow = GetLastRow(ThisWorkbook.Worksheet("Sheet1"), "C") 'column as letter
'or
'LastRow = GetLastRow(ThisWorkbook.Worksheet("Sheet1"), 3) 'column as number
End Sub
So you can even run this on another workbook using:
LastRow = GetLastRow(Workbooks("OtherWorkbook.xlsx").Worksheet("Sheet1"), "C") 'column as letter
There is a Workbook object built into VBA that you can use. This documentation should give you the information that you need https://learn.microsoft.com/en-us/office/vba/api/excel.workbook
You would simply put the name of your other workbook in quotes, in parentheses after using the Workbook object (see example on page I hyperlinked). Good luck!
I guess this is what you looking for.
When you have more then one Workbook active you can switch between then.
Sub GetLastRow()
Dim myLastRow As Integer
'Active Workbook
Set ws = ThisWorkbook.Sheets("Plan1")
myLastRow = ws.Range("C" & Rows.Count).End(xlUp).Row
MsgBox myLastRow
'Way when you know workbook name
Workbooks.Open Filename:=ActiveWorkbook.Path & "\Teste1.xlsx"
Set ws1 = Application.Workbooks("Teste1.xlsx").Sheets("Plan1")
myLastRow1 = ws1.Range("C" & Rows.Count).End(xlUp).Row
MsgBox myLastRow1
Dim myLastRow As Integer
'If you don't know the name but, opened after your main Workbook
Set ws3 = Application.Workbooks(2).Sheets("Plan1")
myLastRow3 = ws1.Range("C" & Rows.Count).End(xlUp).Row
MsgBox myLastRow3
End Sub

Making a loop to execute same code multiple times

I need some help to create a loop from my code
The code has two main functions:
Copy and paste general data to another workbook
Copy and paste employee data to another workbook
I want to make a loop of my code (code is shown below). I can make this code 15 times and it will work but I think that a loop is better. I don't have any experience with loops.
So when I press a button on my sheet it copies the general data and opens a other workbook, then it goes back tot he main workbook and copies the employee data and paste them in the other workbook.
The workbook that needs to be opened is found in range F82:F96, so first F82 then F83... and so on, until it reaches F96 and then the code must stop.
The general data is always found in row 15 & 16.
The employee data is found with the same string as the workbook that must be opened. The row after the string must me copied and paste in the other workbook. So for example (G82:DI82).
What I have
I made a code that works for 1 employee in cell(F82) the code below opens the workbook of this employee then copies the general data then find the right column and row to paste. Then I paste the data then it goes back tot he main workbook and copies the data which belongs to he employee (G82:DI82) an paste this data in the other workbook. Then it saves closes the opened workbook. The main workbook stays open.
What I expect
I need a loop to repeat the code. So first the employee which is in (F82) then the employee which in (F83) and so on.
The code:
Private Sub mUpdate_Click()
Dim General As Range
Dim employe1hours As Range
Dim employepaste As Range
Dim employepastehours As Range
Dim CurrentweekColumn As Range
Dim Currentweekpaste As Range
Dim employepath As String
Dim employe1 As String
Dim rowstr As String
Dim Foundrow As Range
Dim Currentweek As String
employepath = "J:\Planning\Medewerkers\"
Currentweek = Range("B7").Value
employe1 = Range("F82").Value
rowstr = Range("A2").Value
With ActiveWorkbook.Sheets("Planning").Range("14:14")
Set CurrentweekColumn = .find(what:=Currentweek, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
Set General = ActiveWorkbook.Sheets("Planning").Range(Cells(15, CurrentweekColumn.Column), Cells(16, CurrentweekColumn.Offset(0, 106).Column))
General.Copy
Workbooks.Open (employepath & employe1 & ".xlsm")
With ActiveWorkbook.Sheets("Blad1").Range("14:14")
Set Currentweekpaste = .find(what:=Currentweek, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
With ActiveWorkbook.Sheets("Blad1").Range("A:A")
Set Foundrow = .find(what:=rowstr, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=False, SearchFormat:=False)
End With
Set employepaste = ActiveWorkbook.Sheets("Blad1").Range(Cells(Foundrow.Row, Currentweekpaste.Column).Address)
employepaste.PasteSpecial Paste:=xlPasteFormats
employepaste.PasteSpecial Paste:=xlPasteValues
Workbooks(rowstr & ".xlsm").Activate
Set employe1hours = ActiveWorkbook.Sheets("Planning").Range(Cells(82, CurrentweekColumn.Column), Cells(82, CurrentweekColumn.Offset(0, 106).Column))
employe1hours.Copy
Workbooks(employe1 & ".xlsm").Activate
Set employepastehours = ActiveWorkbook.Sheets("Blad1").Range(Cells(Foundrow.Offset(2, 0).Row, Currentweekpaste.Column).Address)
employepastehours.PasteSpecial Paste:=xlPasteValues
ActiveWorkbook.Save
ActiveWorkbook.Close
Since we cannot do all the work for you, this should give you an idea how the loop could look like:
Option Explicit
Public Sub MyUpdateProcedure()
Dim Employees As Range 'define the range of employees
Set Employees = ThisWorkbook.Worksheets("SheetName").Range("F82:F96")
Dim CurrentWorkbook As Workbook
Const EmployePath As String = "J:\Planning\Medewerkers\"
Dim Employe As Range
For Each Employe In Employees 'loop throug all employees
'open the workbook
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
With CurrentWorkbook.Sheets("Blad1")
'your stuff here
End With
'your other stuff here
'save and close workbook
CurrentWorkbook.Close SaveChanges:=True
Next Employe
End Sub
Note that you have to avoid ActiveWorkbook and instead set the opened workbook into a variable like Set CurrentWorkbook = Workbooks.Open that you can easily use then.
Also make sure that all your Range(…) objects have a workbook/worksheet specified like ThisWorkbook.Worksheets("SheetName").Range(…) otherwise Excel guesses which worksheet you mean.
Also be aware of errors:
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
will throw an error if the workbook does not exist so you might want to catch it:
'open the workbook
Set CurrentWorkbook = Nothing 'initialize since we are in a loop!
On Error Resume Next 'next line throws an error if file not found so catch it
Set CurrentWorkbook = Workbooks.Open(EmployePath & Employe.Value & ".xlsm")
On Error GoTo 0 'always re-activate error reporting!
If Not CurrentWorkbook Is Nothing Then
'file for employee was found
With CurrentWorkbook.Sheets("Blad1")
'your stuff here
End With
'your other stuff here
'save and close workbook
CurrentWorkbook.Close SaveChanges:=True
Else
'file for employee was not found
End If

Why is this macro copying multiple times?

I found this macro and it does what I need it to do however whenever it's activated it seems to copy/paste the data multiple times. My master list should only have 75 or so lines and when this runs it ends up at 268. Why is it doing that? Also, is there a way to edit it so if a sheet has no data in it after "A1" it doesn't copy that sheet?
Option Explicit
Private Sub Worksheet_Activate()
'Merge all sheets in a workbook into one summary sheet (stacked)
Dim cs As Worksheet, ws As Worksheet, LR As Long, NR As Long
Application.ScreenUpdating = False
Set cs = Sheets("Master List")
cs.Activate
Range("A2:F" & Rows.Count).ClearContents
For Each ws In Worksheets
If ws.Name <> "Master List" Then
NR = cs.Range("A" & Rows.Count).End(xlUp).Row + 1
LR = ws.Range("A" & Rows.Count).End(xlUp).Row
ws.Range("A2:F" & LR).copy cs.Range("A" & NR)
End If
Next ws
Application.ScreenUpdating = True
End Sub
You have this in the Private Sub Worksheet_Activate() event of the workbook. If this is written into the "Master List" sheet's code, then activating the sheet as you do with line cs.activate will trigger the macro again... the one that is currently running. It's hard to say why this only creates 268 and not infinite, or double... it's tough to say and may be dependant on the speed at which excel works and it's single threadiness or some other deep down dark mystery of Excel and VBA.
Instead of
cs.activate
range("a2:f" & rows.count).clearcontents
try
cs.range("a2.f" & rows.count).clearcontents
If you find yourself writing .activate or .select in your vba code, you are probably doing something not-so-great.

Resources