As you see on the above picture:
I need to match the values on Wb1.coumns(1) with the other workbook Wb2.coumns(1) with some conditions.
Wb2 will be filtered of the value Close at column M.
Then I seek the latest closing date and get it’s respective value at column B and input that value in Wb1.column(K).
the below code may work on the provided example correctly, But it is not reliable on my actual dataset,
because it depends on the sort of many columns from oldest to newest.
This is a link for the provided sample
Sub Get_the_respective_value_of_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range
Dim arr1() As Variant, arr2() As Variant
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open("Path of wb2", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng1 = ws1.Range("A3:K" & ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row) 'Main Range
Set rng2 = ws2.Range("A3:M" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row)
arr1 = rng1.Value2
arr2 = rng2.Value2
Dim i As Long, k As Long
For i = LBound(arr1) To UBound(arr1)
For k = LBound(arr2) To UBound(arr2)
If arr1(i, 1) = arr2(k, 1) And arr2(k, 13) = "Close" Then
rng1.Cells(i, 11) = arr2(k, 2)
End If
Next k
Next i
wb2.Close SaveChanges:=False
Application.ScreenUpdating = True
End Sub
Please, try the next adapted code. It uses a dictionary, to keep the unique kay (and last value from "K:K" as item) of the opened Workbook, then placing the appropriate data in the working workbook:
Sub Get_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range
Dim arr1() As Variant, arr2() As Variant
Dim dict As Object
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
'Please, update the real path of "Book2.xlsx":
Set wb2 = Workbooks.Open(ThisWorkbook.Path & "\Book2.xlsx", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng1 = ws1.Range("A3:K" & ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row) 'Main Range
Set rng2 = ws2.Range("A3:M" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row)
arr1 = rng1.Value2
arr2 = rng2.Value2
'place the unique last key in a dictionary:
Dim i As Long
Set dict = CreateObject("Scripting.dictionary")
For i = 1 To UBound(arr2)
If arr2(i, 13) = "Close" Then
dict(arr2(i, 1)) = arr2(i, 2)
End If
Next i
Debug.Print Join(dict.items, "|") 'just to visualy see the result
'Place the necessary data in its place:
For i = 1 To UBound(arr1)
If dict.Exists(arr1(i, 1)) Then
arr1(i, 11) = dict(arr1(i, 1))
Else
arr1(i, 11) = "NA"
End If
Next i
rng1.Value2 = arr1 'drop back the updated array content
wb2.Close SaveChanges:=False
Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
Column "K:K" of the workbook to be opened must be sorted ascending...
Edited:
The next version works without needing to have column "K:K" sorted:
Sub Get_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng1 As Range, rng2 As Range
Dim arr1() As Variant, arr2() As Variant
Dim dict As Object
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open(ThisWorkbook.Path & "\Book2.xlsx", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng1 = ws1.Range("A3:K" & ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row) 'Main Range
Set rng2 = ws2.Range("A3:M" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row)
arr1 = rng1.Value2
arr2 = rng2.Value2
'place the unique last key in a dictionary:
Dim i As Long
Set dict = CreateObject("Scripting.dictionary")
For i = 1 To UBound(arr2)
If arr2(i, 13) = "Close" Then
If Not dict.Exists(arr2(i, 1)) Then
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11)) 'place the date from K:K, too
Else
If CDate(arr2(i, 11)) > CDate(dict(arr2(i, 1))(1)) Then 'change the item only in case of a more recent date:
dict(arr2(i, 1)) = Array(arr2(i, 2), arr2(i, 11))
End If
End If
End If
Next i
'Place the necessary data in its place:
For i = 1 To UBound(arr1)
If dict.Exists(arr1(i, 1)) Then
arr1(i, 11) = dict(arr1(i, 1))(0) 'extract first item array element
Else
arr1(i, 11) = "NA"
End If
Next i
rng1.Value2 = arr1 'drop back the updated array content
wb2.Close SaveChanges:=False
Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
You may benefit from functions in Excel and combine them with Evaluate trough VBA. Just as example I made up this:
I made up this in same worksheet just as explanation. The formula to get this in column K is:
=IFERROR(INDEX($N$2:$N$16,SUMPRODUCT(--($W$2:$W$16=MAX(--($Y$2:$Y$16="Close")*--($M$2:$M$16=A2)*$W$2:$W$16))*ROW($M$2:$M$16))-1),"NA")
This formula will return desired output. Applied to VBA would be:
Sub Get_Last_Closing_Date()
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rng2 As Range
Dim i As Long
Dim MyFormula As String
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open("D:\Users\gaballahw\Desktop\Book2.xlsx", UpdateLinks:=False, ReadOnly:=True)
Set ws1 = wb1.Sheets(1)
Set ws2 = wb2.Sheets(1)
Set rng2 = ws2.Range("A3:M" & ws2.Cells(ws2.Rows.Count, "A").End(xlUp).Row)
With ws1
For i = 3 To ws1.Cells(ws1.Rows.Count, "A").End(xlUp).Row Step 1
MyFormula = "IFERROR(INDEX(" & rng2.Columns(2).Address & ",SUMPRODUCT(--(" & rng2.Columns(11).Address & _
"=MAX(--(" & rng2.Columns(13).Address & "=""Close"")*--(" & rng2.Columns(1).Address & _
"=" & .Range("A" & i).Value & ")*" & rng2.Columns(11).Address & "))*ROW(" & rng2.Columns(1).Address & "))-2),""NA"")" '-2 because data starts at row 3
.Range("K" & i).Value = Evaluate(MyFormula)
Next i
End With
wb2.Close SaveChanges:=False
Set rng2 = Nothing
Set ws1 = Nothing
Set ws2 = Nothing
Set wb1 = Nothing
Set wb2 = Nothing
Application.ScreenUpdating = True
End Sub
Also, if you have Excel365 you may benefit from function MAXIFS:
MAXIFS function
I'm pretty sure that in the formula provided the part --($W$2:$W$16=MAX(--($Y$2:$Y$16="Close")*--($M$2:$M$16=A2)*$W$2:$W$16)) could be replaced with a MAXIFS but i got an older version of Excel so I can't test.
Also, check Evaluate:
Application.Evaluate method
(Excel)
SORT And XLOOKUP to Get Maximums
In Microsoft 365, you could use the following spilling formula in cell K3 of Sheet1:
=LET(sArray,Sheet2!A3:M22,sFilterCol,13,sCriteria,"Closed",sSortCols,{11;1},sSortOrders,{-1;1},sLookupCol,1,sReturnCol,2,
dLookup,A3:A14,dNotFound,"NA",
sSorted,SORT(FILTER(sArray,CHOOSECOLS(sArray,sFilterCol)=sCriteria),sSortCols,sSortOrders),
sLookup,CHOOSECOLS(sSorted,sLookupCol),sReturn,CHOOSECOLS(sSorted,sReturnCol),
XLOOKUP(dLookup,sLookup,sReturn,dNotFound))
The 1st row holds the source constants (7) while the 2nd row the destination constants (2).
The 3rd row returns the source array filtered and sorted.
In the 4th row this modified array is used to get the source lookup and return columns.
These columns, along with the destination constants, are then fed to the XLOOKUP function in the 5th row.
Edit
For this to work with your test files, with Book2.xlsx open, you need to replace Sheet2!A3:M22 with '[Book2.xlsx]Wb2-sh1'!A3:M18, A3:A14 with A3:A8 and Closed with Close (my bad).
Related
I have been trying to make a function where it matches 2 separate strings with two column then copy corresponding columns data and paste into separate sheet.
I am stuck on that thing how to make 2 matches like For Each cell In myDataRng & myDataRng2.
your help will be appreciated
Sub Tester()
Dim myDataRng, myDataRng2 As Range
Dim cell As Range, wsSrc As Worksheet, wsDest As Worksheet
Dim destRow As Range
Dim FindValue As String
Dim FindValue2 As String
Set wsSrc = Worksheets("Sheet1") 'source sheet
Set wsDest = Worksheets("Sheet2") 'destination sheet
FindValue = wsDest.Range("A2").Value
FindValue2 = wsDest.Range("B2").Value
Set myDataRng = wsSrc.Range("F2:F" & wsSrc.Cells(Rows.Count, "F").End(xlUp).Row)
Set myDataRng2 = wsSrc.Range("A2:A" & wsSrc.Cells(Rows.Count, "A").End(xlUp).Row)
Set destRow = wsDest.Rows(2) 'first destination row
For Each cell In myDataRng
If InStr(1, cell.Value, FindValue) > 0 Then
With cell.EntireRow 'the whole matching row
destRow.Cells(5).Value = .Cells(2).Value
destRow.Cells(6).Value = .Cells(3).Value
destRow.Cells(7).Value = .Cells(4).Value
destRow.Cells(8).Value = .Cells(5).Value
End With
Set destRow = destRow.Offset(1, 0) 'next destination row
End If
Next cell
End Sub
Other Condition
Sub find()
Dim foundRng As Range
Dim mValue As String
Set shData = Worksheets("Sheet1")
Set shSummary = Worksheets("Sheet2")
mValue = shSummary.Range("C2")
Set foundRng = shData.Range("G1:Z1").find(mValue)
'If matches then copy macthed Column and paste into Sheet2 Col"I" (as above code psting the data into Sheet2)
End Sub
Several options:
If Instr(1, cell.Offset(,-5).Value, FindValue2) > 0 Then
If InStr(1, wsSrc.Range("A" & cell.Row), FindValue2) > 0 Then
and others.
I like using rows for loops like this because it makes it very easy to read the code and understand what is happening. By breaking the search range into a series of rows, everything becomes simple to write and read.
Sub Tester()
Dim myDataRng, myDataRng2 As Range
Dim rRow As Range, wsSrc As Worksheet, wsDest As Worksheet
Dim destRow As Range
Dim FindValue As String
Dim FindValue2 As String
Set wsSrc = Worksheets("Sheet1") 'source sheet
Set wsDest = Worksheets("Sheet2") 'destination sheet
FindValue = wsDest.Range("A2").Value
FindValue2 = wsDest.Range("B2").Value
Set myDataRng = wsSrc.Range("F2:F" & wsSrc.Cells(Rows.Count, "F").End(xlUp).Row)
'Set myDataRng2 = wsSrc.Range("A2:A" & wsSrc.Cells(Rows.Count, "A").End(xlUp).Row)
Set destRow = wsDest.Rows(2) 'first destination row
For Each rRow In myDataRng.Rows.EntireRow
If InStr(1, rRow.Columns("F").Value, FindValue) > 0 _
And InStr(1, rRow.Columns("A").Value, FindValue2) > 0 Then
With rRow.EntireRow 'the whole matching row
destRow.Cells(5).Value = .Cells(2).Value
destRow.Cells(6).Value = .Cells(3).Value
destRow.Cells(7).Value = .Cells(4).Value
destRow.Cells(8).Value = .Cells(5).Value
End With
Set destRow = destRow.Offset(1, 0) 'next destination row
End If
Next rRow
End Sub
Set wsSrc = Worksheets("Sheet1") 'source sheet
Set wsDest = Worksheets("Sheet2") 'destination sheet
FindValue = wsDest.Range("A2").Value
FindValue2 = wsDest.Range("B2").Value
Set myDataRng = wsSrc.Range("F2:F" & wsSrc.Cells(Rows.Count, "F").End(xlUp).Row)
'Set myDataRng2 = wsSrc.Range("A2:A" & wsSrc.Cells(Rows.Count, "A").End(xlUp).Row)
Set destRow = wsDest.Rows(2) 'first destination row
For Each rRow In myDataRng.Rows
If InStr(1, rRow.Columns("F").Value, FindValue) > 0 _
And InStr(1, rRow.Columns("A").Value, FindValue2) > 0 Then
With rRow.EntireRow 'the whole matching row
destRow.Cells(5).Value = .Cells(2).Value
destRow.Cells(6).Value = .Cells(3).Value
destRow.Cells(7).Value = .Cells(4).Value
destRow.Cells(8).Value = .Cells(5).Value
End With
Set destRow = destRow.Offset(1, 0) 'next destination row
End If
Next rRow
End Sub
I have numbers in the Range G2:G10, I have to check if these numbers are in one of the Cells in the Row B of the second file. Now I just have a true if argument when the same number is in G2(File 1) and B2(File 2). But how can I do this, so that when G2(File 1) and B4(File 2) are the same the if also works?
Dim cell As Range
Dim wb1 As Workbook, ws1 As Worksheet
Dim wb2 As Workbook, ws2 As Worksheet
Set wb1 = Application.Workbooks.Open("T:\folder\Map2.xlsm")
Set ws1 = wb1.Sheets("Tabelle1")
Set wb2 = Application.Workbooks.Open("T:\folder\file.xlsx")
Set ws2 = wb2.Sheets("sheet1")
For Each cell In wb1.Sheets(1).Range("G2:G10")
If cell.Value = ws2.Cells(cell.Row, "B").Value Then
ws2.Cells(cell.Row, "D").Resize(1, 3).Select
End If
Next cell
End Sub
Try this
Sub test()
Dim c As Range, cx As Range, str$
Dim wb1 As Workbook, ws1 As Worksheet
Dim wb2 As Workbook, ws2 As Worksheet
Set wb1 = Application.Workbooks.Open("T:\folder\Map2.xlsm")
Set ws1 = wb1.Sheets("Tabelle1")
Set wb2 = Application.Workbooks.Open("T:\folder\file.xlsx")
Set ws2 = wb2.Sheets("sheet1")
For Each c In ws1.Range(ws1.Cells(1, 7), ws1.Cells(ws1.Rows.Count, 7).End(xlUp))
For Each cx In ws2.Range(ws2.Cells(1, 2), ws2.Cells(ws2.Rows.Count, 2).End(xlUp))
If c = cx Then
cx.Offset(, 2).Resize(1, 3).Select
str = str & ", " & cx.Address
'Msgbox cx.Address
End If
Next cx
Next c
Msgbox "The following cells meet the conditions: " & Replace(str, ",", "", 1, 1)
End Sub
This uses a dictionary and does what I think you are looking for. Though I might have your sheets backwards. I tested using a single workbook and just added in your workbook and sheet values. I am also unsure what you want to do when a value is found so I left that blank.
Sub compare()
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim cell As Range
Dim lastrow As Long
Dim dict As Object
Set wb1 = Application.Workbooks.Open("T:\folder\Map2.xlsm")
Set ws1 = wb1.Sheets("Tabelle1")
Set wb2 = Application.Workbooks.Open("T:\folder\file.xlsx")
Set ws2 = wb2.Sheets("sheet1")
Set dict = CreateObject("Scripting.Dictionary") 'This is late bound you can change to early binding if you want
With ws2
lastrow = .Cells(.Rows.Count, 2).End(xlUp).Row
For Each cell In .Range("B1:B" & lastrow)
If Not dict.exists(cell.Value) Then 'Avoid errors
dict.Add cell.Value,cell 'Add key value, item will be the range
End If
Next cell
End With
With ws1
For Each cell In Range("G2:G10")
If dict.exists(cell.Value) Then 'Duplicate found when true
'Here we take the matched range offset and place it in the new offset range
Range(cell.Offset(0, 2), cell.Offset(0, 4)).Value = Range(dict(cell.Value).Offset(0, 2), dict(cell.Value).Offset(0, 4)).Value
End If
Next cell
End With
End Sub
I'm trying to compare sheet1 "A" column values to sheet2 "E:E" column values and copy/paste the whole line of every match to sheet3. Please help me to complete this task. I'm very new to VBA.
Thank you very much in advance!
Sub DelDups_TwoLists()
Dim iListCount As Integer
Dim iCtr As Integer
' Turn off screen updating to speed up macro.
Application.ScreenUpdating = False
' Get count of records to search through (list that will be deleted).
iListCount = Sheets("sheet1").Cells(Rows.Count, "A").End(xlUp).Row
' Loop through the "master" list.
For Each x In Sheets("Sheet2").Range("E:E" & Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row)
' Loop through all records in the second list.
For iCtr = iListCount To 1 Step -1
' Do comparison of next record.
' To specify a different column, change 1 to the column number.
If x.Value = Sheets("Sheet1").Cells(iCtr, 1).Value Then
' If match is true then delete row.
Sheets("Sheet1").Cells(iCtr, 1).EntireRow.Copy
Sheets("Sheet3").Select.Paste
End If
Next iCtr
Next
Application.ScreenUpdating = True
MsgBox "Done!"
End Sub
Sub DelDupsTwoLists()
Dim lastRowWs1 As Long, lastRowWs2 As Long
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Set ws1 = Worksheets(1)
Set ws2 = Worksheets(2)
Set ws3 = Worksheets(3)
lastRowWs1 = LastRow(ws1.Name, 1)
lastRowWs2 = LastRow(ws2.Name, 5) 'E = 5
Dim myCell1 As Range, myCell2 As Range
Dim ws1Range As Range, ws2Range As Range
Set ws1Range = ws1.Range(ws1.Cells(1, "A"), ws1.Cells(lastRowWs1, 1))
Set ws2Range = ws2.Range(ws2.Cells(1, "E"), ws2.Cells(lastRowWs2, 1))
Dim rangeToDelete As Range
For Each myCell1 In ws1Range
For Each myCell2 In ws2Range
If myCell1.Value = myCell2.Value Then
Dim lastRowWs3: lastRowWs3 = LastRow(ws3.Name, 1) + 1
myCell2.EntireRow.Copy Destination:=ws3.Cells(lastRowWs3, 1)
If Not rangeToDelete Is Nothing Then
Set rangeToDelete = Union(rangeToDelete, myCell2.EntireRow)
Else
Set rangeToDelete = myCell2.EntireRow
End If
End If
Next
Next
If Not rangeToDelete Is Nothing Then
Debug.Print "Deleting rangeToDelete - "; rangeToDelete.Address
rangeToDelete.Delete
End If
Debug.Print "Done!"
End Sub
Public Function LastRow(wsName As String, Optional columnToCheck As Long = 1) As Long
Dim ws As Worksheet
Set ws = Worksheets(wsName)
LastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row
End Function
Pretty much I rewrote the whole code from scratch. It pretty much uses the initial n2 complexity, but is rather faster than that, because the deletion of the rows in WorkSheet(2) is done in a single last step rangeToDelete.Delete, which saves a lot of time.
Pretty much, the code defines 2 ranges with which is works - ws1Range and ws2Range, using the LastRow function. Once it defines them, it starts looping through them and comparing them. Hence the n2 complexity. In case of equal values, the row is copied and the cell is added to the rangeToDelete.
Note - it will probably not work as "out of the box solution", but try to debug further with F8 and see what happens.
Additionally:
Using Integer is not a great idea in VBA.
"_" in the Sub name is used for Events in VBA, thus it is not a great idea to use it. (although it works)
How to avoid using Select in Excel VBA
Give this a try (see comments in code for more details):
Sub DelDups_TwoLists()
' Turn off screen updating to speed up macro.
Application.ScreenUpdating = False
With ActiveWorkbook
Dim wsSrc As Worksheet: Set wsSrc = .Sheets("Sheet1") 'declare and set the source worksheet
Dim wsDst As Worksheet: Set wsDst = .Sheets("Sheet3") 'declare and set the destination worksheet
Dim R1 As Long, R2 As Long, C As Long, lRow As Long, lCol As Long 'declare variables to use
With wsSrc
lCol = .Cells(1, Columns.Count).End(xlToLeft).Column 'get the last column value in the source sheet, at row 1, will reuse this laster
Dim arrData_1 As Variant: arrData_1 = .Range(.Cells(1, 1), .Cells(.Cells(Rows.Count, 1).End(xlUp).Row, 1)) 'declare and allocate the source data to an array
End With
With .Sheets("Sheet2")
Dim arrData_2 As Variant: arrData_2 = .Range("E1:E" & .Cells(Rows.Count, 1).End(xlUp).Row) 'declare and allocate the compare data to an array
End With
End With
With wsDst
For R1 = LBound(arrData_1) To UBound(arrData_1) 'for each row in the source data
For R2 = LBound(arrData_2) To UBound(arrData_2) 'for each row in the compare data
If arrData_1(R1, 2) = arrData_2(R2, 1) Then 'if there is a match
lRow = .Cells(Rows.Count, 1).End(xlUp).Row + 1 'get the last row in the destination sheet
.Range(.Cells(lRow, 1), .Cells(lRow, lCol)).Value = _
wsSrc.Range(wsSrc.Cells(R1, 1), wsSrc.Cells(R1, lCol)).Value 'allocate the matching values
Exit For 'exit early here if there is a match, go to next row to check
End If
Next R2
Next R1
End With
Application.ScreenUpdating = True
MsgBox "Done!"
End Sub
I've been working on this one for a couple weeks now and I can't seem to get it right. The concept seems easy which is why I'm so frustrated with it. I finally resorted to posting here for some input.
The idea behind this is similar to a vlookup (I tried vlookup and got a result I wasn't looking for). On ThisWorkbook, I set "Desc" equal to cell B7. I then want to look this up in a separate workbook which is the database. Once "Desc" is found in the database, I want to copy the data in column D and paste it to the cell to the right of "Desc" in the original workbook. I need to repeat the Copy-Paste process for the rest of the cells in column B under "Desc". Thanks in advance. Cheers.
Option Explicit
Dim i As Integer, n As Integer
Dim Desc As Range, ExDesc As Range
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Sub Retrieve()
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set ws1 = wb1.Sheets("Import")
ws1.Range("C7:C100000").ClearContents
With ws1
i = 7
Do Until .Cells(i, 2) = ""
Set Desc = ws1.Cells(i, 2)
With Workbooks.Open("C:\Users\Username\Desktop\Database.xlsm")
Set wb2 = ActiveWorkbook
Set ws2 = wb2.Sheets("Data")
n = 2
Do Until ws2.Cells(n, 2) = ""
Set ExDesc = Cells(n, 2)
If ExDesc = Desc Then
ExDesc.Offset(0,2).Copy
End If
n = n + 1
Loop
End With
i = i + 1
Loop
End With
End Sub
Public Sub Paste()
wb1.Activate
ws1.Cells(i, 3).Paste
End Sub
Untested:
Sub Retrieve()
Dim i As Integer, n As Integer
Dim Desc As Range, ExDesc As Range
Dim wb1 As Workbook, wb2 As Workbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim rngLookup As Range
Dim v
Application.ScreenUpdating = False
Set wb1 = ThisWorkbook
Set ws1 = wb1.Sheets("Import")
ws1.Range("C7:C100000").ClearContents
Set wb2 = Workbooks.Open("C:\Users\Username\Desktop\Database.xlsm")
With wb2.Sheets("Data")
Set rngLookup = .Range(.Cells(7, 2), _
.Cells(7, 2).End(xlDown)).Resize(, 3)
End With
With ws1
i = 7
Do Until .Cells(i, 2) = ""
v = Application.VLookup(.Cells(i, 2).Value, rngLookup, 3, False)
If Not IsError(v) Then .Cells(i, 4).Value = v
i = i + 1
Loop
End With
wb2.Close False
End Sub
Try this:
Sub Retrieve()
Application.ScreenUpdating = False
Dim lookuprng As Range
Set wb1 = ThisWorkbook
Set wb2 = Workbooks.Open("C:\Users\username\Desktop\Database.xlsm")
Set lookuprng = wb2.Sheets("Data").Range("look up range in Database")
Set ws1 = wb1.Sheets("Import")
ws1.Range("C7:C100000").ClearContents
wb1.Activate
With ws1
i = 7
Do Until .Cells(i, 2) = ""
Cells(i, 5).Value = Application.VLookup(Cells(i, 2).Value, lookuprng, 2, 0)
i = i + 1
Loop
End With
End Sub
You mentioned I tried vlookup and got a result I wasn't looking for but this should work, though you would have to update links if the sheet with the lookup table is not open in the same session.
How can I concatenate unique cell values in every row to adapt in the code below. Removing duplicate values in a cell. Result after macro is the second image.
Sub Concatenar()
Dim myRange As Range
Dim c As Long
Dim r As Long
Dim txt As String
Set myRange = Application.InputBox("Selecione a primeira e a última célula:", Type:=8)
For r = 1 To myRange.Rows.Count
For c = 1 To myRange.Columns.Count
If myRange(r, c).Text <> "" Then
txt = txt & myRange(r, c).Text & vbLf
End If
Next
If Right(txt, 1) = vbLf Then
txt = Left(txt, Len(txt) - 1)
End If
myRange(r, 1) = txt
txt = ""
Next
Range(myRange(1, 2), myRange(1, myRange.Columns.Count)).EntireColumn.Delete
End Sub
This does what you want, I believe. It pastes/tranposes the values to a temporary workbook, uses RemoveDuplicates to trim them down, and Join to munge them all together. It then pastes the munged values back into column A of the original workbook and deletes the other columns.
Because of the destructive nature of this code, you must test it on a copy of your data:
Sub CrazyPaste()
Dim wsSource As Excel.Worksheet
Dim rngToConcat As Excel.Range
Dim wbTemp As Excel.Workbook
Dim wsPasted As Excel.Worksheet
Dim rngPasted As Excel.Range
Dim i As Long
Dim LastRow As Long
Dim Results() As String
Set wsSource = ActiveSheet
Set rngToConcat = wsSource.UsedRange
Set wbTemp = Workbooks.Add
Set wsPasted = wbTemp.Worksheets(1)
wsSource.UsedRange.Copy
wsPasted.Range("A1").PasteSpecial Transpose:=True
Set rngPasted = wsPasted.UsedRange
ReDim Results(1 To rngPasted.Columns.Count)
For i = 1 To rngPasted.Columns.Count
If WorksheetFunction.CountA(rngPasted.Columns(i)) = 0 Then
Results(i) = ""
Else
rngPasted.Columns(i).RemoveDuplicates Columns:=1, Header:=xlNo
LastRow = Cells(wsPasted.Rows.Count, i).End(xlUp).Row
Results(i) = Replace(Join(Application.Transpose(rngPasted.Columns(i).Resize(LastRow, 1)), vbCrLf), _
vbCrLf & vbCrLf, vbCrLf)
End If
Next i
With wsSource
.Range("A1").Resize(i - 1, 1) = Application.Transpose(Results)
.Range(.Cells(1, 2), .Cells(1, .Columns.Count)).EntireColumn.Delete
wbTemp.Close False
End With
End Sub
In my limited testing, the only situation where this might yield unwanted results is when a cell in the first column is blank, but there's other data in that row. The resulting cell would then start with a blank.