Vlookup from another sheet and paste the result in another sheet - excel

I need a help with a vlookup using vba as I was not able to find the solution on the web
The situation is I have three sheets
Sheet 1: Lookup value in cell B3 with a name
Sheet 1
Sheet 2: Lookup table with column name and surname
Sheet 2
Sheet 3: Result of the lookup value in cell B3 with surname
Sheet 3
You can refer to the images for better understanding
So the value in sheet 1 is my lookup value and the surname has to be printed in the sheet 3 and the table array is in sheet 2
The code which I tried is
Sub nameloopkup()
Dim name As String
Dim result As String
Dim myrange As Range
name = Worksheets("Sheet1").Range("B3").Value
myrange = Worksheets("Sheet2").Range("A:B").Value
result = Application.WorksheetFunction.VLookup(name, myrange, 2, False)
' the query does not run and i don't know how can i print the result in sheet 3
End sub
This might be quiet simple for many around here. But considering my amature level to VBA, I need some guidance regarding the same.
Any kind of help or suggestion is appreciated.

Actuall all you need to do is:
Sub nameloopkup()
Dim Name As String
Dim Result As String
Dim SearchIn As Variant 'variant to use it as array
Name = Worksheets("Sheet1").Range("B3").Value
SearchIn = Worksheets("Sheet2").Range("A:B").Value 'read data into array
On Error Resume Next 'next line errors if nothing was found
Result = Application.WorksheetFunction.VLookup(Name, SearchIn, 2, False)
On Error Goto 0
If Result <> vbNullString Then
Worksheets("Sheet3").Range("B3").Value = Result
Else
MsgBox "Nothing found"
End If
End Sub
Alternatively just write a formula:
Sub NameLookUpFormula()
Worksheets("Sheet3").Range("B3").Formula = "=VLOOKUP(Sheet1!B3,Sheet2!A:B,2,FALSE)"
End Sub

Here is what you could 2... There are 2 options, if you only need 1 entry of data, or if you need a whole array of data and picking each time what you need from it:
Option Explicit
Sub nameloopkup()
Dim C As Range, LastRow As Long, EmptyRow As Long, i As Long, arrData
Dim DictData As New Scripting.Dictionary 'You need to check Microsoft Scripting Runtime from references for this
Dim wsNames As Worksheet, wsTable As Worksheet, wsSurnames As Worksheet
'First thing, reference all your sheets
With ThisWorkbook
Set wsNames = .Sheets("Sheet1") 'change this as needed
Set wsTable = .Sheets("Sheet2")
Set wsSurnames = .Sheets("Sheet3")
End With
'Keep all the data in one dictionary:
With wsTable
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row 'last row on Sheet2
i = .Cells(1, .Columns.Count).End(xlToLeft).Column 'last column on Sheet2
arrData = .Range(.Cells(1, 1), .Cells(LastRow, i)).Value 'keep the data on the array
'This will throw an error if there are duplicates
For i = 2 To UBound(arrData)
DictData.Add arrData(i, 1), i 'keep tracking of every name's position ' also change for arrData(i, 2) if you only need the surname
Next i
End With
With wsNames
LastRow = .Cells(.Rows.Count, 2).End(xlUp).Row 'last row on Sheet1
For Each C In .Range("B3:B" & LastRow)
EmptyRow = wsSurnames.Cells(wsSurnames.Rows.Count, 1).End(xlUp).Row
wsSurnames.Cells(EmptyRow, 2) = DictData(C.Value) 'if you used arrData(i, 2) instead i
wsSurnames.Cells(EmptyRow, 2) = arrData(DictData(C.Value), 2) 'If you used i
Next C
End With
End Sub

myrange = Worksheets("Sheet2").Range("A:B").Value
result = Application.WorksheetFunction.VLookup(name, myrange, 2, False)
Here is your error. The second argument of Vlookup is a Range, not a String. As a range is an object, you also need to Set it:
Set myrange = Worksheets("Sheet2").Range("A:B")
result = Application.WorksheetFunction.VLookup(name, myrange, 2, False)

Related

Trying to create a Vlookup formula via VBA Code

