I'm wanting to use VBA to copy a range of data from one workbook and paste it in another workbook. To know where to paste the information, I search for the next empty row.
The code works successfully until the last portion when trying to copypaste values. I do not get any errors, or any indication of success or failure. I can see it being copied correctly (the marching dots), and the correct cell is selected, but nothing is pasted.
Sub Button1_Click()
Dim wb1 As Workbook
Dim sht As Worksheet
Dim rng As Range
Dim databasewb As Workbook
Dim databasesht As Worksheet
Dim eRow As Integer
'set workbooks to variables
Set databasewb = Workbooks("Aged Debt Data V1.xlsm")
Set wb1 = Workbooks.Open("C:\Users\roanderson\Desktop\Aged debt\Templates\BIO Inc (IO) Template.xlsx")
'select sheet where data lies
Set sht = wb1.Sheets("Conversion to aged debt format")
sht.Activate
'copy range on sheet
Set rng = sht.Range("A2", Range("A2").End(xlDown).End(xlToRight))
rng.Copy
' paste range into database
'activate database workbook
databasewb.Activate
'find next empty row
eRow = Sheet1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Row
MsgBox (eRow)
'paste values into empty row
Sheet1.Cells(eRow, 1).Select
rng.PasteSpecial Paste:=xlPasteValues
wb1.Close
End Sub
The data to be pasted in the Datebase workbook,
When possible, try to avoid using Copy Paste with VBA, as well as avoid using select. Since you just want to copy values, using VBA's Value approach would likely be easier. Modify your line of code where you try to paste special to setting the value. See below
'paste values into empty row
Sheet1.Cells(eRow, 1).Resize(RNG.Rows.Count, RNG.Columns.Count).Value = RNG.Value
wb1.Close
What this is doing starting in Cells(erow,1) the code is using Resize to set the starting range to be the same number of rows and columns or your variable RNG. Then it's just setting the values, the same result as CopyPasteValue only less overhead.
However, if you did want to keep the approach of Copy paste value, then modify your code as such:
'paste values into empty row
Sheet1.Cells(eRow, 1).PasteSpecial Paste:=xlPasteValues
wb1.Close
Change rng.pastespecial to
selection.pastespecial
Performance improvement for copy-paste values. Modular sub.
Bypassing the clipboard is recommended for just Pasting Values. PasteSpecial is less efficient.
See section 8: https://techcommunity.microsoft.com/t5/excel/9-quick-tips-to-improve-your-vba-macro-performance/m-p/173687
Sub CopyPasteSingleCol pastes to PasteFirstRow for Single Column.
sub CopyPasteSingleCol2firstBlank pastes after last blank in column for Single Column.
Sub CopyPasteSingleCol(SrcSheet As Worksheet, ByVal SrcCol As String, ByVal SrcFirstRow As Long, _
PasteSheet As Worksheet, ByVal PasteCol As String, ByVal PasteFirstRow As Long)
Dim SrcLastRow As Long
Dim PasteLastrow As Long
Dim SrcRng As Range
Dim PasteRng As Range
SrcLastRow = SrcSheet.Cells(SrcSheet.Rows.Count, SrcCol).End(xlUp).Row
Set SrcRng = SrcSheet.Range(SrcCol & SrcFirstRow & ":" & SrcCol & SrcLastRow)
Set PasteRng = PasteSheet.Range(PasteCol & PasteFirstRow)
SrcRng.Copy PasteRng
End Sub
Sub CopyPasteSingleCol2firstBlank(SrcSheet As Worksheet, ByVal SrcCol As String, ByVal SrcFirstRow As Long, _
PasteSheet As Worksheet, ByVal PasteCol As String)
Dim SrcLastRow As Long
Dim PasteLastrow As Long
Dim SrcRng As Range
Dim PasteRng As Range
SrcLastRow = SrcSheet.Cells(SrcSheet.Rows.Count, SrcCol).End(xlUp).Row
PasteLastrow = PasteSheet.Cells(PasteSheet.Rows.Count, PasteCol).End(xlUp).Row + 1
' If first row is empty there was not need to add +1 to Lastrow
If PasteSheet.Cells(1, PasteCol) = vbNullString Then PasteLastrow = 1
Set SrcRng = SrcSheet.Range(SrcCol & SrcFirstRow & ":" & SrcCol & SrcLastRow)
Set PasteRng = PasteSheet.Range(PasteCol & PasteLastrow)
SrcRng.Copy PasteRng
End Sub
Sub TESTCopyPasteSingleCol()
Dim SrcSheet As Worksheet
Dim PasteSheet As Worksheet
'Must qualify your Sheet by using Set before calling sub
Set SrcSheet = Workbooks("importGsheettoExcel3.xlsm").Worksheets("SH1")
Set PasteSheet = Workbooks("importGsheettoExcel.xlsm").Worksheets("SH2")
Call CopyPasteSingleCol(SrcSheet, "B", 2, _
PasteSheet, "G", 2)
End Sub
Sub TESTCopyPasteSingleCol2firstBlank()
Dim SrcSheet As Worksheet
Dim PasteSheet As Worksheet
'Must qualify your Sheet by using Set before calling sub
Set SrcSheet = Workbooks("importGsheettoExcel3.xlsm").Worksheets("SH1")
Set PasteSheet = Workbooks("importGsheettoExcel.xlsm").Worksheets("SH2")
Call CopyPasteSingleCol2firstBlank(SrcSheet, "B", 2, _
PasteSheet, "G")
End Sub
Related
I am trying to filter out anything that is below 70% to populate on a separate sheet.
Image of what I am pulling from.
I looked online and got a little code.
Here is what I have and am running into an error.
Private Sub CommandButton1_Click()
lastrow = Worksheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row
For r = 2 To lastrow
If Worksheets("sheet1").Range("O" & r).Value < "70%" Then
Worksheets("sheet1").Rows(r).Copy
Worksheets("sheet2").Activate
lastrowrpt = Worksheets("sheet2").Range("O" & Row.Count).End(xlUp).Row
Worksheets("sheet2").Range("O" & lastrowrpt + 1).Select
ActiveSheet.Paste
End If
Next r
End Sub
This should get you started
In this case you can use the filter and visible cells to copy the range to the other worksheet.
Adjust it to fit your needs
Private Sub CommandButton1_Click()
Dim sourceSheet As Worksheet
Dim sourceRange As Range
Dim sourceFilteredRange As Range
Dim targetSheet As Worksheet
Dim targetCell As Range
Dim cell As Range
Dim sourceLastRow As Long
Dim targetLastRow As Long
' Define source and target objects
Set sourceSheet = ThisWorkbook.Worksheets("Sheet1")
Set targetSheet = ThisWorkbook.Worksheets("Sheet2")
' Get last row of source sheet
sourceLastRow = sourceSheet.Cells(sourceSheet.Rows.Count, "A").End(xlUp).Row
' Get last row of target sheet
targetLastRow = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row + 1
' Set source range
Set sourceRange = sourceSheet.Range("A1:O" & sourceLastRow)
' Filter source range by route and shipped
With sourceRange
.AutoFilter Field:=15, Criteria1:="<70%"
End With
' Get filtered range
Set sourceFilteredRange = sourceRange.SpecialCells(xlCellTypeVisible)
' Copy filtered range to target sheet
sourceFilteredRange.Copy targetSheet.Range("A" & targetLastRow)
End Sub
Let me know if it works
I have a code that should restore range formatting after applying few step.
Sub MyCode()
Sheets("My sheet").ListObjects("My Table").DataBodyRange.Copy
...
refreshing connection and calling function that applies stored formulas to table columns
...
Sheets("My sheet").[A10].PasteSpecial Paste:=xlPasteFormats
End sub
I got error PasteSpecial method on range failed
If I paste immediately, it works.
Is it possible to save range formatting as variable?
Here is an example on how to use variables to store the copy method and use it later. You can set the range to a variable CopyRange and use CopyRange.Copy to store it and later you can use it as the range was stored in the CopyRange and not lost along the way due to other processes running down the line.
Option Explicit
Sub CopyDataToTemplate()
Dim ws As Worksheet
Dim srcWB As Workbook
Dim destWB As Workbook
Dim srcWS As Worksheet
Dim destWS As Worksheet
Dim CopyRange As Variant
Dim i As Long, j As Long
Dim srcLRow As Long, destLRow As Long
Set destWB = Excel.Workbooks("DOLine_example.xlsx")
Set srcWB = ActiveWorkbook
Set srcWS = srcWB.ActiveSheet
Set destWS = destWB.Sheets("DOLine")
srcLRow = srcWS.Cells(srcWS.Rows.Count, "A").End(xlUp).Row
destLRow = destWS.Cells(destWS.Rows.Count, "A").End(xlUp).Row
Application.ScreenUpdating = False
'loop through column 1 to 19
For i = 1 To 19
For j = 1 To 13
'loop through columns
If destWS.Cells(3, i).value = srcWS.Cells(1, j).value Then
' Copy column B to Column D as written in your code above
Set CopyRange = srcWS.Range(Cells(2, j), Cells(srcLRow, j))
CopyRange.Copy
' paste columns from one wb to Columns to another wb
destWS.Cells(destLRow, i).PasteSpecial Paste:=xlPasteAll, Transpose:=False
Application.CutCopyMode = False
End If
Next j
Next i
Application.ScreenUpdating = True
MsgBox "Process completed!", vbInformation
End Sub
I have some code in which I am trying to sort the data set in a csv file based on the content of a cell in another (the main) workbook. Then based on this sort, copy a range of visible cells between the first and sixth columns, but with a dynamic last row thus the range will be dynamic. This dynamic range is then pasted into the main sheet, which will then allow me to do further work on this dataset.
Can't seem to get the sort to work or the dynamic range working. I've tried all sorts of variation on the code below and am looking for some inspiration.
Sub Get_OA_Data()
'Find OA data from source SQL file and copy into serial number generator
Dim ws As Worksheet
Dim wkb2 As Workbook
Dim ws2 As Worksheet
Dim rng As Range
Dim rng2 As Range
Dim LastRow As Long
Dim LastColumn As Long
Dim StartCell As Range
'This section sets the workbooks and worksheets to be used for this macro
Set ws = ThisWorkbook.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srvabdotfpr08\PC_APPS\forum\Gateshead Serialisation\sys_serialisation1.csv")
Set ws2 = wkb2.Worksheets("sys_serialisation1")
Set rng2 = ws.Range("F6")
' This line deletes any content of the cannot assign serial number added previously
ws.Range("I6:I7").ClearContents
'This hides all rows which do not match the desired OA number (found in rng2)
For Each Cell In ws2.Range("A1").End(xlDown)
If Left(Cell.Value, 6) <> rng2.Value Then
Cell.EntireRow.Hidden = True
End If
Next Cell
Set StartCell = ws2.Range("A1")
LastRow = StartCell.SpecialCells(xlCellTypeVisible).Row
LastColumn = StartCell.SpecialCells(xlCellTypeVisible).Column
'This section selects and copies the visible range from csv file into serialisation generator
Set rng = ws2.Range(StartCell.ws2.Cells(LastRow, LastColumn))
rng.Copy
ws.Activate
ws.Range("D12").Select
Selection.PasteSpecial 'Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
Any help would be greatly appreciated, I've bought a couple of books, but none of the stuff in my books is helping with this issue.
P.S I have used very similar code with specific set ranges and it works fine, but this one has me stumped. There may also be an issue with the dataset- which is why I have the LEFT formula in the code (but this seems to work OK).
Try...
Option Explicit
Sub Get_OA_Data()
Dim wkb2 As Workbook
Dim ws As Worksheet, ws2 As Worksheet
Dim rng As Range, xCell As Range
Dim LR As Long, LC As Long, LR2 As Long
Set ws = ThisWorkbook.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srvabdotfpr08\PC_APPS\forum\Gateshead Serialisation\sys_serialisation1.csv")
Set ws2 = wkb2.Worksheets("sys_serialisation1")
ws.Range("I6:I7").ClearContents
LR2 = ws2.Range("A" & ws.Rows.Count).End(xlUp).Row
For Each xCell In ws2.Range("A1:A" & LR2)
xCell.EntireRow.Hidden = Left(xCell.Value, 6) <> ws.Range("F6")
Next xCell
LR = ws2.Range("A" & ws.Rows.Count).End(xlUp).Row
LC = ws2.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Set rng = ws2.Range(ws2.Cells(1, 1), ws2.Cells(LR, LC))
rng.SpecialCells(xlCellTypeVisible).Copy
ws2.Range("D12").PasteSpecial xlPasteValues
End Sub
I want to copy the values from A and B columns of the orders tab of the workbook and paste those values to the Duplicate warning settings tab after the last active row.
Public Sub My_Copy_Orders()
Dim Last_Row As Long
Sheets("Duplicate warning Settings").Select
Last_Row = Range("A1").End(xlDown).Offset(1).Row
Sheets("Orders").Columns("A:B").Copy Destination:=Sheets("Duplicate warning Settings").Range("A" & Last_Row)
End Sub
It gives me an error
You're copying entire columns A & B (all 1,048,576 rows by two columns). Your destination is correctly using only the top-left corner as a reference point but since you are below the first row, you no longer have 1,048,576 rows worth of empty cells below the destination. Essentially you're trying to paste empty cells below the bottom of the worksheet.
Simply limit the source of the copy to the worksheet's usedrange.
with Sheets("Orders")
intersect(.usedrange, .Columns("A:B")).Copy _
Destination:=Sheets("Duplicate warning Settings").Range("A" & Last_Row)
end with
Try below sub
Public Sub My_Copy_Orders()
Dim Last_Row As Range
Dim sht1, sht2 As Worksheet
Dim aRow, bRow As Long
Set sht1 = Sheets("Duplicate warning Settings")
Set sht2 = Sheets("Orders")
Set Last_Row = sht1.Cells(Rows.Count, "A").End(xlUp).Offset(1, 0)
aRow = sht2.Range("A1").End(xlDown).Row
bRow = sht2.Range("B1").End(xlDown).Row
If aRow > bRow Then
sht2.Range("A1:B" & aRow).Copy Last_Row
Else
sht2.Range("A1:B" & bRow).Copy Last_Row
End If
End Sub
Basic code using variables.
Dim wsSrc As Worksheet, wsDest As Worksheet, scrlRow As Long
Set wsSrc = ThisWorkbook.Sheets("Orders")
Set wsDest = ThisWorkbook.Sheets("Duplicate warning Settings")
srclRow = wsSrc.Cells(Rows.Count, 1).End(xlUp).Row
Dim cpyRng As Range
Set cpyRng = Range("A1:B" & srclRow)
cpyRng.Copy wsDest.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Would like to create a Macro to loop through all of the sheets in the workbook and select all the data from each worksheet and then paste said data into a single consolidate table on the "Master" sheet. All sheets have the same column heading to Column "AB".
Currently tried using this code but I have been unable to get anything to paste over onto the Master worksheet. Might be overthinking setting the range each tab.
Just looking for a simple solution to copy all active data from each sheet and paste it into one sheet so that is its all consolidated.
Thanks in advance!
Sub CombineData()
Dim wkstDst As Worksheet
Dim wkstSrc As Worksheet
Dim WB As Workbook
Dim rngDst As Range
Dim rngSrc As Range
Dim DstLastRow As Long
Dim SrcLastRow As Long
'Refrences
Set wkstDst = ActiveWorkbook.Worksheets("Master")
'Setting Destination Range
Set rngDst = wkstDst.Cells(DstLastRow + 1, 1)
'Loop through all sheets exclude Master
For Each wkstSrc In ThisWorkbook.Worksheets
If wkstSrc.Name <> "Master" Then
SrcLastRow = LastOccupiedRowNum(wkstSrc)
With wkstSrc
Set rngSrc = .Range(.Cells(2, 1), .Cells(SrcLastRow, 28))
rngSrc.Copy Destination:=rngDst
End With
DstLastRow = LastOccupiedRowNum(wkstDst)
Set rngDst = wkstDst.Cells(DstLastRow + 1, 1)
End If
Next wkstSrc
End Sub
Throwing another method into the mix. This does assume that the data you are copying has as many rows in column A as it does in any other column. It doesn't require your function.
Sub CombineData()
Dim wkstDst As Worksheet
Dim wkstSrc As Worksheet
Dim rngSrc As Range
Set wkstDst = ThisWorkbook.Worksheets("Master")
For Each wkstSrc In ThisWorkbook.Worksheets
If wkstSrc.Name <> "Master" Then
With wkstSrc
Set rngSrc = .Range(.Cells(2, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(, 28)
rngSrc.Copy Destination:=wkstDst.Cells(Rows.Count, 1).End(xlUp)(2)
End With
End If
Next wkstSrc
End Sub
You have copied this from somewhere else and you have forgotten to copy the function that gets the last row of a worksheet, namely this one LastOccupiedRowNum
So add this function to the same module and the code should work. Please don't forget to mark this as the right answer if it did work:
Function LastOccupiedRowNum(Optional sh As Worksheet, Optional colNumber As Long = 1) As Long
'Finds the last row in a particular column which has a value in it
If sh Is Nothing Then
Set sh = ActiveSheet
End If
LastOccupiedRowNum= sh.Cells(sh.Rows.Count, colNumber).End(xlUp).row
End Function
Try finding the last row dynamically, rather than using .cells
Dim lrSrc as Long, lrDst as Long, i as Long
For i = 1 to Sheets.Count
If Not Sheets(i).Name = "Destination" Then
lrSrc = Sheets(i).Cells( Sheets(i).Rows.Count,"A").End(xlUp).Row
lrDst = Sheets("Destination").Cells( Sheets("Destination").Rows.Count, "A").End(xlUp).Row
With Sheets(i)
.Range(.Cells(2,"A"), .Cells(lrSrc,"AB")).Copy Sheets("Destination").Range(Sheets("Destination").Cells(lrDst+1,"A"),Sheets("Destination").Cells(lrDst+1+lrSrc,"AB"))
End With
End If
Next i
This should replace your sub and the related function.