how to copy data from csv sheet to excel sheet if column header match - excel

Option Explicit
Function GetHeadersDict() As Scripting.Dictionary
' We must activate the Microsoft Scripting Runtime from Tools --References
Dim result As Scripting.Dictionary
Set result = New Scripting.Dictionary
With result
.Add "Name", False
.Add "Mobile", False
.Add "Phone", False
.Add "City", False
.Add "Designation", False
.Add "DOB", False
End With
Set GetHeadersDict = result
End Function
Function FindHeaderRange(ByVal ws As Worksheet, ByVal header As String) As Range
Set FindHeaderRange = ws.Cells.Find(header, , , xlWhole)
End Function
Sub clearDataSheet2()
Sheets("Destination").Range("A1").CurrentRegion.Offset(1).ClearContents
End Sub
Sub copyColumnData()
On Error GoTo ErrorMessage
Dim ws1 As Worksheet, ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Source")
Set ws2 = ThisWorkbook.Sheets("Destination")
clearDataSheet2
Dim numRowsToCopy As Long
numRowsToCopy = ws1.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row - 1
'MsgBox "The no of rows to copy is " & numRowsToCopy
Dim destRowOffset As Long
destRowOffset = ws2.Cells(RowIndex:=Rows.Count, ColumnIndex:=1).End(xlUp).Row
'MsgBox "The next Blank row is " & destRowOffset
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim dictKey As Variant
Dim header As String
Dim numColumnsToCopy As Long
Dim source As Range
Dim dest As Range
Dim headersDict As Scripting.Dictionary
Set headersDict = GetHeadersDict()
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
Set source = FindHeaderRange(ws1, header)
If Not (source Is Nothing) Then
Set dest = FindHeaderRange(ws2, header)
If Not (dest Is Nothing) Then
headersDict.Item(header) = True
' Look at successive headers to see if they match
' If so, copy these columns altogether to make the macro faster
For numColumnsToCopy = 1 To headersDict.Count
'MsgBox numColumnsToCopy
If source.Offset(ColumnOffset:=numColumnsToCopy).Value = dest.Offset(ColumnOffset:=numColumnsToCopy).Value Then
headersDict.Item(source.Offset(ColumnOffset:=numColumnsToCopy).Value) = True
Else
Exit For
End If
Next numColumnsToCopy
source.Offset(RowOffset:=1).Resize(RowSize:=numRowsToCopy, ColumnSize:=numColumnsToCopy).Copy _
dest.Offset(RowOffset:=destRowOffset)
End If
End If
End If
Next dictKey
Dim msg As String
For Each dictKey In headersDict
header = dictKey
If headersDict.Item(header) = False Then
msg = msg & vbNewLine & header
End If
Next dictKey
ExitSub:
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
If msg Not Equal To "" Then
MsgBox "The following headers were not copied:" & vbNewLine & msg
End If
Exit Sub
ErrorMessage:
MsgBox "An error has occurred: " & Err.Description
Resume ExitSub
End Sub
This code works perfectly but i am unable to satisfy two condition:-
Destination excel has Column header in second row. I am unable to compare column header in second row and paste the data from third row
i am unable to read source file as csv and i want to give path by user how can i do that .

Welcome to stack. Assuming you didn't wrote this code yourself you'll need to be willing to learn if you want our help.
That said, all beginning is difficult so assuming you just want to copy columns from a CSV based on a limited list of predefined headers the script you posted is a total overkill imho. So I propose to use this as our base:
Option Explicit
Sub move()
Dim arr, arr2, j As Long, i As Long
arr = Sheet1.Range("A1").CurrentRegion.Value2 'get the source, we'll replace this with the csv import later
ReDim arr2(1 To UBound(arr), 1 To UBound(arr, 2)) 'setup the destination array
For j = 1 To UBound(arr) 'rows, start at the header row
For i = 1 To UBound(arr, 2) 'columns
Select Case arr(1, i)
Case "Name" 'the column names we want to match
arr2(j, 1) = arr(j, i)
'Add the rest of your cols here with Case colname
End Select
Next i
Next j
With Sheet2
.Range(.Cells(1, 1), .Cells(UBound(arr2), UBound(arr2, 2))).Value2 = arr2 'dump to sheet, if you want your destination to start at row 3 change it here
End With
End Sub
It's not yet doing what you want but it should get you on the right path. Complete the code above and post it again if you want more help.

Related

