How to implement user input - vba

I'm just about finished writing this Sub for Excel. I'm basically asking my end user for a total (for example, $3000) find the total amount spent by each customer on the list and report those whose total is more than $3000 (the amount provided by the user) on a new worksheet that I created called Report.
I have this code written so far, which also validates the value entered by the user:
Sub Userinput()
Dim myValue As Variant
myValue = InputBox("Give me some input")
Range("E1").Value = myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
End Sub
Any suggestions on how I can use the inputted value to search through the customer data base and find more than what was inputted and place that in a new worksheet?
EDIT:
Data sample:
Customer orders
Order Date Customer ID Amount purchased
02-Jan-12 190 $580
02-Jan-12 144 $570
03-Jan-12 120 $1,911
03-Jan-12 192 $593
03-Jan-12 145 $332

try this
Sub Userinput()
Dim cl As Range, cl2 As Range, key, myValue
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
dic.comparemode = vbTextCompare
myValue = InputBox("Give me some input")
[E1].Value = "Amount Limit: " & myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
For Each cl In Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row)
If Not dic.exists(cl.Value) Then
dic.Add cl.Value, Nothing
End If
Next cl
Set cl = Range("B2:B" & Cells(Rows.Count, "B").End(xlUp).Row)
Set cl2 = Range("C2:C" & Cells(Rows.Count, "B").End(xlUp).Row)
[E2] = ""
For Each key In dic
If WorksheetFunction.SumIf(cl, key, cl2) > myValue Then
If [E2] = "" Then
[E2] = "Customer ID: " & key
Else
[E2] = [E2] & ";" & key
End If
End If
Next key
Set dic = Nothing
End Sub
output
update
Sub Userinput()
Dim cl As Range, cl2 As Range, key, myValue, i&
Dim dic As Object: Set dic = CreateObject("Scripting.Dictionary")
dic.comparemode = vbTextCompare
myValue = InputBox("Give me some input")
With Sheets("Source")
.[E1].Value = "Amount Limit: " & myValue
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
myValue = CDec(myValue)
For Each cl In .Range("B2:B" & .Cells(.Rows.Count, "B").End(xlUp).Row)
If Not dic.exists(cl.Value) Then
dic.Add cl.Value, Nothing
End If
Next cl
Set cl = .Range("B2:B" & .Cells(.Rows.Count, "B").End(xlUp).Row)
Set cl2 = .Range("C2:C" & .Cells(.Rows.Count, "B").End(xlUp).Row)
Sheets("Destination").UsedRange.ClearContents
Sheets("Destination").[A1] = "Customer ID": i = 2
For Each key In dic
If WorksheetFunction.SumIf(cl, key, cl2) > myValue Then
Sheets("Destination").Cells(i, "A") = key: i = i + 1
End If
Next key
End With
Set dic = Nothing
End Sub
output

You may try this. I assume you need copied into worksheet in same workbook
Option Explicit
Dim MyWorkbook As Workbook
Dim MyWorksheet As Worksheet
Dim MyOutputWorksheet As Worksheet
Sub Userinput()
Set MyWorkbook = Workbooks(ActiveWorkbook.Name)
Set MyWorksheet = MyWorkbook.Sheets("WorksheetName")
Set MyOutputWorksheet = MyWorkbook.Sheets("OutputWorksheetName")
Dim myValue As Long
Dim RowPointer As Long
myValue = InputBox("Give me some input")
MyWorksheet.Range("E1").Value = myValue
'conditional checking
If (Len(myValue) < 0 Or Not IsNumeric(myValue)) Then
MsgBox "Input not valid, code aborted.", vbCritical
Exit Sub
End If
For RowPointer = 2 To MyWorksheet.Cells(Rows.Count, "C").End(xlUp).Row
If MyWorksheet.Range("C" & RowPointer).Value > MyWorksheet.Range("E1").Value Then
MyWorksheet.Range(("A" & RowPointer) & ":C" & RowPointer).Copy Destination:=MyOutputWorksheet.UsedRange.Offset(1, 0)
'MyOutputWorksheet.UsedRange.Offset(1, 0).Value = MyWorksheet.Rows(RowPointer, 1).EntireRow.Value
End If
Next RowPointer
End Sub