I have created a code to use Vlookup formula through VBA but i am stuck that how to fix it. It is very simple to lookup a range but i do not know what to do. Any help will be appreciated.
Sub Example()
Dim value As Range
Dim table As Range
Dim col_index As Range
Dim FinalResult As Variant
lRow = Sheet2.Cells(Rows.Count, 2).End(xlUp).Row
Set value = Sheet2.Range("A2")
Set table = Sheet1.Range("A2:D15")
Set col_index = Sheet2.Range("D2:D" & lRow)
FinalResult = Application.WorksheetFunction.VLookup(value, table, col_index, False)
End Sub
Here is the formula which is working perfectly
=VLOOKUP(Sheet2!A2,Sheet1!$A$2:$D$15,4,FALSE)
Edited
Sub Example()
Dim value As Range
Dim table As Range
Dim col_index As Range
Dim FinalResult As Variant
lRow = Sheet2.Cells(Rows.Count, 2).End(xlUp).Row
Set value = Sheet2.Range("A2")
Set table = Sheet1.Range("A2:D15")
FinalResult = Application.WorksheetFunction.VLookup(value, table, 4, False)
End Sub
Edited but still not working
Sub Example()
Dim rng As Range
Dim table As Range
Dim col_index As Range
Dim FinalResult As Variant
lRow = Sheet2.Cells(Rows.Count, 2).End(xlUp).Row
Set rng = Sheet2.Range("A2")
Set table = Sheet1.Range("A2:D15")
FinalResult = Application.WorksheetFunction.VLookup(rng, table, 4, False)
rng.value = FinalResult.value
End Sub
Assume you have two tables.
Your data table in "Sheet1"
Your output table where you want the result ("Sheet2").
To get the countries from the data sheet ("Sheet1") you would use the formula (I use ";" as separator as I use nordic version of excel):
=VLOOKUP(Sheet2!A2,Sheet1!$A$2:$D$15,4,FALSE)
So in VBA this would look like this:
Sub Example()
Dim tbl As Range
Dim col_index As Range
Dim Lookup_val As Long 'if you use a numerical number as in my example
'Dim Lookup_val As String 'if you use a text or words + numbers as lookup criteria
Dim FinalResult As Variant 'I would consider to use string or long... more specific declaration if you know the datatype to be retrieved.
lRow = Sheet2.Cells(Rows.Count, "B").End(xlUp).Row 'End row in the column we should WRTIE the answer from the vlookup function
EndRow = Sheet2.Cells(Rows.Count, "A").End(xlUp).Row 'End row of the range we would like to MATCH values
Set tbl = Sheet1.Range("A2:D15") 'Data table range
For i = 2 To EndRow 'What range we should loop through. We want to loop from row 2 until the last row in Column A for Sheet2
Lookup_val = Sheet2.Cells(i, "A").value 'Value that should be use as lookup value in the "vlookup function"
FinalResult = Application.WorksheetFunction.VLookup(Lookup_val, tbl, 4, False) 'Perform the vlookup function
Sheet2.Cells(i, "B").value = FinalResult 'write the result of the vlookup finding
Next i 'check next row (go to next lookup value)
End Sub
If the vlookup function can't match a value in the table it will give you an error. I usually fix it dirty by wrapping the function in a error handling line and you need to clear the FinalResult value for each iteration, i.e.:
For i = 2 To EndRow
FinalResult = "" 'To clear previous value from loop iteration
Lookup_val = Sheet2.Cells(i, "A").value
On Error Resume Next 'ignore error if no value found
FinalResult = Application.WorksheetFunction.VLookup(Lookup_val, tbl, 4, False)
On Error GoTo 0 'continue loop anyway
Sheet2.Cells(i, "B").value = FinalResult
Next i

Unable to populate unique values in third sheet comparing the values of the second sheet to the first one