Filter specific data and move it with header to new sheet

I have a list of 10 specific customers that I need excel to search and filter their numbers among hundred of customers in column D and when it finds them, based on their company code in column A, move the filtered range to a new sheet with a header (i want to move each customer with a header, not all of them under the same header) and name the news sheet same as the company code in column A
My Columns go from A to AC
What it looks like:
I wonder how can i pull this successfully using VBA
Adding Header to each customer:
Please, test the next code. It, basically, uses a dictionary to keep unique Company Codes, an array for the ten customers, a column array to faster load the dictionary:
Sub CopyFilteredCustomersByCompanyNames()
Dim wb As Workbook, ws As Worksheet, lastR As Long, wsComp As Worksheet, dictC As Object
Dim rngFilt As Range, arrCust() As Variant, arrFilt, i As Long
arrCust = Array("108169651", "108169651", "108169430", "108169430", "108168704", "108169596") 'place here the 10 specific customers name
Set wb = ActiveWorkbook 'use here the workbook you need
Set ws = ActiveSheet 'use here the necessary sheet (the one to be processed)
If ws.FilterMode Then ws.ShowAllData
Set rngFilt = ws.Range("A1").CurrentRegion: ' Debug.Print rngFilt.Address: Stop
arrFilt = rngFilt.Value2 'place the range in an array for faster iteration
'extract the uneque Company Names:
Set dictC = CreateObject("Scripting.Dictionary")
For i = 2 To UBound(arrFilt)
If arrFilt(i, 1) <> "" Then
dictC(arrFilt(i, 1)) = dictC(arrFilt(i, 1)) + 1
End If
Next i
Application.ScreenUpdating = False 'optimization to make code faster
Dim keyC As Variant, rngF As Range, rngF1 As Range
For Each keyC In dictC.Keys 'iterate between dictionary keys (A:A company names)
rngFilt.AutoFilter 1, keyC 'first filter by dict key
rngFilt.AutoFilter 4, arrCust, xlFilterValues 'second by array of customers numbers
Set wsComp = Nothing
'insert the necessary sheets, name them (if not existing), clear if existing and copy the filtered range
Application.EnableEvents = False: Application.Calculation = xlCalculationManual
Application.AutomationSecurity = msoAutomationSecurityForceDisable
On Error Resume Next
Set wsComp = wb.Worksheets(keyC)
On Error GoTo 0
If Not wsComp Is Nothing Then
wsComp.Cells.ClearContents
Else
Set wsComp = wb.Worksheets.Add(After:=ws)
wsComp.Name = keyC
End If
rngFilt.Rows(1).Copy ' copy the headers columns width
wsComp.Range("A1").Resize(, rngFilt.Rows(1).Columns.Count).PasteSpecial xlPasteColumnWidths
On Error Resume Next
Set rngF1 = Nothing
Set rngF1 = rngFilt.Resize(rngFilt.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible):
Set rngF = rngFilt.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rngF1 Is Nothing Then
rngF.Copy wsComp.Range("A1")
Else
Application.DisplayAlerts = False
wb.Worksheets(keyC).Delete
Application.DisplayAlerts = True
End If
ws.ShowAllData
Application.AutomationSecurity = msoAutomationSecurityByUI
Application.EnableEvents = True: Application.Calculation = xlCalculationAutomatic
Next keyC
Application.ScreenUpdating = True
MsgBox "Ready..."
End Sub
Please, send some feedback after testing it.
If something not clear enough, do not hesitate to ask for clarifications.
First create a tab by name CCList & enter all 10 company codes
for which you have to generate the report.
Secondly Paste the data in the Data tab.
Run this code.
In a new module
Sub GenerateReport()
Dim WsData As Worksheet, WsCCList As Worksheet
Dim FRow As Long, LRow As Long, FCol As Long, LCol As Long
Dim CCFrow As Long, CCLRow As Long, CCCol As Long, CCCounter As Long
Dim ValidationRng As Range, DataRng As Range, SrchString As String
Set WsData = Worksheets("Data")
Set WsCCList = Worksheets("CCList")
WsData.Activate
FRow = 1
FCol = 1
LRow = WsData.Cells(WsData.Rows.Count, FCol).End(xlUp).Row
LCol = WsData.Cells(FRow, WsData.Columns.Count).End(xlToLeft).Column
Set DataRng = WsData.Range(Cells(FRow, FCol), Cells(LRow, LCol))
WsCCList.Activate
CCFrow = 2
CCCol = 1
CCLRow = WsCCList.Cells(WsCCList.Rows.Count, CCCol).End(xlUp).Row
For CCCounter = CCFrow To CCLRow
SrchString = ""
SrchString = WsCCList.Cells(CCCounter, CCCol)
If SrchString = "" Then Exit Sub
If WsData.AutoFilterMode = True Then WsData.AutoFilterMode = False
DataRng.AutoFilter Field:=1, Criteria1:=SrchString, Operator:=xlFilterValues
On Error Resume Next
Set ValidationRng = Nothing
Set ValidationRng = WsData.AutoFilter.Range.Offset(1, 0).Resize(DataRng.Rows.Count - 1, DataRng.Columns.Count).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If ValidationRng Is Nothing Then
'do nothing
Else
Worksheets.Add After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count)
ActiveSheet.Name = SrchString
DataRng.SpecialCells(xlCellTypeVisible).Copy
ActiveSheet.Range("a1").PasteSpecial
Application.CutCopyMode = False
End If
If WsData.AutoFilterMode = True Then WsData.AutoFilterMode = False
Next CCCounter
WsCCList.Select
MsgBox "Task Completed"
End Sub

