I have two sheets, call worksheet1 = GoldCopy and worksheet2 = OPS, both with several of the same columns:
column 1 = Filename, column 3 = file path, column 4 = encryption code, and column 5 = in goldcopy (or OPS depending on which ws you're looking at).
There are 10,000+ rows of data. I want to compare ws1 with ws2 and make sure the filename and encryption code from ws1 is in ws2 (doesn't matter where as long as filename and encryption code are in the same row).
If there is a filename and encryption code that is not in ws2, then that column 5 at that row will be made FALSE.
Then I want to compare ws2 to ws1 with the same logic.
I tried two for loops but it has taken forever to finish. I want to try arrays. I'm having trouble with the 'IF' statements which I will label below.
This is the first part of the code with ws1 checking ws2. I assume to have ws2 check against ws1, it would be the same code, just switched around.
Sub CheckforDiscrepancies
Application.ScreenUpdating = False
Dim s As Worksheet
For Each s In Sheets
'NEW FILE SEARCH A-NAS OPS'
If s.Name = "OPS" Then 'check if there is an OPS file if so then proceed'
ACOL = Worksheets("OPS").Cells(1, Columns.Count).End(xlToLeft).Column
Worksheets("OPS").Cells(1, ACOL + 1).Value = "In Gold Copy?"
'GoldCopy Check with OPS'
Worksheets("GoldCopy").Activate
GCOL = Worksheets("GoldCopy").Cells(1, Columns.Count).End(xlToLeft).Column
Worksheets("GoldCopy").Cells(1, GCOL + 1) = "Deployed in OPS?"
Dim arrayGoldRow As Variant
Dim arrayGoldRow2 As Variant
Dim arrayARow As Variant
Dim arrayARow2 As Variant
arrayGoldRow = Worksheets("GoldCopy").Range("A:A").Value 'this should be column 1 the filename for the goldcopy
arrayARow = Worksheets("OPS").Range("A:A").Value 'this should be column 1 for the filename for the ops sheet
arrayGoldRow2 = Worksheets("GoldCopy").Range("D:D").Value 'this should be column 4 for the encryption code for the goldcopy
arrayARow2 = Worksheets("OPS").Range("D:D").Value 'this should be column 4 for the encryption code for the ops sheet
For i = LBound(arrayGoldRow, 1) To UBound(arrayGoldRow, 1)
GCOL = Worksheets("GoldCopy").Cells(1, Columns.Count).End(xlToLeft).Column
If InStr(Worksheets("GoldCopy").Cells(i, 3), "\sidata\") > 0 Then 'this is checking column 3 to see if the filepath fits a certain criteria
For x = LBound(arrayARow, 1) To UBound(arrayARow, 1) 'not sure if this is correct of not
If Worksheets("GoldCopy").Cells(i,1) = Worksheets("OPS").Cells(j,1) and Worksheets("GoldCopy").Cells(j,4) = Worksheets("OPS").Cells(j,4) Then 'this is saying is filename in column1 and encyrption code in column2 from the goldcopy BOTH match with the filename in column1 and encyrption code in column2 from the ops sheet, then...
bln = True
Worksheets("GoldCopy").Cells(i, GCOL) = bln
Worksheets("GoldCopy").Cells(i, GCOL).Interior.ColorIndex = 10
Exit For
Else
Worksheets("GoldCopy").Cells(i, GCOL) = bln
Worksheets("GoldCopy").Cells(i, GCOL).Interior.ColorIndex = 22
End If
Next x
End If
Next i
This is the way I would tackle the task. Please try my code. It uses the COUNTIFS worksheet function to check if the combination of file and code exists. You could extend this to include the path. It also uses the same function, called with file names reversed, to check availability both ways.
Enum Nws ' worksheet parameters
' 118
NwsFirstDataRow = 2 ' change to suit
NwsFile = 1 ' columns: 1 = column A
NwsPath = 3 ' 3 = column C
NwsCode ' no value assigned means previous + 1
NwsCheck
End Enum
Sub CompareTabs()
' 118
Dim WsOps As Worksheet
Dim WsGold As Worksheet
On Error Resume Next
Set WsOps = Worksheets("OPS")
Set WsGold = Worksheets("GoldCopy")
If Err Then Exit Sub ' exit if one of the sheets doesn't exist
On Error GoTo 0
Application.ScreenUpdating = False
Debug.Print MarkDiscrepancies(WsOps, WsGold)
Debug.Print MarkDiscrepancies(WsGold, WsOps)
Application.ScreenUpdating = False
End Sub
Private Function MarkDiscrepancies(Ws1 As Worksheet, _
Ws2 As Worksheet) As Boolean
' 118
' return True if a discrepancy was found and marked
Dim Src As Variant ' Source = base data
Dim Scode As Variant ' Src encryption codes
Dim Tgt As Range ' Target = range to find Src data in
Dim Tcode As Range ' Tgt encryption codes
Dim R As Long ' loop counter: rows in Ws1
With Ws2
Set Tgt = .Range(.Cells(1, NwsFile), .Cells(.Rows.Count, NwsFile).End(xlUp))
End With
Set Tcode = Tgt.Offset(, NwsCode - NwsFile)
With Ws1
Src = .Range(.Cells(1, NwsFile), .Cells(.Rows.Count, NwsFile).End(xlUp)).Value
Scode = .Range(.Cells(1, NwsFile), .Cells(.Rows.Count, NwsFile).End(xlUp)) _
.Offset(, NwsCode - NwsFile).Value
For R = NwsFirstDataRow To UBound(Src)
On Error Resume Next
.Cells(R, NwsCheck).Value = CBool(WorksheetFunction.CountIfs(Tgt, Src(R, 1), Tcode, Scode(R, 1)))
Next R
MarkDiscrepancies = CBool(WorksheetFunction.CountIf( _
.Range(.Cells(NwsFirstDataRow, NwsCheck), _
.Cells(.Rows.Count, NwsCheck).End(xlUp)), False))
End With
End Function
The function that does the work returns True or False, depending upon whether discrepancies were found. It prints the result to the Immediate Pane. You might show it in a MsgBox or just call the function like a sub (without parentheses) and take your information from column E - as, in fact, does my code.
Related
Need some help with my macro. What I need is to loop through a filterable list of IDs in Sheet2 and match them to where the ID is contained in Column 16 on Sheet 1. Then copy over the whole matched row in Sheet1 over to a Sheet3.
Here's what Sheet2 looks like, generally (filtering by things like Status, etc.):
ID
Summary
Created On
Status
1234567
Text
Date
Done
2345678
Text
Date
In Progress
And Sheet1 (*note the ID -> ID2 match):
ID
Summary
Created On
Status
ID2
#######
Text
Date
Done
1234567, #######, #######
#######
Text
Date
In Progress
#######, 2345678
I used this thread here (Code needed to loop through column range, check if value exists and then copy cells) for a process of pairing in the same workbook that does not need to be filtered, and it seems to work just fine. However, my code in this instance is not pairing the amount of rows correctly nor is it pairing with the correct IDs either. I think something may be off with the pairing process with filtering in the mix?
My code so far:
Public Sub PairingBackTEST()
Dim WS As Worksheet
Set WS = Sheets("Sheet1")
'Clears Sheet 3
Sheets("Sheet3").Activate
Sheets("Sheet3").Cells.Clear
' Get the number of used rows for each sheet
Dim RESULTBlocked As Integer, Blockers As Integer
RESULTBlocked = WS.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count
Debug.Print RESULTBlocked
Blockers = Worksheets(1).Cells(1048576, 1).End(xlUp).Row
Debug.Print Blockers
RESULTBlockers = Worksheets(4).Cells(1048576, 1).End(xlUp).Row
'Set date/time format for Created On and Due Date columns
Sheets("Sheet3").Activate
Sheets("Sheet3").Columns("H:H").Select
Selection.NumberFormat = "[$-en-US]m/d/yy h:mm AM/PM;#"
Sheets("Sheet3").Columns("I:I").Select
Selection.NumberFormat
'Pairing
With Worksheets(1)
'Loop through Sheet2
For i = 1 To Blockers
'Loop through Sheet1
For j = 1 To RESULTBlocked
If InStr(1, .Cells(i, 16), WS.Cells(j, 1), vbBinaryCompare) > 0 Then
' If a match is found:
RESULTBlockers = RESULTBlockers + 1
For k = 1 To 17 'How ever many columns there are
Sheets("Sheet3").Cells(RESULTBlockers, k) = .Cells(i, k)
Next
Exit For
Else
End If
Next j
Next i
End With
'Prepare headers on RESULT Blocked
Sheets("Sheet1").Rows(1).Copy
Sheets("Sheet3").Range("A1").PasteSpecial
I'd maybe try an approach like this:
Public Sub PairingBackTEST()
Dim wb As Workbook
Dim wsList As Worksheet, wsCheck As Worksheet, wsResults As Worksheet
Dim lrList As Long, lrCheck As Long, c As Range, cDest As Range, id, m
'use workbook/worksheet variables for clarity, and to avoid repetition...
Set wb = ThisWorkbook
Set wsList = wb.Worksheets("Sheet2")
Set wsCheck = wb.Worksheets("Sheet1")
Set wsResults = wb.Worksheets("Sheet3")
'no need for activate/select here
With wsResults
.Cells.Clear
.Columns("H:H").NumberFormat = "[$-en-US]m/d/yy h:mm AM/PM;#"
'.Columns("I:I").NumberFormat = ??? this is missing in your posted code
wsCheck.Rows(1).Copy .Range("A1") 'copy headers
End With
Set cDest = wsResults.Range("A2") 'first destination row on result sheet
For Each c In wsList.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells
id = c.Value
'you can use match in place of looping as long as there's only one row to find
m = Application.Match("*" & id & "*", wsCheck.Columns(16), 0)
If Not IsError(m) Then
If m > 1 Then 'avoid matching on header...
cDest.Resize(1, 17).Value = wsCheck.Cells(m, 1).Resize(1, 17).Value
Set cDest = cDest.Offset(1, 0) 'next row on results sheet
End If
End If
Next c
End Sub
I have two excels Book1.xlsm and Book2.xlsx. Book1 will have certain values like alpha, beta, gamma etc. (no repetition) in column A. And Book2 will have multiple occurrence of Book1 values like beta, beta, beta, alpha, alpha, gamma, gamma, gamma, gamma, gamma etc. The values in Book2 may not be alphabetically sorted but same values will be grouped together. Book2 values will be also in column A.
I have a macro designed in Book1.xlsm that should iterate over each value in Book1 column A and find the first row id where same value is present in Book2 column A. This row id should be then copied in corresponding column B of Book1.
This is how my macro code looks like. When I run, it fails with Run Time error '1004': Application-defined or object-defined error
Option Explicit
Sub Get_Data()
Dim wb1 As Worksheet
Dim wb2 As Worksheet
Dim wb2row As Integer
Dim i As Integer
Dim j As Integer
Const A = "A"
Const B = "B"
Set wb1 = Workbooks("Book1.xlsm").Worksheets("Sheet1")
Set wb2 = Workbooks("Book2.xlsx").Worksheets("Sheet1")
'Both For loop start from row id 2.
For i = 2 To wb1.Range("A2", wb1.Range("A2").End(xlDown)).Rows.Count
For j = 2 To wb2.Range("A2", wb2.Range("A2").End(xlDown)).Rows.Count
wb2row = Application.WorksheetFunction.Match(wb1.Cells(i, A), Range(wb2.Cells(j, A)), 0)
wb1.Cells(i, B).Copy (wb2.Cells(j, A))
Exit For ' j loop
Next j
Next i
End Sub
You can make excel do the work for you. Try this (tested)
Sub Get_Data()
With Workbooks("Book1.xlsm").Sheets("Sheet1")
With .Range(.Range("B2"), .Range("A" & Rows.Count).End(xlUp).Offset(0, 1))
.Formula2 = "=IFERROR(MATCH(A2,[Book2.xlsx]Sheet1!$A:$A,0),"""")"
.Value2 = .Value2
End With
End With
End Sub
Match Criteria, Return Row
Option Explicit
Sub Get_Data()
' Source
Const srcFirst As Long = 2
Const srcCol As String = "A"
' Destination
Const dstFirst As Long = 2
Const dstCol As String = "A"
Const resCol As String = "B"
' Source
Dim src As Worksheet
Set src = Workbooks("Book2.xlsx").Worksheets("Sheet1")
Dim rng As Range
Set rng = src.Range(src.Cells(srcFirst, srcCol), _
src.Cells(src.Rows.Count, srcCol).End(xlUp))
Dim RowOffset As Long
RowOffset = srcFirst - 1
' Destination
' 'ThisWorkbook' - the workbook containing this code.
Dim dst As Worksheet
Set dst = ThisWorkbook.Worksheets("Sheet1")
Dim srcRow As Variant ' It could be an error value, hence 'Variant'.
Dim i As Long
For i = 2 To dst.Cells(dst.Rows.Count, dstCol).End(xlUp).Row
srcRow = Application.Match(dst.Cells(i, dstCol), rng, 0)
If Not IsError(srcRow) Then
' This will write the row.
' If you need index, then remove 'RowOffset'.
dst.Cells(i, resCol).Value = srcRow + RowOffset
Else
' no match found, e.g.:
'dst.Cells(i, resCol).Value = ""
End If
Next i
End Sub
The second parameter of match function must be a range not a single cell.
I struggle with VBA and have spent a few days trying to find a solution to this problem. Essentially, I have two spreadsheets with large sets of data. Column K of "Design Mods" worksheet contains the same types of values as Column C of the "Output" Worksheet. I've been trying to get my script to do the following:
1. for each cell in column k of "Design Mods", check if there is a matching cell in column c of the "output" spreadsheet
2. if a match is found, then populate the cell in "Design Mods" to columns over with the information from column b of "Output"
Because of my lack of experience, I've only been able to setup the script below which only checks and pulls correctly for one cell.
I need it to check each cell against a range of other cells.
Any help/guidance would be very much appreciated.
Thank you very much!
Sub MatchValue_Test()
'Routine is meant to populate columns "Design Mods" Spreadsheet with affected calculations from the "Output" Spreadsheet
'Variables below refer to Design Mods spreadsheet
Dim designmod As Worksheet '<-- Design Mods worksheet that we are comparing to the Output Data
Dim DesignMod_DClrow As Integer '<-- Variable used to count to the last low in the DC Number Column of Design Mods Spreadsheet
Dim designmoddc As Range '<-- Variable used to identify the range of values being checked in Design Mods is the DC Numbers Column K from K4 to the end of the column
Dim valuetofind As String '<-- DC Number used as matching criteria between Design Mods spreadsheet and Output Data
'Test Variables for integrating references to from Output worksheet
Dim testset As Worksheet
Dim test2_lrow As Integer
Dim test As Range
Dim valuetofindw2 As String
'Variables below pertain the routine itself
Dim found As Boolean '<-- this condition has to be false to start the routine
'Start of Routine
found = False
'Definition of Data Ranges in Design Mods spreadsheet
Set designmod = ActiveWorkbook.Worksheets("Sheet1")
DesignMod_DClrow = designmod.Range("K4").End(xlDown).Row
Set designmoddc = designmod.Range("K4:K" & DesignMod_DClrow)
'Test variables for integrating values from Output worksheet
Set testset = ActiveWorkbook.Worksheets("Sheet2")
test2_lrow = testset.Range("C2").End(xlDown).Row
Set test = testset.Range("C2:C" & test2_lrow)
'Identify the value being matched against
valuetofind = designmod.Range("L4").Value '<-- the script wont run if I have this value set to a range, and I need to figure out get this to loop so I don't need a variable for every cell im checking against
'test variables to figure out if statement
valuetofindw2 = testset.Range("C2").Value
valuetofindw3 = testset.Range("B2").Value
valuetofindw4 = designmod.Range("K4")
'If Statements performing the comparison
For Each Cell In designmoddc
If Cell.Value = valuetofindw3 Then
found = True
End If
Next
If found = True Then
designmoddc.Cells.Offset(0, 2).Value = testset.Range("B2")
End If
End Sub
You did not answer my clarification questions...
I prepared a solution, able to work very fast (using arrays). Please back-up your workbook, because the code will rewrite the matching cases in column M:M.
Sub MatchValue_TestArrays()
Dim designMod As Worksheet, lastRowD As Long, testSet As Worksheet, lastRowT As Long
Dim arrDes As Variant, arrTest As Variant, d As Long, t As Long, boolFound As Boolean
Set designMod = Worksheets("Sheet1")
Set testSet = Worksheets("Sheet2")
lastRowD = designMod.Range("K" & Cells.Rows.Count).End(xlUp).Row
lastRowT = testSet.Range("C" & Cells.Rows.Count).End(xlUp).Row
arrDes = designMod.Range("K4:M" & lastRowD).value 'load the range in array
arrTest = testSet.Range("B2:C" & lastRowT).value
For d = 1 To UBound(arrDes, 1)
For t = 1 To UBound(arrTest, 1)
If arrDes(d, 1) = arrTest(t, 2) Then
arrDes(d, 3) = arrTest(t, 1)'fill the array third column (M:M) with values of B:B testSheet...
Exit For
End If
Next t
Next d
designMod.Range("K4:M" & lastRowD).value = arrDes' Drop the modified array
End Sub
Try the updated code, please. It searches now for all occurrences and put each one in a consecutive column:
Sub MatchValue_TestArrays_Extended()
Dim designMod As Worksheet, lastRowD As Long, testSet As Worksheet, lastRowT As Long
Dim arrDes As Variant, arrTest As Variant, d As Long, t As Long, col As Long
Set designMod = Worksheets("Design") ' Worksheets("Sheet1")
Set testSet = Worksheets("TestS") ' Worksheets("Sheet2")
lastRowD = designMod.Range("K" & Cells.Rows.Count).End(xlUp).Row
lastRowT = testSet.Range("C" & Cells.Rows.Count).End(xlUp).Row
arrDes = designMod.Range("K4:AQ" & lastRowD).value
arrTest = testSet.Range("B2:C" & lastRowT).value
For d = 1 To UBound(arrDes, 1)
col = 3 'the column where the occurrence will be put
For t = 1 To UBound(arrTest, 1)
If arrDes(d, 1) = arrTest(t, 2) Then
arrDes(d, col) = arrTest(t, 1): col = col + 1
End If
Next t
Next d
designMod.Range("K4:AQ" & lastRowD).value = arrDes
End Sub
Using Match() is fast when your data is on a worksheet:
Sub MatchValue_Test()
Dim wsDesign As Worksheet, wsOut As Worksheet, m, c As Range
Set wsDesign = ActiveWorkbook.Worksheets("Sheet1")
Set wsOut = ActiveWorkbook.Worksheets("Sheet2")
For Each c In wsDesign.Range(wsDesign.Range("K4"), _
wsDesign.Cells(Rows.Count, "k").End(xlUp)).Cells
m = Application.Match(c.Value, wsOut.Columns("C"), 0)
If Not IsError(m) Then
'if Match() found a hit then m will be the row number on sheet2
c.Offset(0, 2).Value = wsOut.Cells(m, "B").Value
End If
Next c
End Sub
I need some direction as to what could be going wrong with the VBA code that I am using. I have
been working at this for hours and can’t seem to figure out what is going on. As of right
now when I run the code, nothing happens, no errors, nothing…
A lot of the code I am using I got from this post: Similar Use Case
Any help would greatly be appreciated.
What I am trying to do:
I am trying to search a database for the values in textboxes on a userform when pressing a
command button. In other words, I am telling vba to search through rows of data and match the
values in textboxes, then if there is a match, copy a that match to a new sheet.
Process:
Have a click event for the “Run Check” button on the UserForm Code
Clear the target sheet area before each run (Each Click).
Set an array from the textbox values where the index of each matches the column number to search (Although I am only searching 2 values in the array, I want to build upon this later so an array made sense)
Filter search for only rows that have the status of “Open” in the Status Column
One row at a time, compare the value of the appropriate column to the array index that matches it
If a match is found, the “match” variable is set to true
Loop through the rest of the Textboxes values from the array, if ANY of them don’t match, the “match” variable is set to false, and break the loop over the Textboxes as fail.
If “match” is true by the end of the loop through the ROW of the “searched” worksheet, columns 1 to 8 get looped through, setting the values from the searched sheet to the target Sheet.
Nest Row finish loop
Screenshots to help with context
Step 1
Step 2
Step 3
Step 4
The Code Updated<-Working:
Private Sub run_check_but_Click()
Const COL_STATUS As Long = 4
Dim wsData As Worksheet, wsSyn As Worksheet
Dim tRow As Long, i As Long
Dim tempList(1 To 9)
Dim match As Boolean
Dim rCol As Range, c As Range
Set wsData = Sheets("Database")
Set rCol = wsData.Range(wsData.Cells(3, 4), wsData.Cells(100, 4))
'Set TargetSheet and clear the previous contents
Set wsSyn = Sheets("Syn_Calc")
wsSyn.Range("A3:G" & wsSyn.Range("A" & Rows.count).End(xlUp).row + 1).ClearContents 'changed from to 3
tRow = 3
'Set an array of strings, based on the index matching the column to search for each
tempList(5) = curbase_box.Text 'Column "E" (5)
tempList(6) = dirquote_box.Text 'Column "F" (6) 'changed from 9 to 6
For Each c In rCol.Cells
With c.EntireRow
If .Cells(COL_STATUS).Value = "Open" Then
match = False
For i = LBound(tempList) To UBound(tempList)
If tempList(i) <> "" Then
match = (.Cells(i).Text = tempList(i))
If Not match Then Exit For
End If
Next i
If match Then
'copy values from E-K
wsSyn.Cells(tRow, 1).Resize(1, 7).Value = _
.Cells(5).Resize(1, 7).Value
tRow = tRow + 1
End If
End If 'open
End With
Next c
End Sub
Untested:
Private Sub run_check_but_Click()
Const COL_STATUS As Long = 4
Dim wsData As Worksheet, wsSyn As Worksheet
Dim tRow As Long, i As Long
Dim tempList(1 To 9)
Dim match As Boolean
Dim rCol As Range, c As Range
Set wsData = Sheets("Database")
Set rCol = wsData.Range(wsData.Cells(3, 4), wsData.Cells(100, 4))
'Set TargetSheet and clear the previous contents
Set wsSyn = Sheets("Syn_Calc")
wsSyn.Range("A8:F" & wsSyn.Range("A" & Rows.Count).End(xlUp).Row + 1).ClearContents
tRow = 3 '<< but you clear from row 8 down?
'Set an array of strings, based on the index matching the column to search for each
tempList(5) = curbase_box.Text 'Column "E" (5)
tempList(9) = dirquote_box.Text 'Column "I" (9)
For Each c In rCol.Cells
With c.EntireRow
If .Cells(COL_STATUS).Value = "Open" Then
match = False
For i = LBound(tempList) To UBound(tempList)
If tempList(i) <> "" Then
match = (.Cells(i).Text = tempList(i))
If Not match Then Exit For
End If
Next i
If match Then
'copy values from E-K
wsSyn.Cells(tRow, 1).Resize(1, 7).Value = _
.Cells(5).Resize(1, 7).Value
tRow = tRow + 1
End If
End If 'open
End With
Next c
End Sub
I have data in this format as show in the image
I want the data to be in the format as shown in the image below.
That means i want data from 1991 in image 1 to be pasted to 1991 from image 2, similarly, data from 1992 in image 1 to be pasted to 1992 from image 2.
Instead of copying the data from 1991,1992,1993 manually from image 1 and pasting it in image 2, i want it to be done automatically using programming since I have large amount of data that needs to be managed. Can it be done by using VBA?
Please try this code. Comments in the code will help you make the required adjustments, in particular the name of the worksheet which has your data and the first column to transpose.
Option Explicit
Sub Unpivot()
' 18 Feb 2018
Const WsOutName As String = "Output" ' name the result sheet
Const CaptionRow As Long = 1 ' specifies the row with the captions
' the next row is presumed data
Dim WsIn As Worksheet, WsOut As Worksheet
Dim Rng As Range
Dim Arr() As Variant
Dim Cap As Variant
Dim C As Long, Cl As Long ' column, Last column
Dim R As Long, Rl As Long ' row, Last row
Application.ScreenUpdating = False
On Error Resume Next
Set WsOut = Worksheets(WsOutName)
If Err Then
Set WsOut = Worksheets.Add(Before:=Worksheets(1))
WsOut.Name = WsOutName
Else
WsOut.Cells.ClearContents ' delete all existing content
End If
On Error GoTo 0
Set WsIn = Worksheets("Unpivot") ' change to match
With WsIn
Cl = .Cells(CaptionRow, .Columns.Count).End(xlToLeft).Column
' (2 = B) specifies first column to look at
For C = 2 To Cl
' columns can be of different lengths
Rl = .Cells(.Rows.Count, C).End(xlUp).Row
If Rl > CaptionRow Then
Cap = .Cells(CaptionRow, C).Value
Set Rng = Range(.Cells(CaptionRow + 1, C), .Cells(Rl, C))
Arr = Rng.Value
End If
With WsOut
Rl = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
.Cells(Rl, 1).Resize(UBound(Arr), 1).Value = Cap
.Cells(Rl, 2).Resize(UBound(Arr), 1).Value = Arr
End With
Next C
End With
Application.ScreenUpdating = True
End Sub
Yes, it could be done by VBA. What you need to do is put all your data in Image 1 into a dictionary. then for the image 2, you can just find the key in the dictionary and paste the result the cell.
PS: You can use Offset to access other cell