I've got three sheets - main,specimen and output in an excel workbook. The sheet main and speciment contain some information. Some of the information in two sheets are identical but few of them are not. My intention is to paste those information in output which are available in speciment but not in main.
I've tried like [currently it fills in lots of cells producing duplicates]:
Sub getData()
Dim cel As Range, celOne As Range, celTwo As Range
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("main")
Dim ws1 As Worksheet: Set ws1 = ThisWorkbook.Worksheets("specimen")
Dim ws2 As Worksheet: Set ws2 = ThisWorkbook.Worksheets("output")
For Each cel In ws.Range("A2:A" & ws.Cells(Rows.Count, 1).End(xlUp).row)
For Each celOne In ws1.Range("A2:A" & ws1.Cells(Rows.Count, 1).End(xlUp).row)
If cel(1, 1) <> celOne(1, 1) Then ws2.Range("A" & Rows.Count).End(xlUp).Offset(1, 0).value = celOne(1, 1)
Next celOne
Next cel
End Sub
main contains:
UNIQUE ID FIRST NAME LAST NAME
A0000477 RICHARD NOEL AARONS
A0001032 DON WILLIAM ABBOTT
A0290191 REINHARDT WESTER CARLSON
A0290284 RICHARD WARREN CARLSON
A0002029 RAYMOND MAX ABEL
A0002864 DARRYL SCOTT ABLING
A0003916 GEORGES YOUSSEF ACCAOUI
specimen contains:
UNIQUE ID FIRST NAME LAST NAME
A0288761 ROBERT HOWARD CARLISLE
A0290284 RICHARD WARREN CARLSON
A0290688 THOMAS A CARLSTROM
A0002029 RAYMOND MAX ABEL
A0002864 DARRYL SCOTT ABLING
output should contain [EXPECTED]:
UNIQUE ID FIRST NAME LAST NAME
A0288761 ROBERT HOWARD CARLISLE
A0290688 THOMAS A CARLSTROM
How can I achieve that?
If you have the latest version of Excel, with the FILTER function and dynamic arrays, you can do this with an Excel formula.
I changed your Main and Specimen data into tables.
On the Output worksheet you can then enter this formula into a single cell:
=FILTER(specTbl,ISNA(MATCH(specTbl[UNIQUE ID],mnTbl[UNIQUE ID],0)))
The remaining fields will autopopulate with the results.
For a VBA solution, I like to use Dictionaries, and VBA arrays for speed.
'set reference to microsoft scripting runtime
' or use late-binding
Option Explicit
Sub findMissing()
Dim wsMain As Worksheet, wsSpec As Worksheet, wsOut As Worksheet
Dim dN As Dictionary, dM As Dictionary
Dim vMain As Variant, vSpec As Variant, vOut As Variant
Dim I As Long, v As Variant
With ThisWorkbook
Set wsMain = .Worksheets("Main")
Set wsSpec = .Worksheets("Specimen")
Set wsOut = .Worksheets("Output")
End With
'Read data into vba arrays for processing speed
With wsMain
vMain = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=3)
End With
With wsSpec
vSpec = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=3)
End With
'add ID to names dictionary
Set dN = New Dictionary
For I = 2 To UBound(vMain, 1)
dN.Add Key:=vMain(I, 1), Item:=I
Next I
'add missing ID's to missing dictionary
Set dM = New Dictionary
For I = 2 To UBound(vSpec, 1)
If Not dN.Exists(vSpec(I, 1)) Then
dM.Add Key:=vSpec(I, 1), Item:=WorksheetFunction.Index(vSpec, I, 0)
End If
Next I
'write results to output array
ReDim vOut(0 To dM.Count, 1 To 3)
vOut(0, 1) = "UNIQUE ID"
vOut(0, 2) = "FIRST NAME"
vOut(0, 3) = "LAST NAME"
I = 0
For Each v In dM.Keys
I = I + 1
vOut(I, 1) = dM(v)(1)
vOut(I, 2) = dM(v)(2)
vOut(I, 3) = dM(v)(3)
Next v
Dim R As Range
With wsOut
Set R = .Cells(1, 1)
Set R = R.Resize(UBound(vOut, 1) + 1, UBound(vOut, 2))
With R
.EntireColumn.Clear
.Value = vOut
.Style = "Output"
.EntireColumn.AutoFit
End With
End With
End Sub
Both show the same result (except the formula solution does not bring over the column headers; but you can do that with a formula =mnTbl[#Headers] in the cell above the original formula above).
Another option is to join the values of each row in each range and store them in arrays.
Then compare arrays and output the unique values.
In this case, your uniques come from evaluating the whole row, and not just the Unique ID.
Please read code's comments and adjust it to fit your needs.
Public Sub OutputUniqueValues()
Dim mainSheet As Worksheet
Dim specimenSheet As Worksheet
Dim outputSheet As Worksheet
Dim mainRange As Range
Dim specimenRange As Range
Dim mainArray As Variant
Dim specimenArray As Variant
Dim mainFirstRow As Long
Dim specimenFirstRow As Long
Dim outputCounter As Long
Set mainSheet = ThisWorkbook.Worksheets("main")
Set specimenSheet = ThisWorkbook.Worksheets("specimen")
Set outputSheet = ThisWorkbook.Worksheets("output")
' Row at which the output range will be printed (not including headers)
outputCounter = 2
' Process main data ------------------------------------
' Row at which the range to be evaluated begins
mainFirstRow = 2
' Turn range rows into array items
mainArray = ProcessRangeData(mainSheet, mainFirstRow)
' Process specimen data ------------------------------------
' Row at which the range to be evaluated begins
specimenFirstRow = 2
' Turn range rows into array items
specimenArray = ProcessRangeData(specimenSheet, specimenFirstRow)
' Look for unique values and output results in sheet
OutputUniquesFromArrays outputSheet, outputCounter, mainArray, specimenArray
End Sub
Private Function ProcessRangeData(ByVal dataSheet As Worksheet, ByVal firstRow As Long) As Variant
Dim dataRange As Range
Dim evalRowRange As Range
Dim lastRow As Long
Dim counter As Long
Dim dataArray As Variant
' Get last row in sheet (column 1 = column A)
lastRow = dataSheet.Cells(dataSheet.Rows.Count, 1).End(xlUp).Row
' Set the range of specimen sheet
Set dataRange = dataSheet.Range("A" & firstRow & ":C" & lastRow)
' Redimension the array to the number of rows in range
ReDim dataArray(dataRange.Rows.Count)
counter = 0
' Join each row values so it's easier to compare them later and add them to an array
For Each evalRowRange In dataRange.Rows
' Use Trim function if you want to omit the first and last characters if they are spaces
dataArray(counter) = Trim(evalRowRange.Cells(1).Value) & "|" & Trim(evalRowRange.Cells(2).Value) & "|" & Trim(evalRowRange.Cells(3).Value)
counter = counter + 1
Next evalRowRange
ProcessRangeData = dataArray
End Function
Private Sub OutputUniquesFromArrays(ByVal outputSheet As Worksheet, ByVal outputCounter As Long, ByVal mainArray As Variant, ByVal specimenArray As Variant)
Dim specimenFound As Boolean
Dim specimenCounter As Long
Dim mainCounter As Long
' Look for unique values ------------------------------------
For specimenCounter = 0 To UBound(specimenArray)
specimenFound = False
' Check if value in specimen array exists in main array
For mainCounter = 0 To UBound(mainArray)
If specimenArray(specimenCounter) = mainArray(mainCounter) Then specimenFound = True
Next mainCounter
If specimenFound = False Then
' Write values to output sheet
outputSheet.Range("A" & outputCounter).Value = Split(specimenArray(specimenCounter), "|")(0)
outputSheet.Range("B" & outputCounter).Value = Split(specimenArray(specimenCounter), "|")(1)
outputSheet.Range("C" & outputCounter).Value = Split(specimenArray(specimenCounter), "|")(2)
outputCounter = outputCounter + 1
End If
Next specimenCounter
End Sub

Excel VBA Compact method to insert text in offset column based on FIND result

I am writing a small timesaver tool that inserts various text values in a column based on a cell offset of the location of a list-based text search in column C.
Dim C1 As Range
Set C1 = Range("B:B").Find("Value to search")
If C1 Is Nothing Then
Else
C1.Offset(0, -1).Value = "Text value to insert"
End If
I am certain there is a better way to write this relatively simple proc in a more scalable way rather than hard code each value to search in the code, but am not sure how this could be simplified further. I've been looking at the first two lines, and I may be wrong, but I believe a cell range needs to be defined as written in the first two lines in order for the Offset to know the cell location to offset from.
Depends on how you are planning on running this. You could have it as a sub that prompts a user to enter the search value and the text to input at offset. I show that below. It is easy enough instead to adapt to a loop if you have the search and offset strings in the sheet. I use only the populated area of column B for the search. The search values and insert/offset values are held in variables.
Option Explicit
Public Sub AddText()
Dim searchValue As String, insertValue As String, C1 As Range, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
searchValue = Application.InputBox("Please supply search value", Type:=2)
insertValue = Application.InputBox("Please supply insert value", Type:=2)
If searchValue = vbNullString Or insertValue = vbNullString Then Exit Sub 'or loop prompting for entry
With ws
Set C1 = .Range("B1:B" & .Cells(.Rows.Count, "B").End(xlUp).Row).Find(searchValue)
End With
If Not C1 Is Nothing Then C1.Offset(0, -1).Value = insertValue
End Sub
Edit:
From your comment you are actually just doing a VLOOKUP.
In sheet 2 A1 put the following and autofill down for as many rows as are filled in column B.
=IFERROR(VLOOKUP(B1,Sheet1!A:B,2,FALSE),"")
Same thing using arrays and a dictionary
Option Explicit
Public Sub AddText()
Dim wsSource As Worksheet, wsSearch As Worksheet
Dim lookupArray(), updateArray(), lookupDict As Object, i As Long
Set lookupDict = CreateObject("Scripting.Dictionary")
Set wsSource = ThisWorkbook.Worksheets("Sheet1")
Set wsSearch = ThisWorkbook.Worksheets("Sheet2")
With wsSource
lookupArray = .Range("A1:B" & GetLastRow(wsSource, 1)).Value
End With
For i = LBound(lookupArray, 1) To UBound(lookupArray, 1)
lookupDict(lookupArray(i, 1)) = lookupArray(i, 2)
Next
With wsSearch
updateArray = .Range("A1:B" & GetLastRow(wsSearch, 2)).Value
For i = LBound(updateArray, 1) To UBound(updateArray, 1)
If lookupDict.Exists(updateArray(i, 2)) Then
updateArray(i, 1) = lookupDict(updateArray(i, 2))
End If
Next
.Cells(1, 1).Resize(UBound(updateArray, 1), UBound(updateArray, 2)) = updateArray
End With
End Sub
Public Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function

VBA VLOOKUP with dynamic range

I am brand-new to VBA.
I have two worksheets in the same workbook. The first worksheet, shStudentInfo, contains all of the information for each of my students, one row per StudentID (B4 in the code). The second worksheet, shSchedData, contains their schedules where there may be 0-14 rows per StudentID, depending on how many courses each student is taking.
I am attempting to use a loop and VLOOKUP with a dynamic range to extract the course name from each row of shSchedData and copy it to the appropriate cell in shStudentInfo, then move down one row. Currently I've hardcoded cell "CO4" as the appropriate cell although I will also need to make that reference move one cell to the right for each pass through the loop.
Here is my inelegant code:
Option Explicit
Dim MyRow As Long
Sub StudentSchedules()
Dim EndRow As Long
Dim MyRng As Range
shSchedData.Activate
'hard code first row of data set
MyRow = 3
'dynamic code last row of data set
EndRow = shSchedData.Range("A1048575").End(xlUp).Row
'create a dynamic range, a single row from shSchedData
Set MyRng = ActiveSheet.Range(Cells(MyRow, 1), Cells(MyRow, 9))
'Loop through entire data set one line at a time
Do While MyRow <= EndRow
shSchedData.Select
MyRng = ActiveSheet.Range(Cells(MyRow,1),Cells(MyRow,9))
shStudentInfo.Select
'Import course name from shSchedData worksheet
Range("CO4").Select
ActiveCell.Clear
ActiveCell.Formula = "=VLOOKUP(B4,'Schedule Data'!& MyRng,6,0)"
'The above line results in a #NAME? error in CO4 of shStudentInfo
'Also tried:
'ActiveCell.Formula = "=VLOOKUP(B4,'Schedule Data'!& MyRng.Address,6,0)"
'increment counter
MyRow = MyRow + 1
Loop
End Sub
The following rewrite will get your code working to the extent that its purpose can be determined.
The VLOOKUP formula does not appear correct and in any event, there might be a better method of retrieving the data. However, I cannot determine your end purpose from your narrative or code. Sample data together with expected results would help.
Option Explicit
'I see no reason to put this here
'dim myRow As Long
Sub StudentSchedules()
Dim myRow, endRow As Long, myRng As Range
'no need to activate, just With ... End With block it
With shSchedData
'assigned a strarting value
myRow = 3
'dynamic code last row of data set
endRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Loop through entire data set one line at a time
Do While myRow <= endRow
'create a dynamic range, a single row from shSchedData
Set myRng = .Range(.Cells(myRow, 1), .Cells(myRow, 9))
'Import course name from shSchedData worksheet
shStudentInfo.Range("CO4").Offset(0, myRow - 3).Formula = _
"=VLOOKUP(B4, " & myRng.Address(external:=True) & ", 6, false)"
'increment counter
myRow = myRow + 1
Loop
End With
End Sub
I came up with this, see if it fits you
Dim a As Double
Dim b As Double
Dim ml As Worksheet
Dim arrayrng As Variant
Dim i As Integer
Dim x As String
Dim y As String
Set ml = Worksheets("Master Data")
a = ml.Cells(Rows.Count, 11).End(xlUp).Row
b = ml.Cells(Rows.Count, 1).End(xlUp).Row
For i = a To b - 1
a = ml.Cells(Rows.Count, 11).End(xlUp).Row
b = ml.Cells(Rows.Count, 1).End(xlUp).Row
arrayrng = "E" & a + 1
x = "=VLOOKUP(" & arrayrng
y = ",'Data Base'!I:J,2,0)"enter code here
Range("K" & a + 1) = x + y
Next

VBA- How to copy and paste values to another sheet beginning on next available row

I have a vba code that copies rows on a sheet to another sheet depending if column A = 1 and it works perfectly. I am trying to make it paste to the next available row instead of overwriting the data that is already there in order to make a log. Here is the code I have already but I can't seem to figure out how to make it paste to the next available row. Any help would be greatly appreciated! Thanks in advance!
Sub Log()
Dim rng As Range
Dim lastRow As Long
Dim cell As Variant
Dim count As Long
count = 0
With ActiveSheet
lastRow = .Range("A" & .Rows.count).End(xlUp).Row
Set rng = .Range("A3:A" & lastRow)
For Each cell In rng
If cell.Value = "1" Then
Range(cell.Offset(0, 1), cell.Offset(0, 6)).Copy
Range("'Log'!B3").Offset(count, 0).PasteSpecial xlPasteValues
count = count + 1
End If
Next
End With
End Sub
You just need to loop through the source sheet.
Try using .Cells(row,col) instead of Range..
This example is heavy on the comments to help understand the looping process.
You will need a few additional Functions to make this work using this code.
LastRow Function
Function lastRow(sheet As String) As Long
lastRow = Sheets(sheet).Cells(Rows.Count, "A").End(xlUp).Row 'Using Cells()
End Function
LastCol Function
Function lastCol(sheet As String) As Long
lastCol = Sheets(sheet).Cells(2, Columns.Count).End(xlToLeft).Column
End Function
Code for solution: Assuming you have your target sheet's headers already set up AND the target and source sheet share the same formatting.
Sub Log()
Dim source As String, target As String
Dim sRow As Long, col As Long, tRow As Long
'Declare Sheets
source = "Sheet1"
target = "Sheet2"
'Loop through rows of source sheet
For sRow = 2 To lastRow(source)
'Get current last row of Target Sheet
tRow = lastRow(target) + 1
'Meet criteria for Column A to = 1 on Source
If Sheets(source).Cells(sRow, 1) = "1" Then
'Copy each column of source sheet to target sheet in same order
For col = 1 To lastCol(source)
Sheets(target).Cells(tRow, col) = Sheets(source).Cells(sRow, col)
Next col
End If
Next sRow
End Sub

Resources