Here is another approach which takes advantage of straight forward Excel features to Copy the customer IDs column, RemoveDuplicates, SUMIF based on customer, and Delete those rows over the minimum.
Sub CopyFilterAndCountIf()
Dim dbl_min As Double
dbl_min = InputBox("enter minimum search")
Dim sht_data As Worksheet
Dim sht_out As Worksheet
Set sht_data = ActiveSheet
Set sht_out = Worksheets.Add()
sht_data.Range("B:B").Copy sht_out.Range("A:A")
sht_out.Range("A:A").RemoveDuplicates 1, xlYes
Dim i As Integer
For i = sht_out.UsedRange.Rows.Count To 2 Step -1
If WorksheetFunction.SumIf( _
sht_data.Range("B:B"), sht_out.Cells(i, 1), sht_data.Range("C:C")) < dbl_min Then
sht_out.Cells(i, 1).EntireRow.Delete
End If
Next
End Sub
I don't do error checking on the input, but you can add that in. I am also taking advantage of Excel's willingness to process entire columns instead of dealing with finding ranges. Definitely makes it easier to understand the code.
It should also be mentioned that you can accomplish all of these same features by using a Pivot Table with a filter on the Sum and no VBA.

Related

Trying to combine two VBA programs together

I have two programs for the same Excel spreadsheet and would like to combine them into one program but I just can't seem to get that to work. If anyone could assist it sure would be appreciated. What I have tried is to take the out the Sub do_it() at the second program and the End Sub out of the first program. I have included everything here so you can see both complete programs.
Sub do_it()
n = [E15]
Set reg = CreateObject("VBScript.RegExp")
reg.Pattern = "^[0-9]*\-[0-9]*$"
reg.Global = True
For Each cell In Range("A15:A30,C15:C30,E15:E30,G15:G30,I15:I30")
strVAL = cell.Offset(0, 1).Value
If cell.Value = n And reg.test(strVAL) Then
Range(“E15”).Value = StrVal
MsgBox "Found a postivive result in " & cell.Address
End If
Next
End Sub
-
Sub do_it()
Dim n, sht As Worksheet, cell As Range, num, tmp, rngDest As Range
Set sht = ActiveSheet
n = sht.Range("E15")
For Each cell In sht.Range("A15:A30,C15:C30,E15:E30,G15:G30,I15:I3 0").Cells
tmp = cell.Offset(0, 1).Value
If cell.Value = n And tmp Like "*#-#*" Then
'get the first number
num = CLng(Trim(Split(tmp, "-")(0)))
Debug.Print "Found a positive result in " & cell.Address
'find the next empty cell in the appropriate row
Set rngDest = sht.Cells(num, sht.Columns.Count).End(xlToLeft).Offset(0, 1)
'make sure not to add before col K
If rngDest.Column < 12 Then Set rngDest = sht.Cells(num, 12)
cell.Offset(0, 1).Copy rngDest
Exit For
End If
Next
End Sub
I am not sure what exactly you want to do, but to do multiple things it is better to break it down into smaller subroutines or functions, for example, you should do this. To run both you need to call the sub main. Remember you cannot have duplicate sub or function names:
Sub main()
Call FirstCode
Call SecondCode
End Sub
Sub FirstCode()
n = [E15]
Set reg = CreateObject("VBScript.RegExp")
reg.Pattern = "^[0-9]*\-[0-9]*$"
reg.Global = True
For Each cell In Range("A15:A30,C15:C30,E15:E30,G15:G30,I15:I30")
StrVal = cell.Offset(0, 1).Value
If cell.Value = n And reg.test(StrVal) Then
Range(“E15”).Value = StrVal
MsgBox "Found a postivive result in " & cell.Address
End If
Next
End Sub
Sub SecondCode()
Dim n, sht As Worksheet, cell As Range, num, tmp, rngDest As Range
Set sht = ActiveSheet
n = sht.Range("E15")
For Each cell In sht.Range("A15:A30,C15:C30,E15:E30,G15:G30,I15:I3 0").Cells
tmp = cell.Offset(0, 1).Value
If cell.Value = n And tmp Like "*#-#*" Then
'get the first number
num = CLng(Trim(Split(tmp, "-")(0)))
Debug.Print "Found a positive result in " & cell.Address
'find the next empty cell in the appropriate row
Set rngDest = sht.Cells(num, sht.Columns.Count).End(xlToLeft).Offset(0, 1)
'make sure not to add before col K
If rngDest.Column < 12 Then Set rngDest = sht.Cells(num, 12)
cell.Offset(0, 1).Copy rngDest
Exit For
End If
Next
End Sub

