Using endxldown function to copy and paste unlimited data - vba

I'm trying to copy and paste data from one workbook into another. This function works when the range is static, but I cannot get it to be dynamic. I know the endxldown function is for this, but how would I work it into my code:
Private Sub CommandButton21_Click()
Dim itemName As String
Dim itemPrice As Single
Dim myData As Workbook
Worksheets("Sheet1").Select
itemName = Range("A2")
Worksheets("Sheet1").Select
itemPrice = Range("B2")
Set myData = Workbooks.Open("C:\Users\Iraj.Masud\Desktop\testing\Master.xlsm")
Worksheets("Sheet1").Select
Worksheets("Sheet1").Range("A1").Select
RowCount = Worksheets("Sheet1").Range("A1").CurrentRegion.Rows.Count
With Worksheets("Sheet1").Range("A1")
.Offset(RowCount, 0) = itemName
.Offset(RowCount, 1) = itemPrice
End With
myData.Save
End Sub
My edits are highlighted in the image below. When I ran the macro, I received an object variable or with block variable not set.
Code with Error

I'd guess:
With Worksheets("Sheet1")
With .Range("A" & .Rows.Count).end(xlUp)
.Offset(1, 0) = itemName
.Offset(1, 1) = itemPrice
End With
End With

try this, (I cleaned up your code), see also the instruction that sets a value to rowcount
Private Sub CommandButton21_Click()
Dim rowcount As Long
Dim myData As Workbook
With Worksheets("Sheet1")
.Range("A2:B" & .Cells(.Rows.Count, 1).End(xlUp).Row).Copy
End With
Set myData = Workbooks.Open("C:\Users\Iraj.Masud\Desktop\testing\Master.xlsm")
With myData.Worksheets("Sheet1")
rowcount = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(rowcount, 1).Paste
End With
myData.Save
End Sub

