I want to copy the contents of two excel in one, and all goes well until I copy the contents of my second excel, because this overwrites what the first copy excel, done that :
These are my statements:
Dim wbOrigen1 As Workbook, _
wbOrigen2 As Workbook, _
wsDestino As Excel.Worksheet, _
wsOrigen1 As Excel.Worksheet, _
wsOrigen2 As Excel.Worksheet, _
rngOrigen1 As Excel.Range, _
rngDestino As Excel.Range, _
rngDestino2 As Excel.Range, _
rngOrigen2 As Excel.Range
Here is the problem
ThisWorkbook.Activate
Set rngDestino2 = wsDestino.Range(celdaDestino,Range(celdaDestino).End(xlDown).Offset(1, 0))
Range(celdaDestino).End(xlDown).Offset(1, 0).Select
wsOrigen2.Activate
rngOrigen2.Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
ThisWorkbook.Activate
rngDestino2.PasteSpecial xlPasteValues
Application.CutCopyMode = False
But this does not work the same way. The problem seems to be with rngDestino2
?rngDestino2
Type Mismatch
?err.Description
Type Mismatch
How I can fix it?
I prefer to avoid select, activate and selection in deference to direct addressing. The paste special, values can also be handled more efficiently by direct cell value transfer.
'make sure that the worksheet vars are set correctly
set wsOrigen2 = <other workbook>.Sheets("Sheet1")
set wsDestino = ThisWorkbook.Sheets("Sheet1")
With wsOrigen2.Cells(1, 1).CurrentRegion
wsDestino.Cells(Rows.Count, 1).End(xlUp) _
.Offset(1, 0).Resize(.Rows.Count, .Columns.Count) = .Cells.Value
End With
set wsDestino = nothing
set wsOrigen2 = nothing
If the workbooks are open and the worksheets are set correctly, that should be all that you really require.
See How to avoid using Select in Excel VBA macros for more methods on getting away from replying on select and activate.
Related
I need your help on something.. I have the 1004 error message (application or object non defined) when running the following code (I put only the critical parts) :
Sub overwrite_CDL()
Dim sht As Worksheet, LastRow As Long
Set sht = ThisWorkbook.Worksheets("JDE_Greece")
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
sht.Activate
Range("M1").AutoFilter Field:=13, Criteria1:="#N/A"
Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Sheets("Mismatches").Select
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats,
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
'we want to create a summary sheet with the matches and the N/A:'
sht.Range("M1").AutoFilter Field:=13, Criteria1:="<>#N/A"
sht.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Select
Selection.Copy
Worksheets.Add(After:=Worksheets("Instructions")).Name = "Summary DRP"
Selection.PasteSpecial Paste:=xlPasteValuesAndNumberFormats,
Operation:=xlNone, SkipBlanks:=False, Transpose:=False
End Sub
Separately, everything works fine (no error messages, good output) but gives me the error 1004 when running together. The sheet I want to add is no created ("Summary DRP") even if the filters are set correctly.
I think the issue is related to the Selection / Copy but I don't know exactly why (I guess something is not defined properly..).
Can someone help me ? Thanks in advance :)
A few things....
Your code is hard to read without indents (that won't cause an error though).
You set your last row on the currently active sheet, which may not be "JDE_Greece".
After finding the last row, then you activate JDE_Greece.
You copy the selection.
You change sheets.
You paste into whatever cells are selected on the Mismatches sheet (K36:Z36 on my sheet).
You try and select the filtered to <>#N/A cells, but you haven't reselected the sheet yet so it can't select the cells and throws a Select Method of Range class failed error.
The moral of this story.... don't use Select.
So your code with nothing removed, but updated with comments:
Sub overwrite_CDL()
Dim sht As Worksheet, LastRow As Long
Dim sht1 As Worksheet, sht2 As Worksheet '\\New variables
Set sht = ThisWorkbook.Worksheets("JDE_Greece")
Set sht1 = ThisWorkbook.Worksheets("Mismatches") '\\Added reference to Mismatches.
LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row '\\Add sheet reference (not really necessary on Rows.Count as row counts should be the same across sheets).
'sht.Activate '\\Don't need to Activate or Select.
sht.Range("M1").AutoFilter Field:=13, Criteria1:="#N/A" '\\Add sheet reference.
sht.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Copy '\\No need to Select, just copy.
'Selection.Copy '\\Don't need this as incorported into above line.
'Sheets("Mismatches").Select
sht1.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False '\\Added sheet and cell reference.
Application.CutCopyMode = False
'we want to create a summary sheet with the matches and the N/A:'
'\\Moved these two lines after the new sheet is created.
'\\sht.Range("M1").AutoFilter Field:=13, Criteria1:="<>#N/A"
'\\sht.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Select
'Selection.Copy '\\Don't need this as incorported into above line.
Set sht2 = ThisWorkbook.Worksheets.Add 'Add worksheet and use variable to reference it.
sht2.Name = "Summary DRP"
sht2.Move After:=ThisWorkbook.Worksheets("Instructions")
'Worksheets.Add(After:=Worksheets("Instructions")).Name = "Summary DRP" '\\This row is now the above 3 rows.
sht.Range("M1").AutoFilter Field:=13, Criteria1:="<>#N/A"
sht.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Copy '\\No need to Select, just copy.
sht2.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats, _
Operation:=xlNone, SkipBlanks:=False, Transpose:=False '\\Added sheet and cell reference.
End Sub
And tidied up:
NB: I've removed the extra arguments you entered in the PasteSpecial - these are default values, so get set as that anyway.
Your code will still fail if 'Summary DRP' already exists.
Sub overwrite_CDL()
Dim sht As Worksheet, LastRow As Long
Dim sht1 As Worksheet, sht2 As Worksheet
Set sht = ThisWorkbook.Worksheets("JDE_Greece")
Set sht1 = ThisWorkbook.Worksheets("Mismatches")
With sht
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
.Range("M1").AutoFilter Field:=13, Criteria1:="#N/A"
.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Copy
End With
sht1.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
Set sht2 = ThisWorkbook.Worksheets.Add
With sht2
.Name = "Summary DRP"
.Move After:=ThisWorkbook.Worksheets("Instructions")
End With
With sht
.Range("M1").AutoFilter Field:=13, Criteria1:="<>#N/A"
.Range("A1:P" & LastRow).SpecialCells(xlCellTypeVisible).Copy
End With
sht2.Range("A1").PasteSpecial Paste:=xlPasteValuesAndNumberFormats
End Sub
I've trawled through a few hours of Google looking for an answer for this, so I apologise if it seems obvious to you, it really isn't to me!
I'm trying to take a cell value from 1 workbook, search for it in another. As a result of that, select some data in the search result's row, copy and paste into a cell in the search term's row in the original workbook.
Here's what I've written:
Sub AutoCableSize()
'
' AutoCableSize Macro
Dim Row As Integer
Dim CableRef As String
Dim Rng As Integer
Rng = 0
Row = 1
CableRef = ""
Windows("170615-Submains Cable Schedule.xlsx").Activate
For Each Cell In Range("F3:F303"):
On Error Resume Next
If CableRef = "Finish" Then
GoTo Finish:
End If
CableRef = Range("F" & Row).Value
Windows("170601-B2-3-HL_BAS_SCH_61_0001.xlsx").Activate
Columns("A:A").Select
Selection.Find(What:=CableRef, LookIn:=xlValues _
, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False).Select
Rng = ActiveCell.Row
If Rng = 1 Then
GoTo Continue
End If
Range("C" & Rng, "D" & Rng).Copy
Windows("170615-Submains Cable Schedule.xlsx").Activate
Range("J" & Row).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Continue:
Row = Row + 1
Next Cell
Finish:
End Sub
What should I put in the Find variables to search for an exact result. I have used xlWhole but I am having an issue:
If the entry does not exist, it skips to the next correctly.
If the entry does exist, it selects the first blank cell in the search series, and treats that as the search result?! I have no idea why!
Try this instead:
Option Explicit
Sub AutoCableSize()
Dim r As Range, findRng As Range
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = Workbooks("170615-Submains Cable Schedule").Worksheets("Sheet1")
Set ws2 = Workbooks("170601-B2-3-HL_BAS_SCH_61_0001").Worksheets("Sheet1")
For Each r In ws1.Range("F3:F303")
Set findRng = ws2.Columns("A:A").Find(What:=r.Value, LookIn:=xlFormulas _
, LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not findRng Is Nothing Then
findRng.Copy
ws1.Range("J" & r.Row).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End If
Next r
End Sub
I've changed your code a lot. The main thing to notice is that I haven't used Activate or Select anywhere. Referring directly to the workbook/worksheet/cell rather than activating it and working with selection is a much better style and it's the first thing to learn if you want to write error-free code.
More here: How to avoid using Select in Excel VBA macros
#CallumDA
In looking at your answer code, I found that in recent Excel versions, it DID NOT FUNCTION correctly - UNLESS you used exactly what the Macro recorder creates:
Set X = {AnyRangeVariableHere}.Find(...) method calls fail universally to return an object instance now, leaving X = Nothing (and failing to find a target, even when a valid one exists).
The only syntax which seems to work is literally:
Set X = Cells.Find(...)
If you look it all up the documents, this distinction makes no sense, but I can assure you that with Excel 2016/2019, this certainly seems to be the case.
Apparently Application.Cells method is some sort of special case/subclass whereby the .Find method actually still functions and returns a range object reference.
I have a code that successfully looks into an external file and copy/pastes the rows that contain that particular condition into the current workbook. For example I am searching for Singapore in the external workbook called Active master project file and copy all the rows containing Singapore to the current workbook that is open.
A problem that occurs is that when I run the same code twice, a border line will exist on the last row of the worksheet. For example when I run the code, it will copy paste the information containing Singapore to the current worksheet called "New Upcoming Projects":
However, when I run the code again it will create a border line on each column such as the image shown below:
And the code that I have for now is:
Sub UpdateNewUpcomingProj()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim copyFrom As Range
Dim lRow As Long '<~~ Not Integer. Might give you error in higher versions of excel
Dim strSearch As String
Set wb1 = Application.Workbooks.Open("U:\Active Master Project.xlsm")
Set ws1 = wb1.Worksheets("New Upcoming Projects")
strSearch = "Singapore"
With ws1
'~~> Remove any filters
.AutoFilterMode = False
'~~> I am assuming that the names are in Col A
'~~> if not then change A below to whatever column letter
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
With .Range("A1:A" & lRow)
.AutoFilter Field:=1, Criteria1:="=*" & strSearch & "*"
Set copyFrom = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
.AutoFilterMode = False
End With
'~~> Destination File
Set wb2 = ThisWorkbook
Set ws2 = wb2.Worksheets("New Upcoming Projects")
With ws2
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lRow = 2
End If
copyFrom.Copy .Rows(lRow)
.Rows.RemoveDuplicates Array(2), xlNo
End With
End Sub
Is there any improvement or additional codes that I have to add in so that the border line would disappear?
As EyePeaSea said you can remove the border by vba code, e.g.
ThisWorkbook.Worksheets("XY").Range("A1", "Z99").Borders.LineStyle = xlNone
In your case the code should be (untested)
copyFrom.Borders.LineStyle = xlNone
after you copied the row
I assume this formatting is coming from the source worksheet. If so, you could PasteSpecial to just paste values, keeping the destination formatting. To do so, simply replace
copyFrom.Copy .Rows(lRow)
with
copyFrom.Copy
.Rows(lRow).PasteSpecial xlPasteValues, xlPasteSpecialOperationNone, False, False
If you do need some formatting from the source sheet, you can use xlPasteAllExceptBorders instead of xlPasteValues.
Paste Special, this will paste to the first empty cell in column A
copyfrom.Copy
ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial xlPasteValues
Application.CutCopyMode = 0
You can add this line after removing the duplicates
.UsedRange.Offset(lRow).Borders.Value = 0
This will remove any borders from the inserted rows
p.s.: I still dont understand where these borders came from, most probably from the original worksheet.. :)
At the end of the code,
please add a new line to format paint of the 3rd row.
So basically before the last two lines
wb1.Select ' please make sure you select the correct one wb1 or wb2 here and try again
Rows("3:3").Select
Selection.Copy
Rows("4:10000").Select
Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Application.CutCopyMode = False
end with
end sub 'This is the last line of your code
I have a workbook that serves as source data for another Excel-based form (not a Userform, just a formatted spreadsheet). The source file has anywhere from 2-40 rows of data - starting from row 18 - and each row needs to be copied into the form and saved separately, i.e. 15 rows from the Source file equates to 15 distinct Form files.
Each cell within the row must be copied separately and pasted to specific cells on the Form. The Source form contains Clients and their relevant info. I am trying to use a macro on the Form to automatically pull line items from the Source file, save the Form as the client's name in a specified folder, and continue until a blank row is reached on the Source file. I have some basic VBA experience, but have little knowledge of loops, variables, or functions, which seem to be my best course of action here.
Here's what I have so far. All I've been able to accomplish is the copy/pasting of the first row from the Source file.
Range("B18").Select
Selection.Copy
Windows("Form.xls").Activate
Range("F7:K7").Select
ActiveSheet.Paste
Windows("Source.xls").Activate
Range("C18").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Processing Form.xls").Activate
Range("D8").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Source.xls").Activate
Range("D18").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Processing Form.xls").Activate
Range("H29").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Source.xls").Activate
Range("E18").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Processing Form.xls").Activate
Range("E29").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Windows("Source.xls").Activate
Range("F18").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Processing Form.xls").Activate
Range("D33").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range(“F7:K7”).Select
Application.CutCopyMode = False
Selection.Copy
ActiveWorkbook.SaveAs
I can't even get my macro to save the Form by the client's name. I also know that my extensive use of "Range" and "Select" will slow my code down to a crawl, I just don't know how to make it more efficient. I've tried using a reference cell to that tells the macro which row of the Source file to copy but haven't had any luck down that road either. Any and all help will be greatly appreciated!
Here's a simple demo:
Note: Not Tested
Option Explicit
Sub CopyToForm()
Dim wbSource As Workbook, wbForm As Workbook
Dim wsSource As Worksheet, wsForm As Worksheet
Dim formpath As String, foldertosavepath as string
Dim lrow As Long, i As Integer
Set wbSource = Thisworkbook '~~> assuming you write your code in Source.xls
Set wsSource = wbSource.Sheets("NameOfYourSheet") '~~> put the source sheet name
'~~> put the path where your form template is saved here
formpath = "C:\Users\Username\FolderName\Processing Form.xls"
'~~> put the path where you want to save individual updated forms.
foldertosavepath = "C:\Users\Username\FolderDestination\"
With wsSource
'~~> get the number of rows with data
lrow = .Range("B" & .Rows.Count).End(xlUp).Row
If lrow < 18 Then Msgbox "No data for transfer": Exit Sub
For i = 18 to lrow
Set wbForm = Workbooks.Open(formpath) '~~> open the form
Set wsForm = wbForm.Sheets("Sheetname") '~~> put the form sheet name
'~~> proceed with the copying
.Range("B" & i).Copy: wsForm.Range("F7:K7").PasteSpecial xlPasteValue
.Range("C" & i).Copy: wsForm.Range("D8").PasteSpecial xlPasteValues
.Range("D" & i).Copy: wsForm.Range("H29").PasteSpecial xlPasteValues
.Range("E" & i).Copy: wsForm.Range("E29").PasteSpecial xlPasteValues
.Range("F" & i).Copy: wsForm.Range("D33").PasteSpecial xlPasteValues
'~~> Save the form using the client name, I assumed it is in B?
wbForm.SaveAs foldertosavepath & .Range("B" & i).Value & ".xls"
wbForm.Close True
Set wbForm = Nothing
Set wsForm = Nothing
Next
End With
End Sub
In above code, I assumed that Form.xls is the same as Processing Form.xls.
This should give you the logic.
I hope this get's you started.
This is not test as I've noted, so if you encounter errors, comment it out.
You are frequently activating the workbooks. that's your code slows down..Below code will work faster
Sub test()
Dim dwb As Workbook
Dim swb As Workbook
Set dwb = Workbooks("Form.xls")
Set swb = Workbooks("Source.xls")
Set awb = Workbooks("Processing Form.xls")
With swb
.ActiveSheet.Range("B18").Copy Destination:=dwb.Sheet1.Range("F7:K7")
.ActiveSheet.Range("C18").Copy Destination:=awb.Sheet1.Range("D8")
.ActiveSheet.Range("D18").Copy Destination:=awb.Sheet1.Range("H29")
.ActiveSheet.Range("e18").Copy Destination:=awb.Sheet1.Range("E29")
.ActiveSheet.Range("F18").Copy Destination:=awb.Sheet1.Range("D33")
End With
End Sub
This might help steer you in the right direction:
Dim i As Long
For i = 1 To 10
With Range("A" & i)
.Copy Workbooks("ToWorkbook.xlsx").Worksheets("Sheet1").Range("B" & i + 9)
.Copy Workbooks("ToAnother.xlsx").Worksheets("Sheet2").Range("C" & i + 8)
.Copy Workbooks("AnotherOne.xlsx").Worksheets("SheetA").Range("D" & i + 2)
End With
Next i
i To 10 is used as a counter to loop through the rows in the source workbook.
For each i, you're taking the range from column A (i.e., with this, do something), copying and pasting it into different cells in different workbooks. In the first round, Range("A1") is being copied into 3 different workbooks at Range("B10"), Range("C9") and Range("D3"), respectively. The next turn, Range("A2") from the source book is going to be copied and pasted into the same destination workbooks from last time, but in Range("B11"), Range("C10") and Range("D4"). It's just a matter of finding the pattern for the different forms you need to paste into.
I get the error "That command cannot be used on multiple selections" when I use a named range in VBA.
VBA is being used to derive a formula which is fine but then I want to just paste the values.
Set rngCopy = rngCopy.Offset(0, 10).SpecialCells(xlCellTypeVisible)
rngCopy.Activate
rngCopy.Value = _
"=IF(RC[-10]="""","""",IF(WEEKDAY(RC[-10])=2,RC[-10]-3,IF(WEEKDAY(RC[-10])<>2,RC[-10]-1)))"
rngCopy.Copy
rngCopy.PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, _
SkipBlanks:=False, _
Transpose:=False
It works for me. Also if your intention is copy paste the formula as values then you don't need to take that long route. You can simply use Application.Evaluate
Sub Sample()
Dim rngCopy As Range
Set rngCopy = Range("A1")
Set rngCopy = rngCopy.Offset(0, 10).SpecialCells(xlCellTypeVisible)
rngCopy.Value = Application.Evaluate( _
"=IF(RC[-10]="""","""",IF(WEEKDAY(RC[-10])=2,RC[-10]-3,IF(WEEKDAY(RC[-10])<>2,RC[-10]-1)))" _
)
End Sub
Testing with Non Contiguous ranges also works.
Sub Sample()
Dim rngCopy As Range
Set rngCopy = Union(Range("A1"), Range("D1"), Range("F1"))
rngCopy.Activate
rngCopy.Value = Application.Evaluate( _
"=IF(RC[-10]="""","""",IF(WEEKDAY(RC[-10])=2,RC[-10]-3,IF(WEEKDAY(RC[-10])<>2,RC[-10]-1)))" _
)
End Sub