While Deleting Repeated Headers

Using the below code to delete the repeated headers from combined into one excel but getting error.
Application.Goto DestSh.Cells(1)
' AutoFit the column width in the summary sheet.
DestSh.Columns.AutoFit
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
Dim xWs As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
For Each xWs In Application.ActiveWorkbook.Worksheets
If xWs.Name <> "Combined Sheet" Then
xWs.Delete
End If
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Dim lstRow As Integer, ws As Worksheet
Set ws = ThisWorkbook.Sheets("Combined Sheet")
With ws
lstRow = .Cells(rows.Count, "B").End(xlUp).Row ' Or "C" or "A" depends
.Range("A1:E" & lstRow).SpecialCells(xlCellTypeBlanks).EntireRow.Delete ERROR GETTING HERE
End With
enter image description here
Please add "on error resume next" before using SpecialCells method and after using use "on error GoTo 0"
.SpecialCells(xlCellTypeBlanks)
This expression gives you every blank cell in a Range. Rows that you are going to delete includes non-blank cells also, so vba will not delete them.
You can try a RemoveDuplicates method like:
.Range("A1:E" & lstRow).RemoveDuplicates Columns:=Array(1, 2, 3, 4, 5), Header :=xlNo
It can be not safe to use the method, but for your task it's may be Ok.
This sub is a safe variant to delete your headers. you can call the sub by the Call statement, and don't forget to set your header address.
Call removeHeaders()
Sub removeHeaders()
Dim hdrRangeAdr As String
Dim l, frstRow, lstRow, offsetRow As Long
Dim counter, row1, row2 As Integer
Dim item As Variant
Dim hdrRng, tRng As Range
Dim ws As Worksheet
' setting of the first header address
hdrRangeAdr = "A1:O1"
Set ws = ThisWorkbook.Sheets("Combined Sheet")
' setting of the header range
Set hdrRng = ws.Range(hdrRangeAdr)
hdrRowsQty = hdrRng.Rows.Count
frstRow = hdrRng.Row
lstRow = hdrRng.Parent.UsedRange.Rows.Count + frstRow
'checking row by row
For l = 1 To lstRow - frstRow
offsetRow = l + hdrRowsQty - 1
counter = 0
' compare row/rows value with the header
For Each item In hdrRng.Cells
If item = item.Offset(offsetRow, 0) Then
counter = counter + 1
End If
Next
' if they are equial then delete rows
If counter = hdrRng.Count Then
row1 = frstRow + offsetRow
row2 = row1 + hdrRowsQty - 1
ws.Rows(row1 & ":" & row2).Delete Shift:=xlUp
'reseting values as rows qty reduced
l = 1
lstRow = hdrRng.Parent.UsedRange.Rows.Count + frstRow
End If
Next
Set ws = Nothing
Set hdrRng = Nothing
End Sub
Good luck

Delete Sheet if contains only one column with text

