Copy varying range from multiple sheets and paste from same row - vba

I am working currently with one workbook and want to implement a preparatory work, copy/pasting all the relevant range from my workbook contained in separate worksheets (3 worksheets at most).
I have the below code to loop through the worksheets, unfortunately I am unable to write the paste-command so as to paste these ranges from the same row successively. I want Transpose:= True. I.E Rgn from sheet1 starting from B2, after last filled cell on the right starts Rgn from Sheet2, after last filled cell starts Rgn from Sheet3 (provided Rgn exists for Sheet3).
Currently, my code overwrites what was copied from previous sheet.
I found a potential reference here (VBA Copy Paste Values From Separate Ranges And Paste On Same Sheet, Same Row Offset Columns (Repeat For Multiple Sheets)) but I am not sure how to use Address nor how the Offset is set in the solution.
' Insert temporary tab
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Sheets(1).Range("D16:D18").Copy
Case 2
lastrow = Sheets(2).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(2).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(2).Range("M9", Sheets(2).Cells(lastrow, lastcol))
Rng.Copy
Case 3
'Check if Range (first col for answers) is not empty
If Worksheetunction.CountA(Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = Sheets(3).Range("A" & Rows.Count).End(xlUp).Row
lastcol = Sheets(3).Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = Sheets(3).Range("L9", Sheets(3).Cells(lastrow, lastcol))
Rng.Copy
End If
End Select
wb.Sheets("Prep").UsedRange.Offset(1,1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing

Can you try this? UsedRange can be unpredictable. You can also have problems if you don't have anything in the first cell of Rng, in which case this code will need adjusting.
I would also prefer to use the sheeet name rather than index.
Sub x()
Dim sh As Worksheet, wb As Workbook, Rng As Range
Set sh = wb.Sheets.Add(after:=wb.Sheets(wb.Sheets.Count))
sh.Name = "Prep"
'Loop
For Each sh In wb.Worksheets
Select Case sh.Index
Case 1
Set Rng = sh.Range("D16:D18")
Case 2
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("M9", sh.Cells(lastrow, lastcol))
Case 3
'Check if Range (first col for answers) is not empty
If WorksheetFunction.CountA(sh.Range("L9:L24")) = 0 Then
Exit For
Else
lastrow = sh.Range("A" & Rows.Count).End(xlUp).Row
lastcol = sh.Cells(9, Columns.Count).End(xlToLeft).Column
Set Rng = sh.Range("L9", sh.Cells(lastrow, lastcol))
End If
End Select
Rng.Copy
wb.Sheets("Prep").Cells(2, Columns.Count).End(xlToLeft).Offset(, 1).PasteSpecial Paste:=xlPasteAll, Transpose:=True
Next
Set sh = Nothing
Set Rng = Nothing
End Sub

Related

Macro to copy-paste range in row to different sheets based on specific cell value

I have a workbook with 3 sheets: first one is the raw data sheet, then 2 target sheets. I would need a macro that would look at cell C in raw data sheet and based on the 2 values (YES or NO), will copy and paste the range A:Y in sheets 2, respectively 3.
Example: if on C2 in raw data sheet i have YES, copy A2:Y2 and paste into sheet 2, same range A2:Y2. If instead i have the value NO, copy A2:Y2 and paste into sheet 3.
Then go to next row and copy-paste A3:Y3 to sheet 2 if YES or A3:Y3 to sheet 3 if NO.
I wrote something that only works for the 2nd row, but i don't know how to make it loop... so basically when it passes to the next rows, it still copies the values from A2:Y2 to the target sheet, instead of copying A3:Y3, A4:Y4 etc..
Pasting my poor code below:
Sub IdentifyInfraction()
Dim rngA As Range
Dim cell As Range
Set rngA = Range("C2", Range("C65536").End(xlUp))
For Each cell In rngA
Worksheets("raw_data").Select
If cell.Value = "YES" Then
Range("A2:Y2").Copy
Worksheets("Value_YES").Select
Range("A2").PasteSpecial Paste:=xlPasteValues
ElseIf cell.Value = "NO" Then
Range("A2:Y2").Copy
Worksheets("Value_NO").Select
Range("A2").PasteSpecial Paste:=xlPasteValues
End If
Next cell
End Sub
Please help!!! :-s
Easiest solution would just be to replace the number 2 in each of your ranges to a variable which you then increment at the end your statement, before you go to the next cell.
For example:
Dim i = 2
Set rngA = Range("C2", Range("C65536").End(xlUp))
For Each cell In rngA
Worksheets("raw_data").Select
If cell.Value = "YES" Then
Range("A" & i & ":Y" & i).Copy
Worksheets("Value_YES").Select
Range("A" & i).PasteSpecial Paste:=xlPasteValues
ElseIf cell.Value = "NO" Then
Range("A" & i & ":Y" & i).Copy
Worksheets("Value_NO").Select
Range("A" & i).PasteSpecial Paste:=xlPasteValues
End If
i = i + 1
Next cell
So, originally we set i = 2, this is to go in line with your starting row of 2 mentioned in your question. Then, Range("A" & i & ":Y" & i).Copy is the same as saying Range("A2:Y2").Copy or Range("A3:Y3").Copy, etc.
This will go through any copy each row, a new row each time, and paste it to the respective row in the various sheets.
I hope this works for what you are trying to do, if not let me know.
There are a few things I'd also recommend looking into. There's a much better way to copy and paste, without going back and forward through the sheets.
ThisWorkbook.Sheets("raw_data").Rows(i).Copy Destination:=Worksheets("Value_YES").Range("A" & i)
Something like this would take the whole row from raw_data and transfer it to Value_YES. You'd have to mess around with it and change the range from Rows(i), but that's just an example.
I'd also recommend that you look into How to avoid using Select in Excel VBA to better understand why it's frowned upon to use Select and Activate in Excel VBA.
My version:
Sub GetR_Done()
Dim rng As Range, c As Range, LstRw As Long
Dim ws As Worksheet, Nr As Long, Yr As Long
Dim Ys As Worksheet, Ns As Worksheet
Set ws = Sheets("raw_data")
Set Ys = Sheets("Value_YES")
Set Ns = Sheets("Value_NO")
With ws
LstRw = .Cells(.Rows.Count, "C").End(xlUp).Row
Set rng = .Range("C2:C" & LstRw)
For Each c In rng.Cells
If c = "YES" Then
With Ys
Yr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
End With
.Range(.Cells(c.Row, "A"), .Cells(c.Row, "Y")).Copy Ys.Range("A" & Yr)
End If
If c = "NO" Then
With Ns
Nr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
End With
.Range(.Cells(c.Row, "A"), .Cells(c.Row, "Y")).Copy Ns.Range("A" & Nr)
End If
Next c
End With
End Sub
If you really require to paste values, then use this one
Sub GetR_Done()
Dim rng As Range, c As Range, LstRw As Long
Dim ws As Worksheet, Nr As Long, Yr As Long
Dim Ys As Worksheet, Ns As Worksheet
Set ws = Sheets("raw_data")
Set Ys = Sheets("Value_YES")
Set Ns = Sheets("Value_NO")
Application.ScreenUpdating = False
With ws
LstRw = .Cells(.Rows.Count, "C").End(xlUp).Row
Set rng = .Range("C2:C" & LstRw)
For Each c In rng.Cells
If c = "YES" Then
With Ys
Yr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
End With
.Range(.Cells(c.Row, "A"), .Cells(c.Row, "Y")).Copy
Ys.Range("A" & Yr).PasteSpecial xlPasteValues
End If
If c = "NO" Then
With Ns
Nr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
End With
.Range(.Cells(c.Row, "A"), .Cells(c.Row, "Y")).Copy
Ns.Range("A" & Nr).PasteSpecial xlPasteValues
End If
Next c
End With
Application.CutCopyMode = False
End Sub
you could try this:
Sub IdentifyInfraction()
Dim cell As Range
With Worksheets("raw_data") 'reference "raw data" sheet
For Each cell In .Range("C2", .cells(.Rows.Count, "C").End(xlUp)) ' loop through referenced sheet column C cells from row 2 down to last not empty one
Worksheets("Value_" & cell.Value).Range(cell.Address).Resize(, 25).Value = cell.Resize(, 25).Value 'have proper target sheet A:Y current cell row values as "raw data" sheet ones
Next
End With
End Sub

VBA: insert a new row before found cell

Below is the code that I'm running, I'm not too sure if I can get what I want.
But strangely, the code is taking too long to run.
I was waiting for it for an hour.
So I figured there must be some errors in the code.
Can anybody shed some light on this?
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range(Cells(1, 1), Cells(lrow, 1))
For Each Acell In rng
If (Acell.Value = "Sum") Then
Acell.Offset(-1, 0).EntireRow.Insert
End If
Next Acell
End If
Next ws
I'm looking for that "Sum" word in Col A, for every sheets in workbook except "master" sheet.
Instead of the For Each loop use a For i = lRow to 1 Step -1 and then use i to access each row: If ws.Cells(i, 1) = "Sum" Then ws.Rows(i).Insert.
When looping from the bottom, then inserting/deleting rows doesn't affect rows above (which are not processed yet) but just rows below (which are already processed).
Dim iRow As Long, lRow As Long
Dim ws As Worksheet
Dim x As Workbook
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
For iRow = lRow To 1 Step -1 'walk through rows from last row (lRow) to first row going upwards (Step -1)
If ws.Cells(iRow, 1) = "Sum" Then
ws.Rows(iRow).Insert xlDown 'insert new row and move other rows down
Exit For 'if there is only one "Sum" you can exit for here (to shorten the run time)
'if there are more that one "Sum" in a sheet then remove that line.
End If
Next iRow
End If
Next ws
When you insert a row and then continue with the loop you will end up on a "Sum"-row again (it has been pushed one row down due to the Insert). Therefore your code will insert row after row after row after row... forever
Try this code (inside the If)... not the best solution perhaps, but it works:
lastrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
R = 1
Do Until R > lastrow
If (ws.Cells(R, 1).Value = "Sum") Then
ws.Cells(R, 1).EntireRow.Insert
R = R + 1 ' Jump one extra step (to skip the inserted row)
lastrow = lastrow+ 1 ' The last row is increased due to the inserted row
End If
R = R + 1
Loop
Since there is only 1 sum in a column
Set x = Workbooks.Open("C:\Users\Desktop\testing.xlsx")
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
lrow = ws.Cells(Rows.Count, "A").End(xlUp).Row
Set rng = ws.Range(Cells(1, 1), Cells(lrow, 1))
For Each Acell In rng
If (Acell.Value = "Sum") Then
Acell.Offset(-1, 0).EntireRow.Insert
exit for
End If
Next Acell
End If
Next ws
try this code.
You are looping through the worksheets but not using each individual worksheet as the parent worksheet to the cells. Without a qualified parent worksheet, each Cells simply defaults to the ActiveSheet.
For Each ws In x.Worksheets
If ws.Name <> "Master" Then
with ws
lrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(lrow, 1))
For Each Acell In rng
If Acell.Value = "Sum" Then
Acell.Offset(-1, 0).EntireRow.Insert
End If
Next Acell
end with
End If
Next ws
Note that you are starting in row 1 and if A1 is Sum then you are trying to insert a row at row 0. There is no row zero.
Have you tried setting Workbook Calculation to Manual, i found this helpful since I tend to work with workbooks with a load of sheets an every sheets has a load of formulas.
File>Options>Formulas
then set Workbook Calculations to manual, but if you want to automate this.
Sub Macro1()
'
' Macro1 Macro
'
' Keyboard Shortcut: Ctrl+e
'
calcu
'your code here
ActiveWorkbook.Application.Calculation = xlCalculationAutomatic
End Sub
'=
Function calcu()
Dim xlCalc As XlCalculation
xlCalc = Application.Calculation
ActiveWorkbook.Application.Calculation = xlCalculationManual
On Error GoTo CalcBack
Exit Function
CalcBack:
ActiveWorkbook.Application.Calculation = xlCalc
End Function
I got this from somewhere in stack but I forgot which post, so if you're the one who did this, thanks. :)

VBA - copy the range in some cells and appear them into other sheet

I want a code that doing the following:
if the last 5 characters of the text value in the cell in column E is “(UK)” then the macro copies the range consisting of 4 cells in columns B,C,D,E in the same row and pastes below the last non-empty row in the worksheet “Sheet 1” in the same columns (so all ranges B-E with “(UK)” must be transferred to the sheet “Sheet1”);
I am just posting my code. Hope #Jonathan will learn it.
Sub CopyC()
Dim wb As Workbook
Dim ws As Worksheet
Dim sheet1lastrow As Long
Dim lastrow As Long
Set wb = ThisWorkbook
Set ws = wb.Worksheets("sheet1")
lastrow = ActiveSheet.Range("E" & Rows.Count).End(xlUp).Row
sheet1lastrow = ws.Range("E" & Rows.Count).End(xlUp).Row
For i = 1 To lastrow
If Right(ActiveSheet.Cells(i, 5).Value, 5) = "(UK)" Then
ActiveSheet.Range(Cells(i, 2), Cells(i, 5)).Copy
ws.Cells(sheet1lastrow + 1, 2).PasteSpecial xlValues
Application.CutCopyMode = False
Application.CutCopyMode = True
End If
Next
End Sub

I want to copy the Some of entire row having same word in the first column as in A3,A4,A5,A6 & paste to another sheet from the vacant rows?

I have some rows in copySheet.sheet1 having some special keyword in first column as "Ojha" . So I want to copy those entire row having "Ojha" in first row & paste it into another pasteSheet.sheet2 . At first I found that cell Having "Ojha". So I put it in Foundcell. So now I used...:
Foundcell.EntireRow.Copy
& in another sheet first I find the vacant rows from where the rows will paste, so
RowCount = WorksheetFunction.CountA(pasteSheet.Range("A:A")) + 1
pasteSheet.Range("A" & RowCount).PasteSpecial xlPasteValues
so it pasted only first row having "Ojha"
So now I want to copy all those rows which are having "Ojha" in the first column & paste to pasteSheet next to next.
If you just want to loop through the cells, this will work
Sub Loopy()
Dim sh As Worksheet, ws As Worksheet
Dim Rws As Long, rng As Range, c As Range
Set sh = Sheets("Sheet1")
Set ws = Sheets("Sheet2")
Application.ScreenUpdating = 0
With sh
Rws = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range(.Cells(1, 1), .Cells(Rws, 1))
End With
With ws
For Each c In rng.Cells
If c = "Ojha" Then
c.EntireRow.Copy
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
End If
Next c
End With
Application.CutCopyMode = 0
End Sub
You can also use an autofilter macro...

Excel vba, compare rows of two workbooks and replace

Here is a bit of background on what I'm trying to achieve.
I have an excel file, which contains 10 sheets and each of the sheets contain many rows of data. This workbook is sent to different people and each one fills in their respective info,only in columns A,B. I have made a vba script which loops through all the filled in workbooks, and checks which rows have cells Ax, Bx filled. Then it copies those in a new workbook.
So what I have right now is:
A workbook which contains only the rows of which the columns A,B have been filled.
A workbook which contains all unfilled rows. (the initial one)
What I want to do now is check row by row, and find e.g. Row 1 of sheet1 of workbook A, minus columns A,B, in workbook's B sheet 1. After the row is found I need to replace workbook's B row with the one from workbook A.
So in the end I will be left with one master workbook (previously workbook B) that will contain both filled and unfilled rows.
I hope I didn't make this too complicated. Any insight on what is the best way to achieve this would be appreciated.
Like I mentioned in my comments, it is possible to use .Find for what you are trying to achieve. The below code sample opens workbooks A and B. It then loops through the values of Col C in Workbook A and tries to find the occurrence of that value in Col C of Workbook B. If a match is found then it compares all columns in that row. And if all columns match then it writes to Col A and Col B of workbook B based on what the value is in workbook A. Once the match is found it uses .FindNext for further matches in Col C.
To test this, Save the files that you gave me as C:\A.xls and C:\B.xls respectively. Now open a new workbook and in a module paste this code. The code is comparing Sheet7 of workbook A with Sheet7 of workbook B
I am sure you can now amend it for rest of the sheets
TRIED AND TESTED (See Snapshot at end of post)
Sub Sample()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim ws1LRow As Long, ws2LRow As Long
Dim i As Long, j As Long
Dim ws1LCol As Long, ws2LCol As Long
Dim aCell As Range, bCell As Range
Dim SearchString As String
Dim ExitLoop As Boolean, matchFound As Boolean
'~~> Open File 1
Set wb1 = Workbooks.Open("C:\A.xls")
Set ws1 = wb1.Sheets("sheet7")
'~~> Get the last Row and Last Column
With ws1
ws1LRow = .Range("C" & .Rows.Count).End(xlUp).Row
ws1LCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
'~~> Open File 2
Set wb2 = Workbooks.Open("C:\B.xls")
Set ws2 = wb2.Sheets("sheet7")
'~~> Get the last Row and Last Column
With ws2
ws2LRow = .Range("C" & .Rows.Count).End(xlUp).Row
ws2LCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
'~~> Loop Through Cells of Col C in workbook A and try and find it
'~~> in Col C of workbook 2
For i = 2 To ws1LRow
SearchString = ws1.Range("C" & i).Value
Set aCell = ws2.Columns(3).Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
ExitLoop = False
'~~> If match found
If Not aCell Is Nothing Then
Set bCell = aCell
matchFound = True
'~~> Then compare all columns
For j = 4 To ws1LCol
If ws1.Cells(i, j).Value <> ws2.Cells(aCell.Row, j).Value Then
matchFound = False
Exit For
End If
Next
'~~> If all columns matched then wrtie to Col A/B
If matchFound = True Then
ws2.Cells(aCell.Row, 1).Value = ws1.Cells(i, 1).Value
ws2.Cells(aCell.Row, 2).Value = ws1.Cells(i, 2).Value
End If
'~~> Find Next Match
Do While ExitLoop = False
Set aCell = ws2.Columns(3).FindNext(After:=aCell)
'~~> If match found
If Not aCell Is Nothing Then
If aCell.Address = bCell.Address Then Exit Do
matchFound = True
'~~> Then compare all columns
For j = 4 To ws1LCol
If ws1.Cells(i, j).Value <> ws2.Cells(aCell.Row, j).Value Then
matchFound = False
Exit For
End If
Next
'~~> If all columns matched then wrtie to Col A/B
If matchFound = True Then
ws2.Cells(aCell.Row, 1).Value = ws1.Cells(i, 1).Value
ws2.Cells(aCell.Row, 2).Value = ws1.Cells(i, 2).Value
End If
Else
ExitLoop = True
End If
Loop
End If
Next
End Sub
SNAPSHOT
BEFORE
AFTER