VBA EXCEL vlookups through all sheets vs index - excel

I have an excel file with over 200 sheets + index sheet, and I am trying to go through all sheets to copy data from index sheet. For example, I have the below table:
A test1
B test2
C test3
D test4
So I would like to do a vlookup in the index sheet, and copy the column K into the right sheet. For example, I would like "test1" to be copied in sheet "A", in cell A3. The table to vlookup is in sheet "INDEX", range J1:K4.
Is that possible? I stored a file here! For confidentiality reason, I've edited sheet names and content, and put a shorter file.
Thanks in advance!

Update Worksheets
Option Explicit
Sub updateWorksheets()
' Define constants.
Const wsName As String = "INDEX"
Const FirstCellAddress As String = "J1"
Const dstAddress As String = "A3"
Dim wb As Workbook: Set wb = ThisWorkbook ' Workbook containing this code.
' Define Data Range.
Dim rng As Range
With wb.Worksheets(wsName).Range(FirstCellAddress).Resize(, 2)
Set rng = .Resize(.Worksheet.Rows.Count - .Row + 1).Find( _
What:="*", _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious)
If rng Is Nothing Then
Exit Sub
End If
Set rng = .Resize(rng.Row - .Row + 1)
End With
' Write values from Data Range to Data Array.
Dim Data As Variant: Data = rng.Value
' Declare additional variables (to be used in the 'For Next' loop).
Dim dst As Worksheet ' Current Destination Worksheet
Dim i As Long ' Data Array Row Counter
' Loop through rows of Data Array.
For i = 1 To UBound(Data, 1)
' Use the value in the first column to try to create a reference
' to the worksheet i.e. check if the worksheet exists.
Set dst = Nothing
On Error Resume Next
Set dst = wb.Worksheets(Data(i, 1))
On Error GoTo 0
' If the worksheet exists,...
If Not dst Is Nothing Then
' ...write value from second column of Data Array
' to Destination Cell Range in Current Destination worksheet.
dst.Range(dstAddress).Value = Data(i, 2)
End If
Next i
End Sub

Related

How do I code a macro in VBA that deletes columns in excel that don't appear in an array?