Split data into multiple workbooks based on cell value in Excel using vba

Each month I get our sales report and it contains quantities of goods we sold along with product details, and I created a template using vba where user can specify a product and it can create a excel report for them.
However, I would like to expand/modify so if I have multiple excel reports instead of just one report. I would like excel to separate however many product codes I input or listed.
Now, I added a tab called list in my template which I can list the # of product codes (the 4 digit number, in column A) where vba should read from but I need help on modifying the codes so instead of asking the user, it reads the list instead. Secondly, since master file contains all of the products and I maybe just need 20 or 30 of them, I will need the vba codes to be flexible as possible.
The way i set it up, I am basically updating/copying new info from Master file into Monthly Template and re-saving Monthly Template as product codes product as of 9.1.2017 file.
Sub monthly()
Dim x1 As Workbook, y1 As Workbook
Dim ws1, ws2 As Worksheet
Dim LR3, LR5 As Long
Dim ws3 As Worksheet
Dim Rng3, Rng4 As Range
Dim x3 As Long
Set x1 = Workbooks("Master.xlsx")
Set y1 = Workbooks("Monthly Template.xlsm")
Set ws1 = x1.Sheets("Products")
Set ws2 = y1.Sheets("Products")
Set ws3 = y1.Sheets("List")
ws2.Range("A3:AA30000").ClearContents
ws1.Cells.Copy ws2.Cells
x1.Close True
LR5 = ws3.Cells(Rows.Count, "A").End(xlUp).Row
With y1.Sheets("List")
Range("A1:A32").Sort key1:=Range("A1"), Order1:=xlAscending
End With
LR3 = ws2.Cells(Rows.Count, "A").End(xlUp).Row
Set Rng3 = ws2.Range("AC3:AC" & LR3)
Set Rng4 = ws3.Range("A1:A" & LR5)
For n = 3 To LR3
ws2.Cells(n, 29).FormulaR1C1 = "=LEFT(RC[-21], 4)"
Next n
With y1.Sheets("List")
j = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
With ws2
l = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
For i = 1 To j
For k = 3 To l
If Sheets("List").Cells(i, 1).Value = Sheets("Products").Cells(k, 29).Value Then
With Sheets("Output")
m = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
Sheets("Output").Rows(m + 1).Value = Sheets("Products").Rows(k).Value
End If
Next k
Next i
Sheets("Output").Columns("AC").ClearContents
Dim cell As Range
Dim dict As Object, vKey As Variant
Dim Key As String
Dim SheetsInNewWorkbook As Long
Dim DateOf As Date
DateOf = DateSerial(Year(Date), Month(Date), 1)
With Application
.ScreenUpdating = False
SheetsInNewWorkbook = .SheetsInNewWorkbook
.SheetsInNewWorkbook = 1
End With
Set dict = CreateObject("Scripting.Dictionary")
With ThisWorkbook.Worksheets("List")
For Each cell In .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
Key = Left(cell.Value, 4)
'Store an ArrayList in the Scripting.Dictionary that can be retrieved using the Product Key
If Not dict.exists(Key) Then dict.Add Key, CreateObject("System.Collections.ArrayList")
Next
End With
With Workbooks("Monthly Template.xlsm").Worksheets("Output")
For Each cell In .Range("H2", .Range("A" & .Rows.Count).End(xlUp))
Key = Left(cell.Value, 4)
'Add the Products to the ArrayList in the Scripting.Dictionary that is associated with the Product Key
If dict.exists(Key) Then dict(Key).Add cell.Value
Next
End With
For Each vKey In dict
If dict(vKey).Count > 0 Then
With Workbooks.Add
With .Worksheets(1)
.Name = "Products"
' .Range("A1").Value = "Products"
Workbooks("Monthly Template.xlsm").Worksheets("Output").Cells.Copy Worksheets(1).Cells
For Z = 1 To LR5
For x3 = Rng3.Rows.Count To 1 Step -1
If InStr(1, Rng3.Cells(x3, 1).Text, Workbooks("Monthly Template.xlsm").Worksheets("List").Cells(Z, 1).Text) = 0 Then
Rng3.Cells(x3, 1).EntireRow.Delete
End If
Next x3
Next Z
'.Range("A2").Resize(dict(vKey).Count).Value = Application.Transpose(dict(vKey).ToArray)
End With
.SaveAs Filename:=getMonthlyFileName(DateOf, CStr(vKey)), FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
.Close SaveChanges:=False
End With
End If
Next
With Application
.ScreenUpdating = True
.SheetsInNewWorkbook = SheetsInNewWorkbook
End With
End Sub
Function getMonthlyFileName(DateOf As Date, Product As String) As String
Dim path As String
path = ThisWorkbook.path & "\Product Reports\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
path = path & Format(DateOf, "yyyy") & "\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
path = path & Format(DateOf, "mmm") & "\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
getMonthlyFileName = path & "Product - " & Product & Format(DateOf, " mmm.dd.yyyy") & ".xlsx"
End Function
I seen no reason why to save copies of Monthly Template.xlsm. The OP's code simply creates a list on a worksheet and saves it to file. I might be some formatting missing that would normally get saved over from the Master File.
getMonthlyFileName(DateOf, Product) - creates a file path (Root Path\Year of Date\Month of Date\Product - Prodcut mmm.dd.yyyy.xlsx. In this way, the Product files can be stored in an easy to lookup structure.
Sub CreateMonthlyReports()
Dim cell As Range
Dim dict As Object, vKey As Variant
Dim Key As String
Dim SheetsInNewWorkbook As Long
Dim DateOf As Date
DateOf = DateSerial(Year(Date), Month(Date), 1)
With Application
.ScreenUpdating = False
SheetsInNewWorkbook = .SheetsInNewWorkbook
.SheetsInNewWorkbook = 1
End With
Set dict = CreateObject("Scripting.Dictionary")
With ThisWorkbook.Worksheets("List")
For Each cell In .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
Key = Left(cell.Value, 4)
'Store an ArrayList in the Scripting.Dictionary that can be retrieved using the Product Key
If Not dict.exists(Key) Then dict.Add Key, CreateObject("System.Collections.ArrayList")
Next
End With
With Workbooks("Master.xlsx").Worksheets("Products")
For Each cell In .Range("H2", .Range("H" & .Rows.Count).End(xlUp))
Key = Left(cell.Value, 4)
'Add the Products to the ArrayList in the Scripting.Dictionary that is associated with the Product Key
If dict.exists(Key) Then dict(Key).Add cell.Value
Next
End With
For Each vKey In dict
If dict(vKey).Count > 0 Then
With Workbooks.Add
With .Worksheets(1)
.Name = "Products"
.Range("A1").Value = "Products"
.Range("A2").Resize(dict(vKey).Count).Value = Application.Transpose(dict(vKey).ToArray)
End With
.SaveAs FileName:=getMonthlyFileName(DateOf, CStr(vKey)), FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
.Close SaveChanges:=False
End With
End If
Next
With Application
.ScreenUpdating = True
.SheetsInNewWorkbook = SheetsInNewWorkbook
End With
End Sub
Function getMonthlyFileName(DateOf As Date, Product As String) As String
Dim path As String
path = ThisWorkbook.path & "\Product Reports\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
path = path & Format(DateOf, "yyyy") & "\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
path = path & Format(DateOf, "mmm") & "\"
If Len(Dir(path, vbDirectory)) = 0 Then MkDir path
getMonthlyFileName = path & "Product - " & Product & Format(DateOf, " mmm.dd.yyyy") & ".xlsx"
End Function
Try two loops for this, making sure you sort by the product in the main list to make this a little quicker.
Dim i as Long, j as Long, k as Long, l as Long, m as Long
With Sheets("List")
j = .Cells( .Rows.Count, 1).End(xlUp).Row
End With
With Sheets("Products")
l = .Cells( .Rows.Count, 1).End(xlUp).Row
End With
For i = 2 to j
For k = 2 to l
If Sheets("List").Cells(i,1).Value = Sheets("Products").Cells(k,1).Value Then
With Sheets("Output")
m = .Cells( .Rows.Count, 1).End(xlUp).Row
End With
Sheets("Output").Rows(m+1).Value = Sheets("Products").Rows(k).Value
End If
Next k
Next i
Edit
Will try to piecemeal something to give at least a lead to splitting into different sheets, rather than having one output sheet (this will not be tested, just free-coding):
Dim i as Long, j as Long, k as Long, l as Long, m as Long, n as String
With Sheets("List")
j = .Cells( .Rows.Count, 1).End(xlUp).Row
End With
With Sheets("Products")
l = .Cells( .Rows.Count, 1).End(xlUp).Row
End With
For i = 2 to j
n = Sheets("List").Cells(i,1).Value
Sheets.Add(After:=Sheets(Sheets.Count)).Name = n
Sheets(n).Cells(1,1).Value = n
Sheets(n).Rows(2).Value = Sheets("Products").Rows(1).Value
For k = 2 to l
With Sheets(n)
If .Cells(1,1).Value = Sheets("Products").Cells(k,1).Value Then
m = .Cells( .Rows.Count, 1).End(xlUp).Row
.Rows(m+1).Value = Sheets("Products").Rows(k).Value
End If
Next k
Next i
I don't know why some people doing VBA thinks declaring all the variables with weird names before a thousand lines of code is a good idea.........
Anyways..back to the question, I believe what you are trying to achieve is:
1) Specify a list whilst the code iterates through the list and filters the data based on the listed items.
2) Creates a workbook where the filtered the data is copied over.
3) saving the workbook to somewhere you'll specify, with a specific name.
So naturally, your programme access point should be the one that iterates through the specified list, which should be your main function.
Then inside main function you'll have a Sub that deals with whatever the product ID is, and then filters on your product ID, then copies the data into a newly created workbook.
Last step would be naming the new workbook and saving it close it.
So here is some code skeleton that hopefully will help you with creating the monthly reports. You'll have to write yourself how you want to copy the data from your master workbook to the destination workbook (it should be simple enough, just filter the source list and copy the results to the destination workbook, no dictionary nor arraylist is needed).
Sub main()
Dim rngIdx As Range
Set rngIdx = ThisWorkbook.Sheets("where your list is").Range("A1")
With Application
.DisplayAlerts = False
.ScreenUpdating = False
End With
While (rngIdx.Value <> "")
Call create_report(rngIdx.Value)
Set rngIdx = rngIdx.Offset(1, 0)
Wend
With Application
.DisplayAlerts = True
.ScreenUpdating = True
End With
End Sub
Sub create_report(ByVal product_ID As String)
Dim dest_wbk As Workbook
Set dest_wbk = Workbooks.Add
Call do_whatever(ThisWorkbook, dest_wbk, product_ID)
dest_wbk.SaveAs getMonthlyFileName(some_date, product_ID)
dest_wbk.Close
End Sub
Sub do_whatever(source_wbk As Workbook, dest_wbk As Workbook, ByVal product_ID As String)
' this is the code where you copy from your master data to the destination workbook
' modify sheet names, formatting.......etc.
End Sub