Use End(xlUp) from the bottom to capture the last row, this is better than using xlDown because the latter will capture the first empty row, not the last row.
Removing all the unnecessary Select stuff and using arrays, your code can be reduced to this:
Private Sub CommandButton21_Click()
With Workbooks.Open("C:\Users\Iraj.Masud\Desktop\testing\Master.xlsm").Sheets("Sheet1")
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(1, 2).Value = _
ThisWorkbook.Sheets("Sheet1").Range("A2:B2").Value2
.Parent.Close True
End With
End Sub
Note that all references are explicit, there is no implicit reference to whichever workbook or worksheet is active. This usually results in safer code.
EDIT
If you want to copy all A:B data from the source, use this:
Private Sub CommandButton21_Click()
Dim src as Range
Set src = ThisWorkbook.Sheets("Sheet1").Range("A2", ThisWorkbook.Sheets("Sheet1").Range("B999999").End(xlUp)
With Workbooks.Open("C:\Users\Iraj.Masud\Desktop\testing\Master.xlsm").Sheets("Sheet1")
.Cells(.Rows.Count, "A").End(xlUp).Offset(1) _
.Resize(src.Rows.Count, src.Columns.Count).Value = src.Value2
.Parent.Close True
End With
End Sub

Private Sub CommandButton21_Click()
Dim itemName As String
Dim itemPrice As Single
Dim wbData As Workbook
Dim wsData As Worksheet
Dim newData As Range
With ThisWorkbook.Worksheets("Sheet1") '<~defines that we are working on sheet1
itemName = .Range("A2") '<~gets the itemname
itemPrice = .Range("B2") '<~gets the itemprice
End With
Set wbData = Workbooks.Open("C:\Users\Iraj.Masud\Desktop\testing\Master.xlsm") '<~opens then workbook
Set wsData = wbData.Worksheets("Sheet1") '<~sets the worksheet
Set newData = wsData.Range("A1048576").End(xlUp).Offset(1, 0) '<~locate last cell and offset 1 row below
With newData '<~defines that we are working with the cell below the last non-blank cell
.Offset(0, 0).Value = itemName '<~passes the item name
.Offset(0, 1).Value = itemPrice '<~passes the item price
End With
Set newData = Nothing '<~post procedure cleaning
Set wsData = Nothing '<~post procedure cleaning
wbData.Save '<~save
wbData.Close
End Sub
This might be a chunky code. But IMO, this is flexible in case you want to change some part/s of the code.

Related

Copy data from one sheet to another in reverse order using vba

I have two sheets in my excel PullData and AllStocks. I would like to copy data from PullData column A and paste the values reverse order into other sheet AllStocks.
Currently, I am using OFFSET function to perform it. But I see a performance issue while running large data set using this method. Is there any better way I can perform this task ?
My CUrrent Code :
Sub GetData()
Dim Main As Worksheet
Dim PullData As Worksheet
Dim AllStocks As Worksheet
Dim i,m As Integer
Set RawImport = Workbooks("vwap.xlsm").Sheets("RawImport")
Set PullData = Workbooks("vwap.xlsm").Sheets("PullData")
m = PullData.Cells(Rows.Count, "A").End(xlUp).Row
For i = 3 To m
AllStocks.Range("A2:A" & i).Formula = "=OFFSET(PullData!$A$" & m & ",-(ROW(PullData!A1)-1),0)"
Next i
End Sub
no loop code:
Option Explicit
Sub GetData()
Dim pullDataVals As Variant
With Workbooks("vwap.xlsm")
With .Sheets("PullData")
pullDataVals = Split(StrReverse(Join(Application.Transpose(.Range("A3", .Cells(.Rows.Count, "A").End(xlUp)).Value), ",")), ",")
End With
.Sheets("RawImport").Range("A2").Resize(UBound(pullDataVals) + 1).Value = Application.Transpose(pullDataVals)
End With
End Sub
just check your sheets names: in your question you're speaking about "PullData and AllStocks" but in your code some RawImport sheet is featuring...
or, in a super compressed style:
Sub GetData()
With Workbooks("vwap.xlsm").Sheets("PullData")
With .Range("A3", .Cells(.Rows.Count, "A").End(xlUp))
.Parent.Parent.Sheets("RawImport").Range("A2").Resize(.Rows.Count).Value = Application.Transpose(Split(StrReverse(Join(Application.Transpose(.Value), ",")), ","))
End With
End With
End Sub
should your data in PullData be a more than one character string or more than one digit number, to prevent what Gary's Student remarked, you could use ArrayList object and its Reverse method:
Sub GetData()
Dim arr As Object
Dim cell As Range
Set arr = CreateObject("System.Collections.Arraylist")
With Workbooks("vwap.xlsm")
With .Sheets("PullData")
For Each cell In .Range("A3", .Cells(.Rows.Count, "A").End(xlUp))
arr.Add cell.Value
Next
End With
arr.Reverse
.Sheets("RawImport").Range("A2").Resize(arr.Count) = Application.Transpose(arr.toarray)
End With
End Sub
This solution applies the INDEX formula to a temporary Name.
Sub Range_ReverseOrder()
Const kFml As String = "=INDEX(_Src,#RowsSrc+#RowTrg-ROW(),1)"
Dim nmSrc As Name, rgTrg As Range
Dim lRows As Long, sFml As String
Rem Set Objects
With Workbooks("vwap.xlsm")
lRows = .Worksheets("PullData").Cells(Rows.Count, 1).End(xlUp).Row
Set nmSrc = .Names.Add(Name:="_Src", _
RefersTo:=.Worksheets("PullData").Cells(2, 1).Resize(-1 + lRows, 1))
.Names("_Src").Comment = "Range_ReverseOrder"
Set rgTrg = .Worksheets("RawImport").Cells(2, 1).Resize(-1 + lRows, 1)
End With
Rem Set Formula
sFml = kFml
sFml = Replace(sFml, "#RowsSrc", nmSrc.RefersToRange.Rows.Count)
sFml = Replace(sFml, "#RowTrg", rgTrg.Row)
Rem Apply Formula
With rgTrg
.Offset(-1).Resize(1).Value = "Reverse.Order"
.Formula = sFml
.Value2 = .Value2
End With
Rem Delete Temporary Name
nmSrc.Delete
End Sub

13 type mismatch error

I'm trying to send data between worksheets. When I run the code below, I get a 13 mismatch error on the IncidentReport variable. On the source sheet these ranges are numerical but one cell is a date (so number, date, number). I have tried to declare the IncidentReport as a string, integer, and long but I keep getting this error. What is the correct variable for this?
Private Sub Update_Click()
Dim AgentName As String
Dim IncidentReport As Long
Dim MyData As Workbook
'Names variable
Worksheets("sheet1").Select
AgentName = Range("C2")
IncidentReport = Range("D1:F1")
'Opens master workbook
Set MyData = Workbooks.Open("C:\Users\ashley.graham\Field_AgentFolder\Incident Reports\Test folder\Incident reports 2018.xlsx")
'Calls sheet and selects cell
Worksheets("Incident Reports").Select
Worksheets("Incident Reports").Range("a1").Select
'finds next blank row for data entry
RowCount = Worksheets("Incident Reports").Range ("A1").CurrentRegion.Rows.Count
With Worksheets("Incident Reports").Range("A1")
.Offset(RowCount, 0) = IncidentReport
.Offset(RowCount, 1) = AgentName
End With
MyData.Save
End Sub
I think this is what you're trying to do:
Private Sub Update_Click()
Dim AgentName As String
Dim IncidentReport As Range
Dim MyData As Workbook
Dim LastRow As Long
With ThisWorkbook.Worksheets("Sheet1")
AgentName = .Range("C2")
Set IncidentReport = .Range("D1:F1")
End With
Set MyData = Workbooks.Open("C:\Users\ashley.graham\Field_AgentFolder\Incident Reports\Test folder\Incident reports 2018.xlsx")
With MyData.Worksheets("Incident Reports")
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(LastRow, 1) = IncidentReport.Cells(1) 'This will put the first cell value here as don't know what you want.
.Cells(LastRow, 2) = AgentName
End With
MyData.Save
End Sub

Faster way to Vlookup and return multiple results?

I have looked for over a day here in Stackoverflow and cannot find an answer to what I am trying to do.
All I need is a vba code that Vlookups and return the multiple results,
Eg; the lookup value is in sheet1 A1, data is in sheet2 columns A1:B40000, match the values in sheet2 A1:A40000 and returns the values from Sheet2 column B1:B40000.
Note:Its possible to find upto 5000 matches in sheet2 A1:A40000.
I have tried several ways to do this, such as Array formula (VERY SLOW), UDF (SLOW), VBA-AutoFilter(SLOW).
Is there any way to do this quickly?
Can anyone help?
Thanks a lot in advance!
Code tested with 40,000 entries, and this completes basically instantly:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim wb As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim vLoookupVal As Variant
Dim vValues As Variant
Dim aResults() As Variant
Dim lResultCount As Long
Dim i As Long
Dim lIndex As Long
Set wb = ActiveWorkbook
Set ws1 = Me 'This is the sheet that contains the lookup value
Set ws2 = wb.Sheets("Sheet2") 'This is the sheet that contains the table of values
Application.EnableEvents = False
If Not Intersect(Target, ws1.Range("A1")) Is Nothing Then
ws1.Columns("B").ClearContents 'Clear previous results
vLoookupVal = Intersect(Target, ws1.Range("A1")).Value
lResultCount = WorksheetFunction.CountIf(ws2.Columns("A"), Target.Value)
If lResultCount = 0 Then
MsgBox "No matches found for [" & vLoookupVal & "]", , "No Matches"
Else
ReDim aResults(1 To lResultCount, 1 To 1)
lIndex = 0
vValues = ws2.Range("A1:B" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row).Value
For i = LBound(vValues, 1) To UBound(vValues, 1)
If vValues(i, 1) = vLoookupVal Then
lIndex = lIndex + 1
aResults(lIndex, 1) = vValues(i, 2)
End If
Next i
ws1.Range("B1").Resize(lResultCount).Value = aResults
End If
End If
Application.EnableEvents = True
End Sub
Maybe your AutoFilter code wasn't like this one?
Private Sub Main()
Dim lookUpVal As Variant
lookUpVal = Worksheets("Sheet1").Range("A1").Value
With Worksheets("Sheet2")
With .Range("A1", .Cells(.Rows.Count, "A").End(xlUp))
If WorksheetFunction.CountIf(.Cells, lookUpVal) = 0 Then Exit Sub
.AutoFilter field:=1, Criteria1:= lookUpVal
.Resize(,2).SpecialCells(xlCellTypeVisible).Copy Worksheets("Sheet1").Range("B1")
End With
.AutoFilterMode= False
End With
End Sub
Pivot table would speed things up and you can use the filter as the search function?

Updating an excel worksheet from another sheet, depending on a value

I am trying to create an If Statement that lets me send an number and a value to another workbook deepening on a value in a 3rd cell (weather the cell is is True or False"). The code that I want to run if the statement is True is below. I have tested this code, and it works, I just want it to happen if the third cell in the row is True. It then needs to carry the information from the number and value rows where the value is true into the function below.
Dim itemName As String
Dim itemPrice As String
Dim myData As Workbook
Worksheets("Sheet1").Select
InvoiceNumber = Range("A2")
qty = Range("B2")
updated = Range("C2")
Set myData = Workbooks.Open("HD:Users:user:Desktop:Inventory.xlsm")
Worksheets("Orders").Select
Worksheets("Orders").Range("a15").Select
RowCount = Worksheets("Orders").Range("a15").CurrentRegion.Rows.Count
With Worksheets("Orders").Range("a15")
.Offset(RowCount, 0) = InvoiceNumber
.Offset(RowCount, 1) = qty
.Offset(RowCount, 2) = updated
End With
Your code looks like it could use another loop to go through a series of rows but I suppose that it may be a case where only a single operation is required.
Dim itemName As String
Dim itemPrice As String
Dim myData As Workbook
Dim sInvoiceNumber As String, dQty As Double, bUpdated As Boolean, iRowCount As Long
With Worksheets("Sheet1")
sInvoiceNumber = .Range("A2").Value
dQty = .Range("B2").Value
bUpdated = CBool(.Range("C2").Value)
If bUpdated Then
Set myData = Workbooks.Open("HD:Users:user:Desktop:Inventory.xlsm")
With myData.Worksheets("Orders").Range("a15")
iRowCount = .CurrentRegion.Rows.Count
.Offset(iRowCount, 0) = sInvoiceNumber
.Offset(iRowCount, 1) = dQty
.Offset(iRowCount, 2) = bUpdated
End With
myData.Close True '<-save and close the workbook
.Range("C2") = Not bUpdated '<- reset the updated field
End If
End With
Rather than loop through the rows, a bulk transfer operation can be used by filtering the data.
Dim itemName As String
Dim itemPrice As String
Dim myData As Workbook
Dim iRowCount As Long
With Worksheets("Sheet1")
If .AutoFilterMode Then AutoFilterMode = False
With .Cells(1, 1).CurrentRegion
.AutoFilter Field:=3, Criteria1:="TRUE"
With .Offset(1, 0).Resize(.Rows.Count - 1, 3)
If CBool(Application.Subtotal(103, .Columns(1))) Then
Set myData = Workbooks.Open("HD:Users:user:Desktop:Inventory.xlsm")
.Cells.Copy Destination:=myData.Sheets("Orders").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
myData.Close True '<-save and close the workbook
.Columns(3).Cells = False
End If
End With
.AutoFilter Field:=3
End With
If .AutoFilterMode Then AutoFilterMode = False
End With
That filters on a worksheet cell value of TRUE in column C.
You should read up on if statements. I'm guessing you'd be able to figure it out from here:
http://www.techonthenet.com/excel/formulas/if_then.php
Basically, just use updated as the test condition in your if statement.
Dim itemName As String
Dim itemPrice As String
Dim myData As Workbook
Worksheets("Sheet1").Select
InvoiceNumber = Range("A2")
qty = Range("B2")
updated = Range("C2")
If updated Then
Set myData = Workbooks.Open("HD:Users:user:Desktop:Inventory.xlsm")
Worksheets("Orders").Select
Worksheets("Orders").Range("a15").Select
RowCount = Worksheets("Orders").Range("a15").CurrentRegion.Rows.Count
With Worksheets("Orders").Range("a15")
.Offset(RowCount, 0) = InvoiceNumber
.Offset(RowCount, 1) = qty
.Offset(RowCount, 2) = updated
End With
End If

Find Matching Data and Paste onto Next Empty Cell on the same row

I am new here. I have been trying to solve this problem but to no avail.
My objectives are:
1) Need to find matching cell in the Installment workbook and paste the data into the next empty cell on the same row as the matching cell. The matching cell will come from Column E.
Private Sub CommandButton1_Click()
Dim itemNumber As String
Dim itemAmount As Single
Dim myData As Workbook
Worksheets("sheet1").Select
itemNumber = Range("B6")
Worksheets("sheet1").Select
itemAmount = Range("H16")
Set myData = Workbooks.Open("C:\Mydata\Installment.xlsx")
Worksheets("sheet1").Select
Worksheets("sheet1").Range("E1").Select
For Each cell In Range(“E2:E10000”)
IF cell.Value = itemNumber Then
Cellvalue = ActiveCell.address
Next
End IF
ColumnCount = Worksheets("sheet1").Range("Cellvalue").CurrentRegion.Columns.Count
With Worksheets("sheet1").Range("Cellvalue")
.Offset(0, ColumnCount) = itemNumber
.End With
myData.Save
Workbooks("Installment.xlsx").Close
End Sub
If I'm understanding you correctly, this should work. I've made a few "tweaks" to your code, primarily removing the "select" statements, which are usually undesirable and unnecessary.
Private Sub CommandButton1_Click()
Dim itemNumber As String
Dim itemAmount As Single
Dim myData As Workbook
Dim Wk As Worksheet
Dim Cel As Range
With ThisWorkbook.Worksheets("sheet1")
itemNumber = .Range("B6").Value
itemAmount = .Range("H16").Value
End With
Set myData = Workbooks.Open("C:\Mydata\Installment.xlsx")
Set Wk = myData.Worksheets("sheet1")
For Each Cel In Wk.Range("E2:E10000")
If Cel.Value = itemNumber Then
Cel.Value = Cel.Address
' get next blank cell in row
Wk.Cells(Cel.Row, Wk.Columns.Count).End(xlToLeft).Offset(, 1).Value = itemNumber
End If
Next
myData.Close True 'save & close
End Sub