I'm creating a macro that is formatting a collection of files and a step in this process is to delete columns that aren't required, keeping a specific set of columns.
I know I can delete columns based on their location and I have this approach implemented already ie 1,3,7 etc or A, C, G etc. But I'm conscious that the report being used might change layout or add extra columns over time and I want to ensure the required columns are kept.
Ideally this code would cycle through each column header starting at A1 until the last column and delete an entire column if the header value isn't found in a list. This list will be an array captured from a range in one of the sheets in the workbook.
List = {Blue, Green, Orange}
Original Table
Blue
Red
Green
Orange
Black
row
row
row
row
row
Formatted Table
Blue
Green
Orange
row
row
row
Does anyone have any suggestions on the approach I could take to get this working or if it's even possible? Any help would be greatly appreciated
You might profit from the following approach by reordering a datafield array via Application.Index which allows even to move the existing columns to any new position.
Note: this flexible solution can be time consuming for greater data sets,
where I would prefer other ways you can find in a lot of answers at SO.
Sub ReorderColumns()
Const headerList As String = "Blue,green,Orange"
'a) define source range
Dim src As Range
Set src = Tabelle3.Range("A1:E100")
'b) define headers
Dim allHeaders: allHeaders = src.Resize(1).Value2
Dim newHeaders: newHeaders = Split(headerList, ",")
'c) get column positions in old headers
Dim cols
cols = getCols(newHeaders, allHeaders)
'd) define data
Dim data As Variant
data = src.Value2
'e) reorder data based on found column positions
data = Application.Index(data, Evaluate("row(1:" & UBound(data) & ")"), cols)
'f) overwrite source data
src = vbNullString ' clear
src.Resize(UBound(data), UBound(data, 2)) = data
End Sub
Help function getCols()
Function getCols(individualHeaders, allHeaders)
'Purp: get 1-based column numbers of found headers via Match
getCols = Application.Match(individualHeaders, allHeaders, 0) ' 1-based
End Function
Please, test the next code. It is compact and fast enough. It will build the columns to be deleted range using Application.Match for the two involved arrays (the existing headers one and the ones to be kept). This code assumes that the headers exist in the first row of the processed sheets, starting from A:A column (If starting from a different column, the code can be adapted:
Sub DeleteColunsNotInArrayDel()
Dim sh As Worksheet, arrStay, lastCol As Long, arrH, arrCols, rngDel As Range
Set sh = ActiveSheet 'use here the sheet you need to process
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column 'last column on the first row
arrStay = Split("Blue,Green,Orange", ",") 'the headers to not be deleted array
arrH = Application.Transpose(Application.Transpose(sh.Range(sh.cells(1, 1), sh.cells(1, lastCol)).Value2)) 'existing headers array
arrCols = Application.IfError(Application.match(arrH, arrStay, 0), "xx") 'match the two arrays and place "xx" where no match has been found
makeColsRng(arrCols).Delete 'delete the columns range, at once
End Sub
Function makeColsRng(arr) As Range
Dim i As Long, colL As String, strAddr As String
For i = LBound(arr) To UBound(arr) 'iterate between the matched arrays array
If arr(i) = "xx" Then 'for the not matching case:
colL = Split(cells(1, i).Address, "$")(1) 'extract the letter of the respective column
strAddr = strAddr & colL & "1," 'build the string of the columns to be deleted range
End If
Next i
Set makeColsRng = Range(left(strAddr, Len(strAddr) - 1)).EntireColumn 'return the necessary range
End Function
In case of headers not starting from the first sheet column, the function can easily be adapted by adding a new parameter (the first column number) to be added when the range to be deleted is built.
The above suggested solution is a fancy one, just for the sake of showing the respective approach, which is not too often used. It may have a limitation of the range building, in case of a string bigger than 254 digits, No error handling for the case of everything matching (even, easy to be added). The next version is standard VBA, compact, more reliable, faster and easier to be understood:
Sub DeleteColunsRangeNotInArray()
Dim sh As Worksheet, arrStay, lastCol As Long, rngH As Range, rngDel As Range, i As Long
Set sh = ActiveSheet
lastCol = sh.cells(1, sh.Columns.count).End(xlToLeft).Column'last column on the first row
arrStay = Split("Blue,Green,Orange", ",") 'the headers to not be deleted array
Set rngH = sh.Range(sh.cells(1, 1), sh.cells(1, lastCol)) 'existing headers range
For i = 1 To rngH.Columns.count
If IsError(Application.match(rngH(i).Value, arrStay, 0)) Then 'if not a match in arrStay:
addToRange rngDel, rngH(i) 'build a Union range
End If
Next i
'delete the not necessary columns at once:
If Not rngDel Is Nothing Then rngDel.EntireColumn.Delete
End Sub
Private Sub addToRange(rngU As Range, rng As Range)
If rngU Is Nothing Then
Set rngU = rng
Else
Set rngU = Union(rngU, rng)
End If
End Sub
Dynamic Named Range
I think a dynamic named range is an excellent choice for storing and retrieving your required columns. Please see the link I provided from https://exceljet.net/ to setup your dynamic named range.
Generic formula =$A$2:INDEX($A:$A,COUNTA($A:$A))
Regular Expression Approach
After reading in your named range, one approach for testing your columns is using regular expressions. To use this you will need to set a library reference to Microsoft VBScript Regular Expressions 5.5. The pipe character | represents an or statement, so we can join our array using that delimiter.
Deleting Ranges in loops
When deleting columns or rows within a loop, the best approach I have found is to union the ranges together in a variable and execute the deletion in one go. This helps performance and it prevents errors from deleting ranges the loop is working on.
I do this so often that I created a custom function for this UnionRange
' Helper function that allows
' concatinating ranges together
Public Function UnionRange( _
ByRef accumulator As Range, _
ByRef nextRange As Range _
)
If accumulator Is Nothing Then
Set UnionRange = nextRange
Else
Set UnionRange = Union(accumulator, nextRange)
End If
End Function
Putting it all together
Below is my implementation of what your code could look like, just make sure to first:
Create a Dynamic Named Range and populate with your required headers
Add Microsoft VBScript Regular Expressions 5.5 reference
Update Sheet1 to whatever sheet your table exists (possibly change logic for finding header row based on your needs)
' Need Regular Expressions Referenced in order to work!
' #libraryReference {Microsoft VBScript Regular Expressions 5.5}
Public Sub DemoDeletingNonRequiredColumns()
' Make sure to create a named range
' otherwise this section will fail. In this
' example the named range is `RequiredColumns`
Dim requiredColumns() As Variant
requiredColumns = Application.WorksheetFunction.Transpose( _
Range("RequiredColumns").Value2 _
)
' To test if the column is in the required
' columns this method uses regular expressions.
With New RegExp
.IgnoreCase = True
' The pipe charactor is `or` in testing.
.Pattern = Join(requiredColumns, "|")
Dim headerRow As Range
' This example uses `Sheet1`, but update to
' the actual sheet you are using.
With Sheet1
Set headerRow = .Range("A1", .Cells(1, Columns.Count).End(xlToLeft))
End With
Dim column As Range
For Each column In headerRow
' If the column name doesn't match the
' pattern, then concatenate it to the
' toDelete range.
If Not .Test(column.Value2) Then
Dim toDelete As Range
Set toDelete = UnionRange(toDelete, column.EntireColumn)
End If
Next
End With
' toDelete is used as it provides better performance
' and it also prevents errors when deleting columns
' while looping.
If Not toDelete Is Nothing Then
toDelete.Delete
Set toDelete = Nothing
End If
End Sub
Delete Columns Not In a List
Option Explicit
Sub DeleteIrrelevantColumns()
' Source - the worksheet containing the list of headers.
Const sName As String = "Sheet2"
Const sFirstCellAddress As String = "A2"
' Destination - the worksheet to be processed.
Const dName As String = "Sheet1"
Const dFirstCellAddress As String = "A1"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sfCell As Range: Set sfCell = sws.Range(sFirstCellAddress)
Dim sData() As Variant
With sfCell
Dim slCell As Range: Set slCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
sData = .Resize(slCell.Row - .Row + 1).Value
End With
Dim sDict As Object: Set sDict = CreateObject("Scripting.Dictionary")
sDict.CompareMode = vbTextCompare
Dim sValue As Variant
Dim sr As Long
For sr = 1 To UBound(sData)
sValue = sData(sr, 1)
If Not IsError(sValue) Then ' exclude error values
If Len(sValue) > 0 Then ' exclude blanks
sDict(sValue) = Empty ' write
End If
End If
Next sr
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dfCell As Range: Set dfCell = dws.Range(dFirstCellAddress)
Dim drg As Range
With dfCell
Dim dlCell As Range: Set dlCell = _
.Resize(, dws.Columns.Count - .Column + 1) _
.Find("*", , xlFormulas, , , xlPrevious)
Set drg = .Resize(, dlCell.Column - .Column + 1)
End With
Dim dData() As Variant: dData = drg.Value
Dim dCells As Range
Dim dValue As Variant
Dim dc As Long
For dc = 1 To UBound(dData, 2)
dValue = dData(1, dc)
If sDict.Exists(dValue) Then
' If duplicate columns, keep only the left-most.
sDict.Remove dValue
Else
' Combine the irrelevant header cells into a range.
If dCells Is Nothing Then
Set dCells = drg.Cells(dc)
Else
Set dCells = Union(dCells, drg.Cells(dc))
End If
End If
Next dc
' Delete columns in one go.
If Not dCells Is Nothing Then
dCells.EntireColumn.Delete
End If
' Inform.
If sDict.Count = 0 Then
MsgBox "Irrelevant columns deleted.", vbInformation
Else
MsgBox "Irrelevant columns deleted." & vbLf & vbLf _
& "Columns not found:" & vbLf _
& Join(sDict.Keys, vbLf), vbCritical
End If
End Sub

How to bypass code if criteria don't match?

The code works when the criteria exists. I get an error when the criteria doesn't exist.
' Define constants.
Const srcName As String = "wfm_rawdata"
Const srcFirst As String = "D2" ' Location for Group
Const dstName As String = "bond_insurance"
Const dstFirst As String = "A2" ' do not change the 'A' (entire row).
'This function will transfer rows from one worksheet to another worksheet
' if the value = specified critiera
' Define workbook.
Dim wb As Workbook: Set wb = ActiveWorkbook ' Workbook containing this code.
' Define Source Range
Dim LastRow As Long
Dim srg As Range
' Define worksheet and column am working on and
' getting the range of last used cell using(LastRow)
With wb.Worksheets(srcName).Range(srcFirst)
LastRow = .Offset(.Worksheet.Rows.Count - .Row).End(xlUp).Row
Set srg = .Resize(LastRow - .Row + 1, 10)
End With
'Combine' critical cells into a range.
Dim brg As Range ' Built Range --> Range in the new sheet
Dim cel As Range ' Current Cell Range --> Range in the current sheet(rawdata)
'for every cell in group within wfm_rawdata sheet if the value = GO
For Each cel In srg.Cells
If cel.Value = "BOND INSURANCE" Then
' If the range in the new sheet have nothing then
' add specific criteria from the group in wfm_rawdata
If brg Is Nothing Then
Set brg = cel
' if there is range in there combine the new and
' old range together using -> Union function
Else
Set brg = Union(brg, cel)
End If
End If
Next cel
Application.ScreenUpdating = False
' Copy and delete critical rows of Source Range.
With wb.Worksheets(dstName).Range(dstFirst)
.Resize(.Worksheet.Rows.Count - .Row + 1, _
.Worksheet.Columns.Count).clear
Set brg = brg.EntireRow ' 'Convert' cells into rows.
brg.Copy .Offset ' Copy. 'Offset' because range is in 'With'.
brg.Delete ' Delete.
End With
How can I use a Boolean or other function to bypass the above code if the criteria doesn't exist?
For example if criteria "dog" exists then run the code and if it doesn't exist bypass the code.
I use this code to run three modules with code similar to the top code.
Sub master()
Call report1
Call report2
Call report3
End Sub
One you've assigned srg you can use Match() to check whether it contains any instances of the term you're interested in:
'...
'...
' Define worksheet and column am working on and getting the range of last used cell using(LastRow)
With wb.Worksheets(srcName).Range(srcFirst)
LastRow = .Offset(.Worksheet.Rows.Count - .Row).End(xlUp).Row
Set srg = .Resize(LastRow - .Row + 1, 10)
End With
'Exit if "BOND INSURANCE" is not found in `srg`
If IsError(Application.Match("BOND INSURANCE", srg, 0)) Then Exit Sub
'...
'...

Match data in row and copy

I am stuck. I have corresponding data on two sheets. I want to go down the rows in sheet1, use the value in column M, find the matching value in sheet3 column M, then copy the data into sheet1. Sheet1 is 4000 lines. My copy logic is working, unfortunately, my loop does not end and it copies row1 until excel freezes. Any assistance is greatly appreciated - obviously I am still a VBA novice.
Dim searchTerm As String
Dim r As Long
For i = 1 To 4000
searchTerm = Worksheets("Sheet1").Range("M" & i).Text
If Worksheets("Sheet1").Range("M" & i).Value = searchTerm Then
'Select row in Sheet1 to copy
Worksheets("Sheet3").Select
Range("A" & i & startcolumn & ":AU" & i & lastcolumn).Select
Selection.Copy
'Paste row into Sheet2 in next row
Sheets("Sheet1").Select
Columns("AX").Select
ActiveSheet.Paste
'Move counter to next row
'Go back to Sheet1 to continue searching
Sheets("Sheet1").Select
End If
Next i
A VBA Lookup
The following will loop through each cell in range "M1:M4000" of worksheet "Sheet1" and try to find each cell's value in column "M" of "Sheet3". If found, the values from columns "A" to column "AU" in the found row of worksheet "Sheet3" will be copied to worksheet "Sheet1", to the same sized row range starting with column "AX".
The Code
Option Explicit
Sub SimpleLookup()
' Define workbook.
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Destination
' Define Destination Worksheet.
Dim dst As Worksheet
Set dst = wb.Worksheets("Sheet1")
Dim lValue As Variant ' Lookup Value
Dim i As Long ' Destination Rows Counter
' Source
' Define Source Worksheet.
Dim src As Worksheet
Set src = wb.Worksheets("Sheet3")
' Define Copy Range.
Dim cRng As Range
Set cRng = src.Range("A1:AU4000")
' Define Lookup Column Range.
Dim lRng As Range
Set lRng = cRng.Columns(13)
Dim rRng As Range ' Current Copy Row Range
Dim lIndex As Variant ' Lookup Index
' Loop
' Loop through rows (cells) of Criteria Column Range.
For i = 1 To 4000
' Write the value of the current cell to a variable, Lookup Value.
lValue = dst.Cells(i, "M").Value
' Define Lookup Index, the index (row) where the Lookup value
' was found in Lookup Column Range.
lIndex = Application.Match(lValue, lRng, 0)
' Evaluate Lookup Index: it will be an error value if not found.
If Not IsError(lIndex) Then
' Define Current Copy Row Range.
Set rRng = cRng.Rows(lIndex)
' Either...:
' Values only.
' Copy Current Copy Row Range to Destination Worksheet.
dst.Cells(i, "AX").Resize(, rRng.Columns.Count).Value = rRng.Value
' ...Or:
' Values, formulas, formats.
'rRng.Copy Destionation:=dst.Cells(i, "AX")
End If
Next i
End Sub

Excel VBA search id and import data from other sheet

I'm working on a project with lots of data in two different sheets which is want to combine.
For example:
My Sheet1 should contain 4 columns. Columns 1 and 2 are already filled with ID's and a status.
In Sheet2 I have 3 columns. The first contains the ID's again, the second a serial-number and the third a Yes/No.
The two sheets have around 5500 rows in it. The first a little more then the second.
I would like to run a loop which picks the first ID in Sheet1, checks if it exists in Sheet2, and if it does, it should copy the two missing columns (serial-number and Yes/No) into into Sheet1.
Then the to the next Id in Sheet1 and do the same again.
I tried it with the code below, but I'm not getting it to work.
Hope you can help me out!
Dim i As Long
Dim Found As Range
For i = 1 To Rows.Count
Worksheets("Sheet1").Activate
If Cells(i, 1).Value <> "" Then
Set Found = Worksheets("Sheet2").Range("A2", Range("A")).Find(i, 1)
If Not Found Is Nothing Then
Worksheets("Sheet1").Range(i, 3).Value = Cells(Found.Row, 2).Value
Worksheets("Sheet1").Range(i, 4).Value = Cells(Found.Row, 3).Value
End If
End If
Next i
You could try with two nested for each loops.
Sub copySerial()
Dim range1 As Range, range2 As Range
Set range1 = Worksheets("Sheet1").Range("A2:A" & Cells(Rows.Count, 1).End(xlUp).Row)
Set range2 = Worksheets("Sheet2").Range("A2:A" & Cells(Rows.Count, 1).End(xlUp).Row)
For Each c1 In range1
For Each c2 In range2
If c1.Value = c2.Value Then
c1.Offset(0, 2).Value = c2.Offset(0, 1).Value
c1.Offset(0, 3).Value = c2.Offset(0, 2).Value
End If
Next c2
Next c1
End Sub
Arrays Before Ranges
Adjust the values in the constants section to fit your needs. Do it
carefully (slowly) because there are many.
First I created the second code which appeared to be super slow.
After implementing arrays, it got 30 times faster at 5000 records. I guess the extra work pays off.
Option Explicit
Sub UpdateSheetArray() ' Calculates for about 3s at 5000 records - Acceptable!
Const strSrc As String = "Sheet2" ' Source Worksheet Name
Const frSrc As Long = 2 ' Source First Row Number
Const colSrc As Long = 1 ' Source Compare Column Number
Const colSrc1 As Long = 2 ' Source Data Column 1
Const colSrc2 As Long = 3 ' Source Data Column 2
Const strTgt As String = "Sheet1" ' Target Worksheet Name
Const frTgt As Long = 1 ' Target First Row Number
Const colTgt As Long = 1 ' Target Compare Column Number
Const colTgt1 As Long = 3 ' Target Data Column 1
Const colTgt2 As Long = 4 ' Target Data Column 2
Dim wsSrc As Worksheet ' Source Worksheet
Dim wsTgt As Worksheet ' Target Worksheet
Dim vntSrc As Variant ' Source Compare Array
Dim vntSrc1 As Variant ' Source Data Array 1
Dim vntSrc2 As Variant ' Source Data Array 2
Dim vntTgt As Variant ' Target Compare Array
Dim vntTgt1 As Variant ' Target Data Array 1
Dim vntTgt2 As Variant ' Target Data Array 2
Dim rngSrc As Range ' Source Compare Range,
' Source Data Range 1,
' Source Data Range 2
Dim rngTgt As Range ' Target Compare Range,
' Target Data Range 1,
' Target Data Range 2
Dim lrSrc As Long ' Source Last Non-Empty Row Number
Dim lrTgt As Long ' Target Last Non-Empty Row Number
Dim varCur As Variant ' Current Target Cell Value
Dim i As Long ' Source Row Counter
Dim j As Long ' Target Row Counter
' Define Source and Target Worksheets.
Set wsSrc = Worksheets(strSrc)
Set wsTgt = Worksheets(strTgt)
' Calculate Last Non-Empty Row in Source Worksheet.
lrSrc = wsSrc.Columns(colSrc).Find(What:="*", LookIn:=xlFormulas, _
SearchDirection:=xlPrevious).Row
' Calculate Last Non-Empty Row in Target Worksheet.
lrTgt = wsTgt.Columns(colTgt).Find(What:="*", LookIn:=xlFormulas, _
SearchDirection:=xlPrevious).Row
' Define Source Compare Range and write its values to Source Compare Array.
Set rngSrc = wsSrc.Cells(frSrc, colSrc).Resize(lrSrc - frSrc + 1)
vntSrc = rngSrc
' Define Source Data Range 1 and write its values to Source Data Array 1.
Set rngSrc = rngSrc.Offset(, colSrc1 - colSrc): vntSrc1 = rngSrc
' Define Source Data Range 2 and write its values to Source Data Array 2.
Set rngSrc = rngSrc.Offset(, colSrc2 - colSrc1): vntSrc2 = rngSrc
' Define Target Compare Range and write its values to Target Compare Array.
Set rngTgt = wsTgt.Cells(frTgt, colTgt).Resize(lrTgt - frTgt + 1)
vntTgt = rngTgt
' Define Target Data Arrays (same size as Target Compare Array).
ReDim vntTgt1(1 To UBound(vntTgt), 1 To 1)
ReDim vntTgt2(1 To UBound(vntTgt), 1 To 1)
' Note: These last two arrays are going to be written to,
' while the previous four are going to be read from.
' All arrays are 2-dimensional 1-based 1-column arrays.
' Loop through elements of Target Compare Array.
For i = 1 To UBound(vntTgt)
' Write value of current element in Target Array
' to Current Target Cell Value.
varCur = vntTgt(i, 1)
' Check if Current Target Cell Value is not "".
If varCur <> "" Then
' Loop through elements of Source Compare Array.
For j = 1 To UBound(vntSrc)
' Check if value of current element in Source Array is equal
' to Current Target Cell Value.
If vntSrc(j, 1) = varCur Then
' Write current elements in Source Data Arrays
' to Target Data Arrays.
vntTgt1(i, 1) = vntSrc1(j, 1): vntTgt2(i, 1) = vntSrc2(j, 1)
' No need to loop anymore after found.
Exit For
End If
Next
End If
Next
' Define Target Data Range 1.
Set rngTgt = rngTgt.Offset(, colTgt1 - colTgt)
' Write values of Target Data Array 1 to Target Data Range 1.
rngTgt = vntTgt1
' Define Target Data Range 2.
Set rngTgt = rngTgt.Offset(, colTgt2 - colTgt1)
' Write values of Target Data Array 2 to Target Data Range 2.
rngTgt = vntTgt2
End Sub
Sub UpdateSheetRange() ' Calculates for about 90s at 5000 records - too slow!
Const strSrc As String = "Sheet2" ' Source Worksheet Name
Const frSrc As Long = 2 ' Source First Row Number
Const colSrc As Long = 1 ' Source Compare Column Number
Const colSrc1 As Long = 2 ' Source Data Column 1
Const colSrc2 As Long = 3 ' Source Data Column 2
Const strTgt As String = "Sheet1" ' Target Worksheet Name
Const frTgt As Long = 1 ' Target First Row Number
Const colTgt As Long = 1 ' Target Compare Column Number
Const colTgt1 As Long = 3 ' Target Data Column 1
Const colTgt2 As Long = 4 ' Target Data Column 2
Dim wsSrc As Worksheet ' Source Worksheet
Dim wsTgt As Worksheet ' Target Worksheet
Dim lrSrc As Long ' Source Last Non-Empty Row Number
Dim lrTgt As Long ' Target Last Non-Empty Row Number
Dim varCur As Variant ' Current Target Cell Value
Dim i As Long ' Source Row Counter
Dim j As Long ' Target Row Counter
' Define Worksheet.
Set wsSrc = Worksheets(strSrc)
Set wsTgt = Worksheets(strTgt)
' Calculate Last Non-Empty Row in Source Worksheet.
lrSrc = wsSrc.Columns(colSrc).Find(What:="*", LookIn:=xlFormulas, _
SearchDirection:=xlPrevious).Row
' Calculate Last Non-Empty Row in Target Worksheet.
lrTgt = wsTgt.Columns(colTgt).Find(What:="*", LookIn:=xlFormulas, _
SearchDirection:=xlPrevious).Row
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
On Error GoTo ProgramError
For i = frTgt To lrTgt
varCur = wsTgt.Cells(i, colTgt).Value
If varCur <> "" Then
For j = frSrc To lrSrc
If wsSrc.Cells(j, colSrc).Value = varCur Then
wsTgt.Cells(i, colTgt1) = wsSrc.Cells(j, colSrc1).Value
wsTgt.Cells(i, colTgt2) = wsSrc.Cells(j, colSrc2).Value
Exit For
End If
Next
End If
Next
SafeExit:
With Application
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
Exit Sub
ProgramError:
MsgBox "An unexpected error occurred."
On Error GoTo 0
GoTo SafeExit
End Sub

Search first sheet coumn name in another sheet coumn and insert that column data

I have 2 workbook i.e workbook A and Workbook B
A workbook having column in order A,B,C,D and B workbook having Column D,C,B,A.
I have to insert A workbook data into B workbook in proper column that is the columns inserted into proper column A in A ,B in B, C in C, D in D
I tried below code
Sub DEMO()
For i = 1 To 4
For j = 2 To 4
For k = 2 To 4
If Sheets(1).Cells(i, j).Value = Sheets(2).Cells(i, j).Value Then
Sheets(2).Cells(k, j).Value = Sheets(1).Cells(j, i).Value
End If
Next k
'MsgBox Sheets(1).Cells(2, 1).Value
'MsgBox Sheets(2).Cells(2, 1).Value
Next j
Next i
End Sub
Please help on this
To match the column names of …
Worksheet A
with the column names in …
Worksheet B
Use a loop and the WorksheetFunction.Match method
Option Explicit
Sub MatchColumns()
Dim wsA As Worksheet 'define worksheet A
Set wsA = ThisWorkbook.Worksheets("A")
Dim ColsRangeA As Range 'get column names in A
Set ColsRangeA = wsA.Range("A1", wsA.Cells(1, wsA.Columns.Count).End(xlToLeft))
Dim wsB As Worksheet 'define worksheet B
Set wsB = ThisWorkbook.Worksheets("B")
Dim ColsRangeB As Range 'get column names in B
Set ColsRangeB = wsB.Range("A1", wsB.Cells(1, wsB.Columns.Count).End(xlToLeft))
Dim MatchedColNo As Long
Dim Col As Range
For Each Col In ColsRangeA 'loop throug column names in A
MatchedColNo = 0 'initialize
On Error Resume Next 'test if column name can be found in worksheet B column names
MatchedColNo = Application.WorksheetFunction.Match(Col.Value, ColsRangeB, False)
On Error GoTo 0
If MatchedColNo <> 0 Then 'if name was found
wsB.Cells(2, MatchedColNo).Value = "Matches wsA col " & Col.Column
Else 'if name didn't match
MsgBox "no maching column found for " & Col.Value
End If
Next Col
End Sub
Copy Below Headers
The Code
'*******************************************************************************
'Purpose: Copies the values below headers from one worksheet
' to another containing the same headers.
'*******************************************************************************
Sub CopyBelowHeaders()
' !!! Header List !!! Change this to any comma separated string containing
' the values of the headers e.g. "ID, Product,Count, Price,Stock ".
Const cHeaders As String = "A,B,C,D"
Const cSource As String = "Sheet1" ' Source Worksheet Name
Const cTarget As String = "Sheet2" ' Target Worksheet Name
Const cFirstR As Long = 2 ' First Row Number
Dim rngS As Range ' Current Source Header Cell Range,
' Current Source Column Last Used Cell Range,
' Current Source Column Range
Dim rngT As Range ' Current Target Header Cell Range,
' Current Target Column Range
Dim vntH As Variant ' Header Array
Dim vntS As Variant ' Source Header Column Array
Dim vntT As Variant ' Target Header Column Array
Dim i As Long ' Header Arrays Element Counter
vntH = Split(cHeaders, ",") ' Write Header List to Header Array.
ReDim vntS(UBound(vntH)) As Long ' Resize Source Header Column Array.
ReDim vntT(UBound(vntH)) As Long ' Resize Target Header Column Array.
' Column Numbers to Column Arrays
' In Source Worksheet
With ThisWorkbook.Worksheets(cSource)
' Loop through elements of Header Array.
For i = 0 To UBound(vntH)
' In Source Row Range (Header Row, 1st Row)
With .Rows(1)
' Find current element (string) of Header Array
' in Source Row Range.
Set rngS = .Find(Trim(vntH(i)), .Cells(.Cells.Count), _
xlValues, xlWhole, xlByRows, xlNext)
' When current element was found, write column number to
' Source Header Columns Array.
If Not rngS Is Nothing Then vntS(i) = rngS.Column
End With
Next
End With
' In Target Worksheet
With ThisWorkbook.Worksheets(cTarget)
' Loop through elements of Header Array.
For i = 0 To UBound(vntH)
' In Target Row Range (Header Row, 1st Row)
With .Rows(1)
' Find current element (string) of Header Array
' in Target Row Range.
Set rngT = .Find(Trim(vntH(i)), .Cells(.Cells.Count), _
xlValues, xlWhole, xlByRows, xlNext)
' When current element was found, write column number to
' Source Header Columns Array.
If Not rngS Is Nothing Then vntT(i) = rngT.Column
End With
Next
End With
' Source Worksheet to Target Worksheet
' In Source Worksheet
With ThisWorkbook.Worksheets(cSource)
' Loop through elements of Source Array.
For i = 0 To UBound(vntS)
' When current element of Source Header Column Array and current
' element of Target Header Column Array are different than "".
If vntS(i) > 0 And vntT(i) > 0 Then
' Find Last Used Cell Range in current Source Column Range.
Set rngS = .Columns(vntS(i)).Find("*", , xlFormulas, _
xlWhole, xlByColumns, xlPrevious)
' When current Source Column is not empty.
If Not rngS Is Nothing Then
' When current Source Column contains data in at least
' one more row than the Source Header row.
If rngS.Row > 1 Then
' Calculate Source Column Range.
Set rngS = .Range(.Cells(cFirstR, vntS(i)), rngS)
' In First Cell of Target Column Range
With ThisWorkbook.Worksheets(cTarget) _
.Cells(cFirstR, vntT(i))
' Clear contents in Target Column Range from
' First Cell to bottom cell.
.Resize(Rows.Count - cFirstR + 1).ClearContents
' Resize Current Target Column Range to the size
' of Current Source Column Range.
Set rngT = .Resize(rngS.Rows.Count)
End With
' Copy values from Current Source Column Range to
' Current Target Column Range.
rngT = rngS.Value
End If
End If
End If
Next
End With
End Sub

Resources