Subscript out of range (error 9) --- running debugger and going through code everything is fine

Basically, have this code which uses Vlookups and a match to find past order dates of a particular product. The sub fills text boxes in a userform with N/A if there are no past orders found in the sheet. Otherwise, finds the latest order and fills the information in the userform.
The program stops when this sub routine is called. Getting 'subscript out of range' (error 9), I run the debugger and go through the code and everything works the way it is supposed to. In both the N/A case and the case where there is past order info.
Sub PastOrderInfo()
Dim wks As Worksheet
Dim Date_Ordered As Variant
Dim PreviousDate As Variant
Dim Qty_Ordered As String
Dim Total_Cost As String
Dim Rng, RngCol As String
Dim Last_Row As Long
Dim i, NewRow As Integer
Set wks = Worksheets("Order Data")
With wks
Last_Row = .UsedRange.Rows(.UsedRange.Rows.count).Row
Rng = "A2:D" & Last_Row
RngCol = "A2:A" & Last_Row
For i = 2 To Last_Row
If i = 2 Then
On Error Resume Next
PreviousDate = Application.VLookup(CStr(ProdNum), .Range(Rng), 2, False)
On Error GoTo 0
If IsError(PreviousDate) Then
Me.TextBox4.Value = "N/A"
Me.TextBox5.Value = "N/A"
Me.TextBox6.Value = "N/A"
Exit Sub
End If
NewRow = Application.Match(CStr(ProdNum), .Range(RngCol), 0) + 2
Rng = "A" & NewRow & ":D" & Last_Row
RngCol = "A" & NewRow & ":A" & Last_Row
ElseIf i > 2 Then
On Error Resume Next
Date_Ordered = Application.VLookup(CStr(ProdNum), .Range(Rng), 2, False)
On Error GoTo 0
If IsError(Date_Ordered) Then
NewRow = NewRow - 1
Rng = "A" & NewRow & ":D" & Last_Row
Me.TextBox4.Value = CDate(PreviousDate)
Me.TextBox5.Value = Application.VLookup(CStr(ProdNum), .Range(Rng), 3, False)
Me.TextBox6.Value = Application.VLookup(CStr(ProdNum), .Range(Rng), 4, False)
Exit Sub
End If
NewRow = Application.Match(CStr(ProdNum), .Range(RngCol), 0) + NewRow
Rng = "A" & NewRow & ":D" & Last_Row
RngCol = "A" & NewRow & ":A" & Last_Row
If Date_Ordered > PreviousDate Then PreviousDate = Date_Ordered
End If
Next i
Me.TextBox4.Value = CDate(PreviousDate)
Me.TextBox5.Value = Application.VLookup(CStr(ProdNum), .Range(Rng), 3, False)
Me.TextBox6.Value = Application.VLookup(CStr(ProdNum), .Range(Rng), 4, False)
End With
End Sub
Here is the line which is the section of code which opens the userform, when I click to debug it highlights the ProDescription.Show line below the if .Range(cellselect)...:
Private Sub CommandButton1_Click()
Dim i, r, c As Integer
Dim wks As Worksheet
Dim cellselect As String
Set wks = Workbooks("Data Direct Orders2.xlsx").Worksheets("Direct Items")
With wks
If ProdNumberCmbBox.ListIndex = -1 Then
Unload Me
ErrorMsg.Show
End
Else
For r = 2 To 84
cellselect = "A" & r
If .Range(cellselect).Text = ProdNum Then
ProDescription.Show
Unload Me
End
End If
Next r
If c = 0 Then
Unload Me
ErrorMsg.Show
End
End If
End If
End With
End Sub
Here is the sub routine where the userform is initialized:
Private Sub UserForm_Initialize()
TextBox8.Value = ProdNum
Call PastOrderInfo
End Sub
Just figured it out.
The line:
Set wks = Worksheets("Order Data")
in
Sub PastOrderInfo()
Was the problem. Needed to specify the workbook, so after adding:
Set wks = Workbooks("VBA - Final Project.xlsm").Worksheets("Order Data")
It worked!