I have a workbook with multiple sheets.
I want to check if each sheet has more than one column of content. If not delete it.
This would have to be deleted:
This not:
Try this code, please.
Edited: In order to answer your last question from the comment, the initial Sub will be adapted to call two other subs, able to add numbers to existing headers, in order to make them unique:
Sub deleteSheetsOneColumn()
Dim wb As Workbook, sh As Worksheet, nrCol As Long, i As Long
Set wb = ActiveWorkbook
For Each sh In wb.Worksheets
If sh.Cells(1, Columns.Count).End(xlToLeft).Column = 1 Then
Application.DisplayAlerts = False
sh.Delete
Application.DisplayAlerts = True
Else
'testUniQHeaders sh 'the simple solution (need to uncomment it and comment the next line
testUniQueH sh 'comment the previous line, to make it working
End If
Next
End Sub
The code will also delete the empty sheets, too...
The next sub will simply add an incremented number to each existing header, making it unique:
Sub testUniQHeaders(sh As Worksheet)
Dim nrCol As Long, i As Long
nrCol = sh.Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To nrCol
sh.Cells(1, i).Value = sh.Cells(1, i).Value & " " & i
Next i
End Sub
The next one, will load each column header in a dictionary, in a tricky way and use the result in order to adapt only the headers appearing more then once:
Private Sub testUniQueH(sh As Worksheet)
Dim nrCol As Long, i As Long, dict As Object, strH As String, key As Variant
Dim arrK As Variant
Set dict = CreateObject("Scripting.Dictionary")
nrCol = sh.Cells(1, Columns.Count).End(xlToLeft).Column
'input cols in the dictionary
For i = 1 To nrCol
strH = sh.Cells(1, i).Value
If Not dict.Exists(strH) Then
dict.aDD key:=strH, Item:=Array(1, i) 'init number plus column number
Else
dict(strH) = Array(dict(strH)(0) + 1, dict(strH)(1) & "|" & i) 'add occurrences and col no
End If
Next i
For Each key In dict.Keys
If CLng(dict(key)(0)) > 1 Then
arrK = Split(dict(key)(1), "|")
For i = 1 To UBound(arrK)
sh.Cells(1, CLng(arrK(i))).Value = _
sh.Cells(1, CLng(arrK(i))).Value & " " & i
Next i
End If
Next
End Sub

Copy/Paste columns

I have several columns with headers in one excel workbook, I want to copy some of these columns into another workbook.
Let’s say I have my origin workbook:
Ident|Name|Code|Part|Desc|U|Total
These are the headers of the columns with some data below them.
And I want to copy only the data in the columns Ident, Code and Part in another workbook that has the same headers but in a different order with the exception that one header has a different name:
Code|Ident|Piece
It is blank and Piece corresponds to Part.
So I want a code that takes the data from the origin workbook and copy it to the destination workbook. Also if possible I’d like that you can choose the original workbook from a file as I have different excel files to choose from.
Thank you for your answers. I have never used VBA and I’m trying to learn.
I have the following code that lets you choose the data you want manually but I want something similar that does it automatically after recognizing the headers.
Sub ImportDatafromotherworksheet()
Dim wkbCrntWorkBook As Workbook
Dim wkbSourceBook As Workbook
Dim rngSourceRange As Range
Dim rngDestination As Range
Set wkbCrntWorkBook = ActiveWorkbook
With Application.FileDialog(msoFileDialogOpen)
.Filters.Clear
.Filters.Add "Excel 2007-13", "*.xlsx; *.xlsm; *.xlsa"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
Workbooks.Open .SelectedItems(1)
Set wkbSourceBook = ActiveWorkbook
Set rngSourceRange = Application.InputBox(prompt:="Select source range", Title:="Source Range", Default:="A1", Type:=8)
wkbCrntWorkBook.Activate
Set rngDestination = Application.InputBox(prompt:="Select destination cell", Title:="Select Destination", Default:="A1", Type:=8)
rngSourceRange.Copy rngDestination
rngDestination.CurrentRegion.EntireColumn.AutoFit
wkbSourceBook.Close False
End If
End With
End Sub
I add here some part I modified:
arrC = Split("CODE|ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.Count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).Value
'Copy the columns:
arrC = Split("CODE|ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.Count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).Value
'Copy the columns:
For j = 0 To UBound(arrC)
If arrC(j) = "Ident" Then strH = "ident" Else strH = arrC(j)
If arrC(j) = "Code" Then strH = "CODE" Else strH = arrC(j)
If arrC(j) = "Piece" Then strH = "Part" Else strH = arrC(j)
For i = 1 To UBound(arrO, 2)
If arrO(1, i) = strH Then
lastRowO = shO.Cells(Rows.Count, i).End(xlUp).Row 'last row of the found orig header column
lastRowC = shC.Cells(Rows.Count, j + 1).End(xlUp).Row 'last row of toCopy sheet header column
arrTransf = shO.Range(shO.Cells(2, i), shO.Cells(lastRowO, i)).Value
Set copyCell = shC.Range(shC.Range("A1"), shC.Cells(1, lastColO)).Find(arrC(j))
If copyCell Is Nothing Then MsgBox "There is not a column named """ & _
arrC(j) & """ in the page to Copy.": Exit Sub
copyCell.Offset(1, 0).Resize(UBound(arrTransf, 1), UBound(arrTransf, 2)).Value = arrTransf
End If
Next i
Next j
End Sub
Try this code, please. It copies columns from the active sheet to shC worksheet, which must be set in the code below:
Sub moveColumnsContent()
Dim shO As Worksheet, shC As Worksheet, lastRowO As Long, lastRowC As Long
Dim arrO As Variant, arrC As Variant, lastColO As Long, lastColC As Long
Dim El As Variant, arrTransf As Variant, strH As String, copyCell As Range
Dim wbNumb As Variant, wb As Workbook, ws As Worksheet, strWB As String
Dim WbC As Workbook, sh As Worksheet, strWh As String, shNunb As String
Dim i As Long, j As Long
Set shC = ActiveSheet
WbSelection:
For i = 1 To Workbooks.count
strWB = strWB & Workbooks(i).Name & " - " & i & vbCrLf
Next i
wbNumb = InputBox("Please, write the the right workbook name number to be chosen:" & vbCrLf & _
vbCrLf & strWB, "Choose the workbook from where to copy columns!", 1)
If wbNumb = "" Then MsgBox "You did not select anything and code stops!"
Exit Sub
If IsNumeric(wbNumb) Then
On Error Resume Next
Set WbC = Workbooks(CLng(wbNumb))
if Err.Number<> 0 Then
Err.Clear: On Error GoTo 0:Exit Sub
End If
On Error GoTo 0
Else
MsgBox "Please select the number to the right side of the chosen workbook!": GoTo WbSelection
End If
WsSelection:
For i = 1 To WbC.Worksheets.count
strWh = strWh & WbC.Worksheets(i).Name & " - " & i & vbCrLf
Next
shNunb = InputBox("Please, write the the right sheet name number to be chosen:" & vbCrLf & _
vbCrLf & strWh, "Select the worksheet to be used for copying the columns!", 1)
If shNunb = "" Then MsgBox "Please select a worksheet number to be selected for copying columns!": _
GoTo WsSelection
Set shO = WbC.Worksheets(CLng(shNunb))
arrC = Split("Code|Ident|Piece", "|")
lastColO = shO.Cells(1, Cells.Columns.count).End(xlToLeft).Column
arrO = shO.Range(shO.Cells(1, 1), shO.Cells(1, lastColO)).value
'Copy the columns:
For j = 0 To UBound(arrC)
If arrC(j) = "Piece" Then strH = "Part" Else strH = arrC(j)
For i = 1 To UBound(arrO, 2)
If arrO(1, i) = strH Then
lastRowO = shO.Cells(Rows.count, i).End(xlUp).Row 'last row of the found orig header column
lastRowC = shC.Cells(Rows.count, j + 1).End(xlUp).Row 'last row of toCopy sheet header column
arrTransf = shO.Range(shO.Cells(2, i), shO.Cells(lastRowO, i)).value
Set copyCell = shC.Range(shC.Range("A1"), shC.Cells(1, lastColO)).Find(arrC(j))
If copyCell Is Nothing Then MsgBox "There is not a column named """ & _
arrC(j) & """ in the page to Copy.": Exit Sub
copyCell.Offset(1, 0).Resize(UBound(arrTransf, 1), UBound(arrTransf, 2)).value = arrTransf
End If
Next i
Next j
End Sub
If you will need more headers in the sheet to copy, it is enough to add them in "Code|Ident|Piece" string.
Now, trying to think how it would be more convenient for you to use it, probably, a better way would be to name the sheet where from the columns will be copied, in a specific way (maybe "MasterSheet") and copy the columns to the active one. Or, iterate between all Workbook sheets and do this process automatically. But, please, try the code as it is and let me know how looks more convenient for you.
If your intention is to extract a three columns set in the fixed order Code|Ident|Part=Piece copying them to the first three target columns A:C, you may try the following Rearrange procedure executing these steps:
[0-1] get source data
[2 ] rearrange columns of source data in a given order by a one-liner instead of copying separate columns arrays each time
[3 ] write (rearranged) data to target sheet
Sub Rearrange(src As Worksheet, tgt As Worksheet)
'Purpose: extract and rearrange data array columns
'Author: https://stackoverflow.com/users/6460297/t-m
With src
'[0] get last row of source data in column A:A (Ident)
Dim lastRow As Long: lastRow = .Range("A" & .Rows.Count).End(xlUp).Row
'[1] assign data to (1-based) 2-dim variant datafield array
Dim data: data = .Range("A2:G" & lastRow)
'[2] rearrange columns
' where Array(3,1,4) gets the 3rd, 1st and 4th column only
' (and Evaluate("ROW(1:nnn)") gets the entire row set)
data = Application.Index(data, Evaluate("ROW(1:" & (lastRow - 1) & ")"), Array(3, 1, 4))
End With
'[3] write (rearranged) data to target sheet
tgt.Range("A2").Resize(UBound(data), 3) = data
End Sub
If, however you are confronted with a variable target column structure you might play around with Moving columns based on header name and change it to your needs :-)
This should work, you only need to tweak the target sheet and, if it were the case, add more cases where origin/target have different column names:
Option Explicit
Sub Main()
Dim arrOrigin As Variant: arrOrigin = GetArrayFromSheet
Dim OriginHeaders As New Dictionary: Set OriginHeaders = GetOriginHeaders(arrOrigin)
With ThisWorkbook.Sheets("Your target sheet name") 'change this name
Dim arrTarget As Variant: ReDim arrTarget(1 To UBound(arrOrigin), _
1 To .UsedRange.Columns.Count)
'Last row on column 1 (or column A)
Dim LastRow As Long: LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
End With
Dim TargetHeaders As New Dictionary: Set TargetHeaders = GetTargetHeaders(arrTarget)
Dim i As Long
Dim Key As Variant
Dim OriginColumn As Long, TargetColumn As Long
Dim x As Long: x = 1
For i = 2 To UBound(arrOrigin)
For Each Key In TargetHeaders.Keys
OriginColumn = OriginHeaders(Split(TargetHeaders(Key), "\")(0))
TargetColumn = Split(TargetHeaders(Key), "\")(1)
arrTarget(x, TargetColumn) = arrOrigin(i, OriginColumn)
Next Key
Next i
ThisWorkbook.Sheets("Your target sheet name").Range("A" & LastRow).Resize(UBound(arrTarget), UBound(arrTarget, 2)).Value = arrTarget
End Sub
Private Function GetArrayFromSheet() As Variant
Dim wb As Workbook: Set wb = FilePicker
Dim ws As Worksheet
For Each ws In wb.Sheets
If ws.Name Like "* Annex 1" Then
GetArrayFromSheet = ws.UsedRange.Value
wb.Close False
Exit Function
End If
Next ws
End Function
Private Function FilePicker() As Workbook
With Application.FileDialog(msoFileDialogOpen)
.Filters.Clear
.Filters.Add "Excel 2007-13", "*.xlsx; *.xlsm; *.xlsa"
.AllowMultiSelect = False
.Show
If .SelectedItems.Count > 0 Then
Set FilePicker = Workbooks.Open(.SelectedItems(1))
Else
MsgBox "No file was selected, the procedure will end"
End
End If
End With
End Function
Private Function GetOriginHeaders(arr As Variant) As Dictionary
Set GetOriginHeaders = New Dictionary
Dim i As Long
For i = 1 To UBound(arr, 2)
GetOriginHeaders.Add arr(1, i), i
Next i
End Function
Private Function GetTargetHeaders(arr As Variant) As Dictionary
Set GetOriginHeaders = New Dictionary
Dim i As Long
Dim MyHeader As String
For i = 1 To UBound(arr, 2)
MyHeader = arr(1, i)
Select Case MyHeader
Case "Piece"
MyHeader = "Part"
'..More cases for different names
End Select
TargetHeaders.Add arr(1, i), MyHeader & "\" & i
Next i
End Function

How to find matching headers in a worksheet using VBA?

There is a sheet with headers. Out of those headers I have to verify/check that 12 headers are available. If they are available message should show as success and if not it should show that the specific header is missing.
I created a sub and took an array with those twelve values but how to match?
Please test the next code. You will build the headers array in a way to reflect your reality:
Sub testCheckHeadersArray()
Dim sh As Worksheet, arrH As Variant, El As Variant, C As Range
Dim boolFound As Boolean, strNotFound As String, lastCol As Long
arrH = Split("Header1,Header3,Header4,Header5,Header6,Header7,Header8,Header9,Header10", ",")
Set sh = ActiveSheet 'please, use here your sheet to be checked
lastCol = sh.Cells(1, Cells.Columns.Count).End(xlToLeft).column
For Each El In arrH
boolFound = False
For Each C In sh.Range(sh.Cells(1, 1), sh.Cells(1, lastCol))
If UCase(El) = UCase(C.value) Then
boolFound = True: Exit For
End If
Next
If Not boolFound Then strNotFound = strNotFound & El & vbCrLf
Next
If strNotFound <> "" Then
MsgBox "The next headers have not been found:" & vbCrLf & strNotFound
Else
MsgBox "Everything OK"
End If
End Sub
If you have a sheet with the correct headers, you can extract the array from there:
Set shH = Worksheets("HeaderModel")
arrH = shH.Range(Range("A1"), shH.Cells(1, shH.Cells(1, _
Cells.Columns.Count).End(xlToLeft).column)).value
This is how you might tackle your problem. Please read the comments in the code to understand how it's done.
Option Explicit
Sub TestHeaderPresence()
Dim CheckHeaders As Variant
Dim Headers As String
' list the required headers
Headers = "Header1,Header3,Header4,Header5,Header6,Header7,Header8," & _
"Header9,Header10,Header11,Header12"
' pass the list to the function
CheckHeaders = HeadersArePresent(Headers)
If CheckHeaders = True Then
MsgBox "All headers are present.", vbInformation, "Caption check"
Else
MsgBox "At least caption """ & CheckHeaders & """" & " is missing.", _
vbInformation, "Caption check"
End If
End Sub
Function HeadersArePresent(Headers As String) As Variant
Dim Fun As String ' function return
Dim Captions() As String
Dim HeaderRange As Range
Dim HeaderArray As Variant
Dim Tmp As Variant
Dim i As Long
With ActiveSheet ' replace with "With Worksheets("[tab name]")"
' Available Captions start from column "C" in row "1"
' modify as appropriate
Tmp = .Range(.Cells(1, "C"), .Cells(1, .Columns.Count).End(xlToLeft)).Value
End With
ReDim HeaderArray(1 To UBound(Tmp, 2))
For i = 1 To UBound(Tmp, 2)
HeaderArray(i) = Tmp(1, i)
Next i
HeaderArray = Join(HeaderArray, ",")
Captions = Split(Headers, ",")
For i = 0 To UBound(Captions)
If InStr(HeaderArray, Captions(i)) = 0 Then
Fun = Captions(i)
Exit For
End If
Next i
' return True or the name of first missing header
HeadersArePresent = IIf(Len(Fun), Fun, True)
End Function
Approach via Filter() function
After defining the set of regular headers (~> [0]) and current headers (~> [1]), the Filter() function allows to reduce the initially full set of headers subsequently by the next current header via the 3rd include argument set to False (~> section [2]).
See MS Help: If include is False, Filter returns the subset of the array that does not contain match as a substring
Sub ListMissingHeaders()
'[0] define needed headers and assign them to 1-dim array
Const HEADERLIST = "Header1,Header3,Header4,Header5,Header6,Header7,Header8,Header9,Header10"
Dim regularHeaders: regularHeaders = Split(HEADERLIST, ",")
'[1] get current headers
With Sheet1 ' << change to actual sheet's Code(Name)
Dim lastCol As Long ' get last column in head line
lastCol = .Cells(1, .Cells.Columns.Count).End(xlToLeft).Column
Dim currHeaders ' assign current headers to 2-dim array
currHeaders = .Range("1:1").Resize(columnsize:=lastCol)
End With
'[2] Filter regular set of headers passed to array missingHeaders
Dim i As Long, missingHeaders
missingHeaders = regularHeaders ' start with complete set of headers
For i = 1 To UBound(currHeaders, 2) ' filter out existing headers one by one
missingHeaders = Filter(missingHeaders, currHeaders(1, i), False, vbTextCompare)
Next i
'[3] show missing headers
Debug.Print UBound(missingHeaders) + 1 & " missing Headers: """ & _
Join(missingHeaders, """, """)
End Sub

Resources