VBA Macro wanted - Loop copying data from one sheet to another - vba

Last year, I made a huge spreadsheet with all newest available data on every country in the world. The idea was that I could download the latest data - say, a data sheet containing population statistics from the World Bank - and easily transport them into my main sheet.
Here is an example of how it looked like:
To draw the data from the other spreadsheets, I used long, messy lines of IF-functions, such as:
=IF(ISNUMBER(IFERROR(VLOOKUP($A3;Population!$A$3:$C$400;2;FALSE);"Not
Found"));IFERROR(VLOOKUP($A3;Population!$A$3:$C$400;2;FALSE);"Not
Found");"Not Found")&"
("&IF(ISNUMBER(IFERROR(VLOOKUP($A3;Population!$A$3:$C$400;3;FALSE);"Not
Found"));IFERROR(VLOOKUP($A3;Population!$A$3:$C$400;3;FALSE);"Not
Found");"Not Found")&")"
Obviously, this is not the most efficient way of doing this. Here is what I need the macro to do:
To first match column A, containing all country names, in my main sheet, with column A in the data sheet, containing countries specific to this data set.
Then copy-paste the latest data (non-blank cell furthest to the right) from the data sheet into the main sheet, at the appropriate places (i.e. Uganda gets matched with Uganda).
The pasted data must also contain their respective years in parenthesis (in the picture, all data happen to be from 2016, but this is not always the case).
I have experimented with some loops to try and replicate the above-mentioned IF-functions, but nothing seems to work for me. So far, my tries have led me to this:
Option Explicit
Sub test()
Dim data As Worksheet
Dim report As Worksheet
Dim finalrow As Integer
Dim finalcol As Integer
Dim rngMatch As Range
Dim i As Integer
Dim countryname As String
Set data = Ark2
Set report = Ark1
countryname = data.Range("A5").Value
report.Range("B2:CC300").ClearContents
data.Select
finalrow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To finalrow
If Cells(i, 1) = countryname Then
Cells(i, 5).Copy
report.Select
Range("B300").End(xlUp).Offset(1, 0).PasteSpecial xlPasteFormulasAndNumberFormats
data.Select
End If
Next i
report.Select
End Sub
There are many flaws here, and it does not come close to solve my problem. Can anyone perhaps point me in the right direction of what to do?
Thank you for your time.

here is a loop that will:
Loop through column A in your main workbook (country names)
Will look up this country in your data workbook
Gets the last used column of the found row (if value is found)
Prints the value in the direct window, obviously you must adjust that piece of code
Sub Test()
Dim RNG1 As Range, CL1 As Range
Dim LR1 As Long, LR2 As Long, LC As Long
LR1 = Workbooks("MainWB").Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
LR2 = Workbooks("DataWB").Sheets(1).Cells(Rows.Count, 1).End(xlUp).Row
Workbooks("DataWB").Activate
Set RNG1 = Workbooks("DataWB").Sheets(1).Range(Cells(1, 1), Cells(LR2, 1))
For X = 3 To LR1
With RNG1
Set CL1 = .Find(What:=Workbooks("MainWB").Sheets(1).Cells(X, 1).Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not CL1 Is Nothing Then
LC = Workbooks("DataWB").Sheets(1).Cells(CL1.Row, Columns.Count).End(xlToLeft) + 1
Debug.Print Workbooks("DataWB").Sheets(1).Cells(CL1.Row, LC).Value 'Do something else with this value obviously
End If
End With
Next X
Workbooks("MainWB").activate
End Sub
You obviously need to adjust all variables and names to your needs. Hopefully you will find bits and pieces usefull.

EDIT - As JvdV pointed out, copy pasting is not really necessary, so I changed the code to report.Sheets[...].Value = data.Sheets[...].Value instead, which is much, much faster. Thank you again, JvdV.
So, with the help of JvdV, I was able to piece together a macro, which works just fine for me.
Sub extract()
Dim RNG1 As Range, CL1 As Range
Dim LR1 As Long, LR2 As Long, LC As Long
Set report = Workbooks("Main.xlsm")
Set data = Workbooks("API_NE.EXP.GNFS.CD_DS2_en_excel_v2_9944773.xls")
report.Sheets("Report").Activate
data.Sheets("Data").Activate
LR1 = report.Sheets("Report").Cells(Rows.Count, 1).End(xlUp).Row
LR2 = data.Sheets("Data").Cells(Rows.Count, 1).End(xlUp).Row
RC2 = report.Sheets("Report").Cells(LR1, Columns.Count).End(xlToLeft).Column + 1
RC3 = RC2 + 1
Set RNG1 = data.Sheets("Data").Range(Cells(1, 1), Cells(LR2, 1))
report.Sheets("Report").Cells(1, RC2).Value = data.Sheets("Data").Cells(5, 3).Value
report.Sheets("Report").Cells(1, RC3).Value = "Year"
For X = 2 To LR1
With RNG1
Set CL1 = .Find(What:=report.Sheets("Report").Cells(X, 1).Value, LookIn:=xlValues, LookAt:=xlWhole)
If Not CL1 Is Nothing Then
LC1 = data.Sheets("Data").Cells(CL1.Row, Columns.Count).End(xlToLeft).Column
If IsNumeric(data.Sheets("Data").Cells(CL1.Row, LC1)) Then
report.Sheets("Report").Cells(LR1, RC2).End(xlUp).Offset(1, 0).Value = data.Sheets("Data").Cells(CL1.Row, LC1).Value
Else
report.Sheets("Report").Cells(LR1, RC2).End(xlUp).Offset(1, 0).Value = "N/A"
End If
If IsNumeric(data.Sheets("Data").Cells(CL1.Row, LC1)) Then
report.Sheets("Report").Cells(LR1, RC3).End(xlUp).Offset(1, 0).Value = data.Sheets("Data").Cells(4, LC1).Value
Else
report.Sheets("Report").Cells(LR1, RC3).End(xlUp).Offset(1, 0).Value = "N/A"
End If
End If
End With
Next X
report.Sheets("Report").Activate
With Worksheets("Report").Columns(RC2)
.NumberFormat = "0.00"
.Value = .Value
End With
With Worksheets("Report").Columns(RC3)
.NumberFormat = "0"
.Value = .Value
End With
End Sub
This macro allows you to extract latest data from a timeseries, as well as the respective year of the datapoint. In this specific macro you can duplicate data on any country, from any spreadsheet provided by the World Bank. All you have to do, is:
plug in the name of your workbook (eg. "Main.xlsm") as well as the name of the workbook from the World Bank (eg. "API_NE.EXP.GNFS.CD_DS2_en_excel_v2_9944773.xls")
Name the countries of your interest in Column A of your own workbook.
Let the macro run
Plug in a new workbook from the World Bank
Let the macro run again
etc.
The macro will not overwrite previous data, but rather duplicate the datapoints and sample years in the right-most columns. An example of the macro in action can be seen below.
Example of the macro

Related

Creating a macro that properly filters data and puts it on another sheet

I have a large dataset that is ordered in a weird way, as in the picture:
This is how my data looks currently
This is what i want it to be like
So mainly I want to do 2 things, first i want to cut the two other columns that display data, and paste them underneath the first column, but only for the first weeks period, and then sort the data, macro recording doesn't work very well since weeks are really months, therefore the amount of days changes per month, hence the height of each column.
My idea is to use a while loop to scroll through the first column (the first one displaying "Day", for each non-number entry (say the first no-greater than zero input), and then cut the whole three block array and paste it somewhere else, say a new sheet called Week "n", given it's the n'th week.
Then properly order this array, copying the two right blocks underneath the first one, and sort them by day and hour.
This I want to do for each data period of a week, but I'm not that well versed on vba's syntax to achieve this, mostly i do not know how to order the array the way im looking to once they are copied to new sheets, neither do i know how to do it if i were not to add new sheets and instead reformat it in place.
Any help is welcome.
Considering your data is set up as per the following image...
Place the following code on a Standard Module like Module1...
Sub TransformWeekData()
Dim sws As Worksheet, dws As Worksheet
Dim lr As Long, dlr As Long, i As Long
Dim Rng As Range
Application.ScreenUpdating = False
Set sws = Sheets("Sheet1") 'Source data sheet
lr = sws.Cells(Rows.Count, 1).End(xlUp).Row
On Error Resume Next
Set dws = Sheets("Combined Data") 'Output Sheet
dws.Cells.Clear
On Error GoTo 0
If dws Is Nothing Then
Set dws = Sheets.Add(after:=sws)
dws.Name = "Combined Data"
End If
On Error Resume Next
For Each Rng In sws.Range("A2:A" & lr).SpecialCells(xlCellTypeConstants, 1).Areas
If dws.Range("A1").Value = "" Then
dlr = 1
Else
dlr = dws.Range("A" & Rows.Count).End(3)(2).Row
End If
dws.Range("A" & dlr).Value = Rng.Cells(1).Offset(-2, 0).Value
dws.Range("A" & dlr + 1 & ":C" & dlr + 1).Value = Array("Day", "Amount", "Hour")
For i = 1 To 9 Step 3
dlr = dws.Range("A" & Rows.Count).End(3)(2).Row
Rng.Offset(, i - 1).Resize(Rng.Cells.Count, 3).Copy dws.Range("A" & dlr)
Next i
Next Rng
dlr = dws.Range("A" & Rows.Count).End(xlUp).Row
For Each Rng In dws.Range("A2:A" & dlr).SpecialCells(xlCellTypeConstants, 1).Areas
Rng.Resize(Rng.Cells.Count, 3).Sort key1:=Rng.Cells(1), order1:=xlAscending, key2:=Rng.Cells(1, 3), order2:=xlAscending, Header:=xlNo
Next Rng
Application.ScreenUpdating = True
End Sub
The code above will insert a sheet called Combined Data if doesn't exist in the workbook with the data in the desired format as shown in the image below...
You may change the output sheet's name as per your requirement.

Sum Values based on unique ID

Just started a new job. I'm automating a month-end report and I'm new at VBA. Been googling most of my issues with success, but I've finally run into a wall. In essence I'm downloading some data from SAP and from there I need to build a report.
My question is: How to do a sumif function using loops in VBA?
Data pull:
Sheet1 contains a product code and purchase amounts (columns A & B) respectively. One product code can have several purchases (several rows with the same product code).
Steps so far:
I arranged the data sheet1 to be in ascending order.
Copied unique values for the product codes onto another sheet (sheet2). So Sheet2 has a list of all the products (in ascending order).
I want to get the sum of all purchases in sheet2 column B (per product code). I know how to do this using formulas, but I need to automate this as much as possible. (+ I'm genuinely interested in figuring this out)
This is what I did in VBA so far:
Sub Macro_test()
Dim tb As Worksheet
Dim tb2 As Worksheet
Dim x As Integer
Dim y As Integer
Dim lrow As Long
Set tb = Sheets("sheet1")
Set tb2 = Sheets("sheet2")
lrow = tb.Cells(Rows.Count, "A").End(xlUp).Row
For x = 2 To lrow
For y = 2 To lrow
If tb2.Cells(x, 1).Value = tb.Cells(y, 1).Value Then
tb2.Cells(x, 2).Value = tb.Cells(y, 2).Value
End If
Next y
Next x
End Sub
If i'm not mistaken, for each product_code in sheet2 col A, I'm looping through all the product codes in sheet1 and getting back the LAST value it finds, instead of the sum of all values... I understand why it doesn't work, I just don't know how to fix it.
Any help would be much appreciated. Thanks!
This statement overwrites the value of tb2.Cells(x, 2).Value at each iteration:
tb2.Cells(x, 2).Value = tb.Cells(y, 2).Value
Instead, I think you need to keep adding to it:
tb2.Cells(x, 2).Value = tb2.Cells(x, 2).Value + tb.Cells(y, 2).Value
But I don't like the looks of your double-loop which uses only one lrow variable to represent the "last row" on the two different worksheets, that could be causing some issues.
Or, in your loop do something like this which I think will avoid the duplicate sum. Still, assumes the second worksheet doesn't initially have any value in
' Base our lRow on Sheet2, we don't care how many rows in Sheet1.
lrow = tb2.Cells(tb2.Rows.Count, 1).End(xlUp).Row
Dim cl as Range
Set cl = tb.Cells(2,1) 'Our initial cell value / ID
For x = 2 to lRow '## Look the rows on Sheet 2
'## Check if the cell on Sheet1 == cell on Sheet2
While cl.Value = tb2.Cells(x,1).Value
'## Add cl.Value t- the tb2 cell:
tb2.Cells(x, 2).Value = tb2.Cells(x, 2).Value + cl.Offset(0,1).Value
Set cl = cl.Offset(1) '## Reassign to the next Row
Wend
Next
But it would be better to omit the double-loop and simply use VBA to do 1 of the following:
1. Insert The Formula:
(See Scott Holtzman's answer).
This approach is better for lots of reasons, not the least of which is that the WorksheetFunction is optimized already, so it should arguably perform better though on a small dataset the difference in runtime will be negligible. The other reason is that it's stupid to reinvent the wheel unless you have a very good justification for doing so, so in this case, why write your own version of code that accomplishes what the built-in SumIf already does and is specifically designed to do?
This approach is also ideal if the reference data may change, as the cell formulas will automatically recalculate based on the data in Sheet1.
2. Evaluate the formula & replace with values only:
If you prefer not to retain the formula, then a simple Value assignment can remove the formula but retain the results:
With .Range(.Range("B2"), .Range("A2").End(xlDown).Offset(, 1))
.FormulaR1C1 = "=SUMIF(Sheet1!C[-1]:C[-1],RC[-1],Sheet1!C:C)"
.Value = .Value 'This line gets rid of the formula but retains the values
End With
Use this approach if you will be removing Sheet1, as removing the referents will break the formula on Sheet2, or if you otherwise want the Sheet2 to be a "snapshot" instead of a dynamic summation.
If you really need this automated, take advantage of VBA to place the formula for you. It's very quick and easy using R1C1 notation.
Complete code (tested):
Dim tb As Worksheet
Dim tb2 As Worksheet
Set tb = Sheets("sheet1")
Set tb2 = Sheets("sheet2")
Dim lrow As Long
lrow = tb.Cells(tb.Rows.Count, 1).End(xlUp).Row
tb.Range("A2:A" & lrow).Copy tb2.Range("A2")
With tb2
.Range("A2").CurrentRegion.RemoveDuplicates 1
With .Range(.Range("B2"), .Range("A2").End(xlDown).Offset(, 1))
.FormulaR1C1 = "=SUMIF(Sheet1!C[-1]:C[-1],RC[-1],Sheet1!C:C)"
End With
End With
Note that with R1C1 notation the C and R are not referring to column or row letters . Rather they are the column and row offsets from the place where the formula is stored on the specific worksheet. In this case Sheet!C[-1] refers to the entire A column of sheet one, since the formula is entered into column B of sheet 2.
I wrote a neat little algorithm (if you can call it that) that does what you want them spits out grouped by totals into another sheet. Basically it loops through the first section to get unique names/labels and stores them into an array. Then it iterates through that array and adds up values if the current iteration matches what the current iteration of the nested loop position.
Private Sub that()
Dim this As Variant
Dim that(9, 1) As String
Dim rowC As Long
Dim colC As Long
this = ThisWorkbook.Sheets("Sheet4").UsedRange
rowC = ThisWorkbook.Sheets("Sheet4").UsedRange.Rows.Count
colC = ThisWorkbook.Sheets("Sheet4").UsedRange.Columns.Count
Dim thisname As String
Dim i As Long
Dim y As Long
Dim x As Long
For i = LBound(this, 1) To UBound(this, 1)
thisname = this(i, 1)
For x = LBound(that, 1) To UBound(that, 1)
If thisname = that(x, 0) Then
Exit For
ElseIf thisname <> that(x, 0) And that(x, 0) = vbNullString Then
that(x, 0) = thisname
Exit For
End If
Next x
Next i
For i = LBound(that, 1) To UBound(that, 1)
thisname = that(i, 0)
For j = LBound(this, 1) To UBound(this, 1)
If this(j, 1) = thisname Then
thisvalue = thisvalue + this(j, 2)
End If
Next j
that(i, 1) = thisvalue
thisvalue = 0
Next i
ThisWorkbook.Sheets("sheet5").Range(ThisWorkbook.Sheets("Sheet5").Cells(1, 1), ThisWorkbook.Sheets("Sheet5").Cells(rowC, colC)).Value2 = that
End Sub
Yay arrays

Select and extract row of data to another sheet

I'm working with big worksheet containing stocks information, with columns organized like this :
ID DATE TIME PRICE QUANTITY NBE
It goes on for 500k+ rows, and I have 10+ sheets to go through. I need to extract only the first two trade of each trading day, and create a new list on a new sheet (Sheet1). The first trade of every day is always at "09:00:00".
So far I wrote this piece of code, in which I tried to copy the two lines I need and then paste them into Sheet1 thus creating the new list. It runs without errors, but nothing shows up...
Sub Macro1()
i = 2
Range("C2").Select
Range(Selection, Selection.End(xlDown)).Select
For Each Cell In Selection
If Day(.Range("B" & cRow).Value) <> Day(.Range("B" & cRow - 1).Value) Then
ActiveCell.EntireRow.Copy
ActiveWorkbook.Sheets("Sheet1").Rows(i).Paste
ActiveCell.Offset(1).Copy
ActiveWorkbook.Sheets("Sheet1").Rows(i + 1).Paste
i = i + 2
End If
Next Cell
End Sub
Shouldn't i select and the copy paste the two rows together? Or is it possible to create a range consisting of 2 rows and 6 columns from the activecell and then copy paste that range?
EDIT 1: It's not working.. I updated it like above, but I still get an error 438 here ActiveWorkbook.Sheets("Sheet1").Rows(i).Paste
EDIT 2: I'm def a big noob. Just realized not every first trade was made at 9:00:00 so i need to select the row based on wether or not one day have passed, and select the first two.
Can I use this condition instead : If Day(Range("B" & cRow).Value) <> Day(Range("B" & cRow - 1).Value) Then ?
I'm betting that your Time column is formatted as a Date/Time field, so you're comparing a string 09:00:00 to a long (date/time) and it's never going to be equal.
Try this:
if Format(Cell.Value, "hh:mm:ss") = "09:00:00" Then
And your English isn't bad at all...
This should do it quickly
make sure your on the sheet with data and run it, and it will copy it onto sheet1 in the same workbook starting at row2
you should make sure sheet1 is empty also , with .clearContents
Sub Macro1()
Dim lngFirstRow As Long
Dim lngLastRow As Long
Dim cRow As Long
Dim shSrc As Worksheet
Dim lngNextDestRow As Long
Dim shDest As Worksheet
Application.ScreenUpdating = False
Set shSrc = ActiveWorkbook.ActiveSheet
Set shDest = ActiveWorkbook.Sheets("Sheet1")
With shSrc
lngFirstRow = 2
lngLastRow = .Cells.Find(What:="*", After:=.Cells.Cells(1), LookAt:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
lngNextDestRow = 2
For cRow = lngFirstRow To lngLastRow Step 1
If Format(.Range("C" & cRow).value, "hh:mm:ss") = "09:00:00" Then
.Rows(cRow).EntireRow.Copy Destination:=shDest.Range("A" & lngNextDestRow )
.Rows(cRow+1).EntireRow.Copy Destination:=shDest.Range("A" & lngNextDestRow+1 )
lngNextDestRow = lngNextDestRow + 2
End If
Next cRow
End With
Application.ScreenUpdating = True
End Sub
When you refrence a sheet using the following line
ActiveWorkbook.Sheets(Sheet1).Rows(i).Paste
Sheet1 is likely a variable that is not defined properly. If "Sheet1" is the actual name of the sheet then enclose it in doublequotes
ActiveWorkbook.Sheets("Sheet1").Rows(i).Paste
After looking at #FreeMan's answer....you should do that first. You'll probably get an error 9 subscript error after you fix what he said to do.

Create loop index and copy data from index worksheets into Master

What I am trying to do is copy variable data ranges, but identical headers, from all sheets and paste into the Master sheet one after the other. The original code (CODE 1 below) renewed the data in the master whenever I clicked on another sheet and back onto the master. The problem now is that there are other sheets in the Workbook that I do not want included in the copy process.
I have edited the code I received below (CODE 2 below) to try and define start and end sheets for running a "loopindex" and also removing the "copy headers" line of code as the headers for each worksheet are appearing throughout the mastersheet. Obviously it does not work and I was wondering if someone could help.
Could you please help me correct the combined code or provide a more elegant solution? Thanks.
Original question here - Excel Forum post
Secondary code from here - Stack post LoopIndex
Original CODE 1
Private Sub Worksheet_Activate()
Dim ws As Worksheet
Application.ScreenUpdating = False
Me.UsedRange.Clear
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> Me.Name Then
If Range("A1") = "" Then ws.Range("A1").EntireRow.Copy Me.Range("A1")'copy in the headers
ws.UsedRange.Offset(1).Copy Me.Range("A" & Rows.Count).End(xlUp).Offset(1)'copy data
End If
Next ws
Application.ScreenUpdating = True
End Sub
Edited CODE 2
Private Sub Worksheet_Activate()
Dim ws As Worksheet
Application.ScreenUpdating = False
Me.UsedRange.Clear
Dim StartIndex, EndIndex, LoopIndex As Integer
StartIndex = Sheets("Master sheet").Index + 1
EndIndex = Sheets("End").Index - 1
For LoopIndex = StartIndex To EndIndex
If Range("A1") = "" Then ws.Range("A1").Offset(1).Copy Me.Range("A" &Rows.Count).End(xlUp).Offset(1) 'copy data
Next LoopIndex
Application.ScreenUpdating = True
End Sub
I can just about understand why you had this as a Worksheet Activate event routine against worksheet "Master list" when there was only one source worksheet. I am having more difficulty in seeing this as convenient when you have multiple source worksheets. I am not asking you to justify your decision since I do not have a full understanding of workbook but you might like to reconsider your approach. I have coded the routine below as an normal macro but you can change this easily if you wish.
I do not like the approach of assuming the worksheets to be loaded are from Sheets("Master sheet").Index + 1 to Sheets("End").Index - 1. I would have thought that was unstable although I have never tried this approach.
I have created a hidden worksheet "Load List":
This lists the worksheets to be loaded in the sequence to be loaded.
I have filled worksheet "Sheet1" with data:
Not very imaginative data but it makes it easy to check that "Master list" is loaded with the correct data. Worksheets "Sheet2" to "Sheet5" have similar data except that the number of data rows vary and "S1" is replaced by "S2", "S3", "S4" and "S5".
After the macro has run, the top of "Master list" contains:
You can see I have loaded all rows from the first worksheet then data rows only from subsequent worksheets.
I do not say a great deal about the VBA I have used. Once you know a statement exists it is normally easy to look it up. Ask if necessary. I hope I have provided an adequate explanation of what the code does. Again ask if necessary.
Option Explicit
Sub CombinedSelected()
Dim ColSrcMax As Long
Dim LoadList As Variant
Dim RowListCrnt As Long
Dim RowListMax As Long
Dim RowMasterNext As Long
Dim RowSrcMax As Long
With Worksheets("Load List")
RowListMax = .Cells(Rows.Count, "A").End(xlUp).Row
' Load the values from column A of worksheet "Load List" to LoadList.
' The statement converts LoadList to a 2 dimensional array. It is the
' equivalent of Redim LoadList(1 To RowListMax, 1 to 1)
LoadList = .Range(.Cells(1, "A"), .Cells(RowListMax, "A")).Value
End With
RowMasterNext = 1
With Worksheets("Master sheet")
.Cells.EntireRow.Delete ' Delete existing contents
End With
For RowListCrnt = 2 To RowListMax
With Worksheets(LoadList(RowListCrnt, 1))
' Find last used row and column containing a value.
' Warning. These statements do not allow for any of the source worksheets being empty
RowSrcMax = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious).Row
ColSrcMax = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByColumns, xlPrevious).Column
If RowListCrnt = 2 Then
' For first source worksheet only include header row
.Range(.Cells(1, 1), .Cells(RowSrcMax, ColSrcMax)).Copy _
Destination:=Worksheets("Master sheet").Cells(RowMasterNext, 1)
RowMasterNext = RowMasterNext + RowSrcMax
Else
' Data rows only to be copied
.Range(.Cells(2, 1), .Cells(RowSrcMax, ColSrcMax)).Copy _
Destination:=Worksheets("Master sheet").Cells(RowMasterNext, 1)
RowMasterNext = RowMasterNext + RowSrcMax - 1
End If
End With
Next
End Sub

Copy multiple rows from one worksheet to another worksheet using macro/vba

I've looked around the forum and played with various options but not found a clear match for my problem:
My task is to copy data from a worksheet (called “workorders”) to a second worksheet (called “Assignments”). The data to be copied is from the “workorders” worksheet starting at cell range “E2, P2:S2”; and also copied from each row (same range) until column “P” is empty – (the number of rows to be copied can vary each time we need to run this macro so we can’t select a standard range) . Then pasted into the “Assignments” worksheet, starting at cell “A4”. I’ve used the forum so far to successfully copy a single row of date (from row 2) – I admit that’s the easy part, and I’ve used various versions of code to achieve this.
I’ve also tried some code (which I found via watching a youtube clip and modifying http://www.youtube.com/watch?v=PyNWL0DXXtQ )to allow me to run a loop which repeats the copy process for each required row in the “workorders” worksheet and then pastes the data into the “assignments” worksheet- but this is where I am not getting it right, I think I’m along the right lines and think I’m not far off but any help would be very useful.
Code examples below (first 2 only copy first row, 3rd example is where I’ve tried to loop and copy multiple rows:
Sub CopyTest1()
' CopyTest1 Macro
'copy data from workorders sheet
'Worksheets("workorders").Range("E2,P2,Q2,R2,S2").Copy
Worksheets("workorders").Range("E2, P2:S2").Copy
'paste data to assignments sheet
'sheets("assigments dc").Range("A4").Paste
Sheets("Assigments DC").Select
Range("A4").Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
Sub CopyTest2()
Sheets("workorders").Range("e2,p2,q2,r2,s2").Copy Sheets("assigments dc").Range("a4")
End Sub
Sub CopyTest3()
Dim xrow As Long
'Dim xrow As String
xrow = 2
Worksheets("workorders").Select
Dim lastrow As Long
lastrow = Cells(Rows.Count, 16).End(xlUp).Row
Do Until xrow = lastrow + 1
ActiveSheet.Cells(xrow, 16).Select
If ActiveCell.Text = Not Null Then
'Range("E2,P2,Q2,R2,S2").Copy
'Selection = Range("E2,P2,Q2,R2,S2").Copy
'Cells(xrow, 5).Copy
Cells(xrow, 5).Copy
Sheets("Assigments DC").Select
Range("A4").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Sheets("workorders").Select
End If
xrow = xrow + 1
Loop
End Sub
Try this:
Sub LoopCopy()
Dim shWO As Worksheet, shAss As Worksheet
Dim WOLastRow As Long, Iter As Long
Dim RngToCopy As Range, RngToPaste As Range
With ThisWorkbook
Set shWO = .Sheets("Workorders") 'Modify as necessary.
Set shAss = .Sheets("Assignments") 'Modify as necessary.
End With
'Get the row index of the last populated row in column P.
'Change accordingly if you want to use another column as basis.
'Two versions of getting the last row are provided.
WOLastRow = shWO.Range("P2").End(xlDown).Row
'WOLastRow = shWO.Range("P" & Rows.Count).End(xlUp).Row
For Iter = 2 to WOLastRow
Set RngToPaste = shAss.Range("A" & (Iter + 2))
With shWO
Set RngToCopy = Union(.Range("E" & Iter), .Range("P" & Iter & ":S" & Iter))
RngToCopy.Copy RngToPaste
End With
Next Iter
End Sub
Read the comments first and test.
Let us know if this helps.
From what I see, you are only copying the cell in Column E. You could correct this by replacing Cells(xrow, 5).Copy with
Union(Sheets("workorders").Cells(xrow,5),Sheets("workorders").Range(Cells(xrow,"P"),Cells(xrow,"S")).Copy
However, using Select and Copy are not ideal. Instead, you can assign the value of the range directly:
Sheets("Assignments DC").Range("A4").Value = Union(Sheets("workorders").Cells(xrow,5),Sheets("workorders").Range(Cells(xrow,"P"),Cells(xrow,"S")).Value
More info on the Union method and why using Select is bad.
Is it even possible to run a line like this?
Worksheets("workorders").Range("E2, P2:S2").Copy
Each time I try different ways to copy/select a range which contains in my case, A3 and the range A34:C40 ("A3, A34:C40").Copy i get an error saying theres to many parameters.. Could this be because I'm running excel 2007?
Any tips or help would be greatly apreciated! :)