How to select the cell when case is true

First off, just starting trying to learn Excel and VBA yesterday....so bear in mind.
Private Sub CommandButton2_Click()
For a = 1 To myLastRow
Select Case ActiveWorkbook.Sheets("Sheet2").Cells(a, 2).Value
Case Is = myOrderNumber
ActiveWorkbook.Sheets("Sheet2").Cells(a, 2).Active
Case False: MsgBox "False"
End Select
Next a
End Sub
I want to know which cell or the row of the cell that matches my variable. This does not do what I want.......
Thanks guys
I appreciate you are learning code. But beyond getting the range syntax correct two better methods (efficiency wise) are shown below
Array
recut
Private Sub CommandButton2_Click()
Dim myLastRow As Long
Dim myOrderNumber As Long
Dim lngCnt As Long
Dim ws As Worksheet
Dim X
myOrderNumber = 2
Set ws = ActiveWorkbook.Sheets("Sheet2")
X = ws.Range(ws.[b1], ws.[b10])
For lngCnt = 1 To UBound(X)
If X(lngCnt, 1) = myOrderNumber Then MsgBox "True " & lngCnt
Next
End Sub
Evaluate
From Is it possible to fill an array with row numbers which match a certain criteria without looping?
myOrderNumber = 2
MsgBox Join(Filter(Application.Transpose(Application.Evaluate("=IF(B1:B10=" & myOrderNumber & ",ROW(B1:B10),""x"")")), "x", False), ",")
Try this
Private Sub CommandButton2_Click()
Dim myLastRow As Long, a As Long, myOrderNumber As Long
myLastRow = 10
For a = 1 To myLastRow
With ActiveWorkbook.Sheets("Sheet2")
If .Cells(a, 2).Value = myOrderNumber Then
MsgBox "True " & .Cells(a, 2).Row
Else
Msgbox "False"
End If
End With
Next a
End Sub
For a = 1 To myLastRow
With ActiveWorkbook.Sheets("Sheet2")
If .Cells(a, 2).Value = myOrderNumber Then
myRow = .Cells(a, 2).Row
MsgBox "True " & myRow
Else
'MsgBox "False "
End If
End With
Next a

excel vba macro to match cells from two different workbooks and copy and paste accordingly

i have 2 workbooks, workbook A and workbook B. Each workbook has a table. workbook A has 2 columns. All three columns are filled.
product_id
Machine_number and
Workbook B has the same 2 columns but only one column, Product_id, is filled. The other 1 column is vacant.
I need to match the cells of product_id of both workbooks. If the product_id found in workbook A matches workbook B, then the machine number of that product id should be copied from workbook A to workbook B.
I have performed this using this code:
Sub UpdateW2()
Dim w1 As Worksheet, w2 As Worksheet
Dim c As Range, FR As Long
Application.ScreenUpdating = False
Set w1 = Workbooks("workbookA.xlsm").Worksheets("Sheet1")
Set w2 = Workbooks("workbookB.xlsm").Worksheets("Sheet1")
For Each c In w1.Range("A2", w1.Range("A" & Rows.Count).End(xlUp))
FR = 0
On Error Resume Next
FR = Application.Match(c, w2.Columns("A"), 0)
On Error GoTo 0
If FR <> 0 Then w2.Range("C" & FR).Value = c.Offset(, 0)
Next c
Application.ScreenUpdating = True
End Sub
There is a cell that says "machine 4" in product number column. This cell does not get copied and pasted alongside the corresponding product_id value in workbook B.
The rest of the machine numbers for the product ids get copied and pasted accordingly.
These are the screenshots of results
The first screenshot is
Workbook B
The second screenshot is
Workbook A
I have no idea why this happens, can someone please give me the reason for this?
................................................................................
UPDATE
I found that the issue ive descriped in the question arises when the product_id(style_number) repeats.
Say if product_id GE 55950 is present in 2 cells,in both workbooks. Then when i execute the macro only one of the cells is detected.
I tried the coding in both answers but neither solved this problem.
Below is a screenshot of the results.
In the screenshots the cell with machine 7 is not shown. Can someone tell me why this happens?
try this
Sub UpdateW2()
Dim Dic As Object, key As Variant, oCell As Range, i&
Dim w1 As Worksheet, w2 As Worksheet
Set Dic = CreateObject("Scripting.Dictionary")
Set w1 = Workbooks("workbookA.xlsm").Sheets("Sheet1")
Set w2 = Workbooks("workbookB.xlsm").Sheets("Sheet1")
i = w1.Cells.SpecialCells(xlCellTypeLastCell).Row
For Each oCell In w1.Range("D2:D" & i)
If Not Dic.exists(oCell.Value) Then
Dic.Add oCell.Value, oCell.Offset(, -3).Value
End If
Next
i = w2.Cells.SpecialCells(xlCellTypeLastCell).Row
For Each oCell In w2.Range("A2:A" & i)
For Each key In Dic
If oCell.Value = key Then
oCell.Offset(, 2).Value = Dic(key)
End If
Next
Next
End Sub
UPDATE AGAINST NEW REQUIREMENTS
use this
Sub UpdateW2()
Dim key As Variant, oCell As Range, i&, z%
Dim w1 As Worksheet, w2 As Worksheet
Dim Dic As Object: Set Dic = CreateObject("Scripting.Dictionary")
Dim Dic2 As Object: Set Dic2 = CreateObject("Scripting.Dictionary")
Set w1 = Workbooks("workbookA.xlsm").Sheets("Sheet1")
Set w2 = Workbooks("workbookB.xlsm").Sheets("Sheet1")
'-------------------------------------------------------------------------
'get the last row for w1
i = w1.Cells.SpecialCells(xlCellTypeLastCell).Row
'-------------------------------------------------------------------------
' fill dictionary with data for searching
For Each oCell In w1.Range("D2:D" & i)
'row number for duplicates
z = 1: While Dic.exists(oCell.Value & "_" & z): z = z + 1: Wend
'add data with row number to dictionary
If Not Dic.exists(oCell.Value & "_" & z) Then
Dic.Add oCell.Value & "_" & z, oCell.Offset(, -3).Value
End If
Next
'-------------------------------------------------------------------------
'get the last row for w2
i = w2.Cells.SpecialCells(xlCellTypeLastCell).Row
'-------------------------------------------------------------------------
'fill "B" with results
For Each oCell In w2.Range("A2:A" & i)
'determinate row number for duplicated values
z = 1: While Dic2.exists(oCell.Value & "_" & z): z = z + 1: Wend
'search
For Each key In Dic
If oCell.Value & "_" & z = key Then
oCell.Offset(, 2).Value = Dic(key)
End If
Next
'correction of the dictionary in case
'when sheet "A" has less duplicates than sheet "B"
If oCell.Offset(, 2).Value = "" Then
Dic2.RemoveAll: z = 1
For Each key In Dic
If oCell.Value & "_" & z = key Then
oCell.Offset(, 2).Value = Dic(key)
End If
Next
End If
'add to dictionary already passed results for
'the next duplicates testing
If Not Dic2.exists(oCell.Value & "_" & z) Then
Dic2.Add oCell.Value & "_" & z, ""
End If
Next
End Sub
output results below
I tried to replicate your workbooks, I believe they go something like this
Before
After
Code changes are minor,
Sub UpdateW2()
Dim w1 As Worksheet, w2 As Worksheet
Dim c As Range, FR As Long
Application.ScreenUpdating = False
Set w1 = Workbooks("BookOne.xlsm").Worksheets("Sheet1")
Set w2 = Workbooks("BookTwo.xlsm").Worksheets("Sheet1")
For Each c In w1.Range("D2", w1.Range("D" & Rows.Count).End(xlUp))
FR = 0
On Error Resume Next
FR = Application.Match(c, w2.Columns("A"), 0)
On Error GoTo 0
If FR <> 0 Then w2.Range("C" & FR).Value = c.Offset(, -3)
Next c
Application.ScreenUpdating = True
End Sub