Use stored value to call or create & call sheet - excel

I have a workbook that creates other workbooks and shifts data to them based on the value in column one. Afterwords I need the workbook to store the data it has just copied in a sheet of the same name as the stored variable (in the next empty row), or create the tab if it does not exist.
However i'm having an issue pasting into the tab with the name of the variable, and no idea how to create a new sheet if the variable does not already exist as a sheet.
It's the With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste i'm having trouble with.
Current code below. Thanks!
Private Sub CopyItOver()
Dim myVal As String
Dim SupID As String
'Store Supplier ID
SupID = Trim(Sheets("Raw Data").Range("A2").Value)
'Create workbook
Set newbook = Workbooks.Add
'Copy Records
Set myRng = Workbooks("Book1.xlsm").Worksheets("Raw Data").Range("B2:X7")
myRng.Copy
newbook.Worksheets("Sheet1").Range("A2").PasteSpecial (xlPasteValues)
'Create Header
newbook.Worksheets("Sheet1").Range("A1").Value = "ZHF"
newbook.Worksheets("Sheet1").Range("B1").Value = "CTO"
newbook.Worksheets("Sheet1").Range("C1").Value = "RET"
newbook.Worksheets("Sheet1").Range("D1").Value = SupID
newbook.Worksheets("Sheet1").Range("E1").Value = "RET"
newbook.Worksheets("Sheet1").Range("F1").Value = "RET"
newbook.Worksheets("Sheet1").Range("G1").Value = "6"
newbook.Worksheets("Sheet1").Range("H1").Value = "PROD"
newbook.Worksheets("Sheet1").Range("J1").Value = newbook.Worksheets("Sheet1").Range("B1").Value _
& newbook.Worksheets("Sheet1").Range("D1").Value & "TEMPNUMBER"
newbook.Worksheets("Sheet1").Range("I1").Value = newbook.Worksheets("Sheet1").Range("J1").Value _
& newbook.Worksheets("Sheet1").Range("C1").Value & ".CSV"
newbook.Worksheets("Sheet1").Range("K1") = Format(Date, "ddmmyyyy")
newbook.Worksheets("Sheet1").Range("L1").Value = "Unknown"
newbook.Worksheets("Sheet1").Range("M1").Value = "1"
LastRow = newbook.Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
'Create Footer
newbook.Worksheets("Sheet1").Range("A" & LastRow + 1).Value = "ZFV"
newbook.Worksheets("Sheet1").Range("B" & LastRow + 1).Value = "BATCH" & "TEMPNUMBER"
newbook.Worksheets("Sheet1").Range("C" & LastRow + 1).Value = WorksheetFunction.CountIf(Sheets("Sheet1").Range("A1:A1000"), "RET")
'Name Sheet
myVal = newbook.Worksheets("Sheet1").Range("J1").Value & "RET"
newbook.Worksheets("Sheet1").Name = myVal
'Copy to relevant matching sheet
With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste
End With
'Save Workbook
NewBook.SaveAs Filename:=NewBook.Worksheets("Sheet1").Range("I1").Value
End Sub
Function DLastRow(sh As Worksheet)
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", _
After:=sh.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
On Error GoTo 0
End Function

The error's occurring because Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste is trying to find that worksheet on your active book, ie the new book. You'd need either to Activate your raw data workbook or change the line to ThisWorkbook.Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste.
However, it's not great to use (either explicitly or implicitly) Activate, Select or other keystroke style commands in VBA. Given that you're only copying values (and not the worksheet formats) then, you'd probably be better served reading the data into an array of variants and manipulating those. I've adjusted your code to demonstrate this.
There are some other coding aspects that might not be as robust as they could be. I won't list them all but a comparison of this code with yours will help you see them.
Private Sub CopyItOver()
Dim newBook As Workbook
Dim supSheet As Worksheet
Dim v As Variant
Dim supID As String
Dim namePrefix As String
Dim footerCount As Integer
Dim i As Integer
'Store Supplier ID
supID = Trim(ThisWorkbook.Worksheets("Raw Data").Range("A2").value)
namePrefix = "CTO" & supID & "TEMPNUMBER"
'Create workbook
Set newBook = Workbooks.Add
'Copy Records
v = rawDataSheet.Range("B2:X7").value
For i = 1 To UBound(v, 1)
If v(i, 1) = "RET" Then footerCount = footerCount + 1
Next
'Write new sheet
With newBook.Worksheets(1)
'Values
.Range("A2").Resize(UBound(v, 1), UBound(v, 2)).value = v
'Header
.Range("A1").Resize(, 13) = Array( _
"ZHF", "CTO", "RET", supID, "RET", "RET", "6", "PROD", _
namePrefix & "RET.CSV", namePrefix, _
Format(Date, "ddmmyyyy"), "Unknown", "1")
'Footer
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(, 3).value = Array( _
"ZFV", "BATCH TEMPNUMBER", footerCount)
'Name
.Name = namePrefix & "RET"
'Save
.SaveAs Filename:=namePrefix & "RET.CSV"
End With
'Copy to relevant matching sheet
On Error Resume Next
Set supSheet = ThisWorkbook.Worksheets(supID)
On Error Goto 0
If newSheet Is Nothing Then
With ThisWorkbook.Worksheets
Set supSheet = .Add(After:=.Item(.Count))
End With
supSheet.Name = supID
End If
With supSheet
.Cells(.Rows.Count, "A").End(xlUp).Offset(1).Resize(UBound(v, 1), UBound(v, 2)).value = v
End With
End Sub

A few things that aren't quite right:
Add Option Explicit at the top of the module and declare your variables.
LastRow will be a Long data type, but you're trying to use it like an array in With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste. Just use LastRow+1.
With Worksheets(SupID).Range("A" & LastRow(SupID) + 1).Paste
End With should probably be Worksheets(SupID).Range("A" & LastRow + 1).Paste, but it will paste myRng - can't see anything else you've copied.
At the start of the code you reference Workbooks("Book1.xlsm"). If this is the workbook that the code is in I'd change it to ThisWorkbook.
SupID looks at Raw Data on whichever workbook is active at the time (you'd don't specify the workbook when initialising that variable).
This function will return TRUE/FALSE if a named worksheet exists:
Public Function WorkSheetExists(SheetName As String) As Boolean
Dim wrkSht As Worksheet
On Error Resume Next
Set wrkSht = ThisWorkbook.Worksheets(SheetName)
WorkSheetExists = (Err.Number = 0)
Set wrkSht = Nothing
On Error GoTo 0
End Function
Hope that points you in the right direction :)
Edit:
Just noticed to....
Rather than write:
newbook.Worksheets("Sheet1").Range("A1").Value = "ZHF"
newbook.Worksheets("Sheet1").Range("B1").Value = "CTO"
newbook.Worksheets("Sheet1").Range("C1").Value = "RET"
newbook.Worksheets("Sheet1").Range("D1").Value = SupID
newbook.Worksheets("Sheet1").Range("E1").Value = "RET"
newbook.Worksheets("Sheet1").Range("F1").Value = "RET"
newbook.Worksheets("Sheet1").Range("G1").Value = "6"
newbook.Worksheets("Sheet1").Range("H1").Value = "PROD"
You can just use:
newbook.Worksheets("Sheet1").Range("A1:H1") = Array("ZHF", "CTO", "RET", "SupID", "RET", "RET", "6", "Prod")

I managed to resolve my issue using help from Here, to which I adapted to the code below and ran in a separate module, which allows for the use of a previously unspecified sheet name, that is later derived from a cell value. If the sheet does not exist, it is created matching the name to the stored value and the data pasted into it. Thanks for the support!
Sub TEST()
Dim i As Integer, blnFound As Boolean
blnFound = False
SupID = Trim(Sheets("Raw Data").Range("A2").Value)
Set myRng = Workbooks("Book1.xlsm").Worksheets("Raw Data").Range("B2:X7")
myRng.Copy
With ThisWorkbook
For i = 1 To .Sheets.Count
If .Sheets(i).Name = SupID Then
blnFound = True
.Sheets(i).Activate
ActiveSheet.Paste Destination:=Range("A" & LastRow + 1)
Exit For
End If
Next i
If blnFound = False Then
.Sheets.Add
With ActiveSheet
.Name = SupID
ActiveSheet.Paste Destination:=Range("A" & LastRow + 1)
End With
End If
End With
End Sub

Related

Excel VBA: Loop through autofilter criteria to copy and paste to new sheet then save as new file

I am beginner for excel VBA.
I want to use VBA to loop through autofilter criteria in column G( below photo) to copy and paste to new sheet then save as new file with sequence file name.
Below is my code, i know that it can use if else to do but the code will change to very long and difficult to revise, i want to know how to change to use the loop.
Thank you very much for your help.
Dim wb As Workbook
Dim wsw As Worksheet
Dim y As Workbook
Dim lastRow, lastRow2 As Long
Dim readsheetName As String
Dim destsheetName As String
Dim fso As Object, FolDir As String, FileNm As Object, NumStr As Integer, MaxNum As Integer
Dim NewName As String, StrNum As String, MaxStr As String
Dim FolderStr As String 'Object
MaxNum = 1
FolderStr = "Q:\Alan\VBA\CCA\"
'Set fso = CreateObject("scripting.filesystemobject")
'Set FolDir = fso.GetFolder(FolderStr)
FolDir = Dir(FolderStr)
readsheetName = "2011-2019"
destsheetName = "Cable Collection Advices (2)"
Set wb = ThisWorkbook
Set wsw = wb.Sheets(readsheetName)
wsw.Activate
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Filtered Data").Delete
On Error GoTo 0
Application.DisplayAlerts = True
Application.ScreenUpdating = False
Set wsDest = ThisWorkbook.Sheets.Add(After:= _
ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
wsDest.Name = "Filtered Data"
MM1
wsw.Range("A1:U1").AutoFilter Field:=7, Criteria1:="296699"
wsw.Range("A1:U1").AutoFilter Field:=14, Criteria1:="Available", Operator:=xlOr, Criteria2:="="
If wsw.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Count > 1 Then
wsw.Cells.SpecialCells(xlCellTypeVisible).Copy
wsDest.Activate
wsDest.Range("A1").PasteSpecial xlPasteFormulasAndNumberFormats
wsDest.Columns("N:U").Delete
wsDest.Columns("A:B").Delete
wsDest.Columns("F").Delete
wsDest.Rows(1).Delete
lastRow = wsDest.Range("A" & Rows.Count).End(xlUp).Row
Set SourceRange = wsDest.Range("A1:D" & lastRow)
Set SourceRange2 = wsDest.Range("F1:G" & lastRow)
Set SourceRange3 = wsDest.Range("E1:E" & lastRow)
Set SourceRange4 = wsDest.Range("J1:J" & lastRow)
SourceRange.Copy
Set y = Workbooks.Open("\\SSSSNNMR20\EAS2EAS1\75 ABCDE Engineering\76 CABLE Engineering - General\PE-Test-ABCDE\E_P\02 AB\Alan\VBA\CCA\Cable Collection Advices - 11.xls")
y.Sheets(destsheetName).Range("C8").PasteSpecial xlPasteValues
SourceRange2.Copy
y.Sheets(destsheetName).Range("G8").PasteSpecial xlPasteValues
SourceRange3.Copy
y.Sheets(destsheetName).Range("I8").PasteSpecial xlPasteValues
SourceRange4.Copy
y.Sheets(destsheetName).Range("J8").PasteSpecial xlPasteValues
lastRow2 = wsDest.Range("C" & Rows.Count).End(xlUp).Row
y.Sheets(destsheetName).Range("A8:A" & lastRow2 + 7).Value = Format(Now(), "dd.mm.yyyy")
y.Sheets(destsheetName).Range("B5").Value = Format(Now(), "dd.mm.yyyy")
Application.DisplayAlerts = False
Do While Len(FolDir) > 0
If FolDir Like "Cable Collection Advices - " & "*" & ".xlsx" Then
StrNum = Right(Left(FolDir, 32), 5)
'MsgBox "StrNum" & StrNum
NumStr = CInt(StrNum)
If NumStr > MaxNum Then
MaxNum = NumStr
End If
End If
FolDir = Dir
'Next FileNm
Loop
MaxStr = CStr(Format(MaxNum + 1))
NewName = FolderStr & "Cable Collection Advices - " & MaxStr & ".xlsx"
y.SaveAs Filename:=NewName, FileFormat:=51, CreateBackup:=False
y.Close SaveChanges:=False
ActiveWorkbook.Worksheets("Filtered Data").Delete
wsw.Activate
MM1
Else
MsgBox ("No data")
End If
Sub MM1() 'close all the worksheet autofilter
Dim ws As Worksheet
For Each ws In Worksheets
'ws.AutoFilterMode = ShowAllData
With ws
If .AutoFilterMode Then
If .FilterMode Then
.ShowAllData
End If
End If
End With
Next ws
End Sub
Just yesterday I've made a multiple fields filter - it collected the multiple criteria and put the list on another sheet.
1.- creating 2-dimention array Result(a,b) - where a in horizontal dimention and b- vertical dimension of the table write the filtered table into this array
2. - create a user function to put the lines in Result(a,b) that doesn't satisfy criteria to 0 (in my case there were text data, so i used 0, you can use anything you can identify)
Function is like this
Function ArrFilter(ByVal fVal, ByVal ColNbr)'fVal - value to filter, ColNbr - number of column you filter in
For i = 1 To count7
If CStr(fVal) <> CStr(Result(ColNbr, i)) Then
For j = 1 To count3
Result(j, i) = 0
Next j
End If
Next i
End Function
Put your criteria dimension in a loop if you have array of criteria Criteria() and column 2
For Each x in Criteria
Call ArrFilter(x, 2)
Next x
Then you write the result into table, selecting those that are not 0
count=0
For i=b
If Result(2,i)<>0 Then
For j=a
count=count+1
Cells(count,j)=Result(j,i)
Next j
End If
Next i

Excel -Looking to use VBA to build a table of contents with extra cells copied

I have a good basic script that returns me the sheet name of each sheet in the workbook, but now I'd like to add the contents of cell A1, A2, A3, and A4 into columns B, C, D, and E and add a header row with "Link, Variable, Definition, Calculation, Notes" in columns A, B, C, D. The existing hyperlink will be in column A.
It will need to loop through the entire workbook, and if possible skip adding a link to the table of contents page. Here is a basic script I currently use (borrowed from Extend Office) -
'updateby Extendoffice 20180413
Dim xAlerts As Boolean
Dim I As Long
Dim xShtIndex As Worksheet
Dim xSht As Variant
xAlerts = Application.DisplayAlerts
Application.DisplayAlerts = False
On Error Resume Next
Sheets("Table of contents").Delete
On Error GoTo 0
Set xShtIndex = Sheets.Add(Sheets(1))
xShtIndex.Name = "Table of contents"
I = 1
Cells(1, 1).Value = "Table of contents"
For Each xSht In ThisWorkbook.Sheets
If xSht.Name <> "Table of contents" Then
I = I + 1
xShtIndex.Hyperlinks.Add Cells(I, 1), "", "'" & xSht.Name & "'!A1", , xSht.Name
End If
Next
Application.DisplayAlerts = xAlerts
End Sub
Not sure if this does exactly what you want, there is some gaps in the explanation in regards how you want to handle the link fucntion. Since you mention the code "works" but you want some added function, and you dont want links on the "table of contents" but it doesn't do that now either?
anyway give this a go...
Private Sub CommandButton1_Click()
Dim xAlerts As Boolean
Dim I As Long
Dim xShtIndex As Worksheet
Dim Table As Worksheet
Dim xSht As Variant
xAlerts = Application.DisplayAlerts
Application.DisplayAlerts = False
On Error Resume Next
Sheets("Table of contents").Delete
On Error GoTo 0
Set xShtIndex = Sheets.Add(Sheets(1))
xShtIndex.Name = "Table of contents"
Set Table = Worksheets("Table of contents")
I = 2
targetcolumn = 1
'Cells(1, 1).Value = "Table of contents"
'Disabled this because i'm not sure if this code should be here?
For Each xSht In ThisWorkbook.Sheets
With xSht
If xSht.Name = "Table of contents" Then
.Cells(1, 1).Value = "Table of contents"
.Range("A1").Value = "Link"
.Range("B1").Value = "Variable"
.Range("C1").Value = "Definition"
.Range("D1").Value = "Calculation"
.Range("E1").Value = "Notes"
End If
If xSht.Name <> "Table of contents" Then
lrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Dim copyrng As Range
Set copyrng = .Range("A1:A" & lrow)
copycount = 2 'skipping one because with 1 it would write to row 1 which is where the headers are
For Each cell In copyrng
Table.Cells(targetcolumn, copycount).Value = cell.Value
copycount = copycount + 1
Next
Table.Hyperlinks.Add Table.Cells(I, 1), "", "'" & xSht.Name & "'!A1", , xSht.Name
I = I + 1
End If
End With
targetcolumn = targetcolumn + 1
Next
Application.DisplayAlerts = xAlerts
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

Looping vlookup through predefined named range in multiple sheets

So I've been solving this problem of mine for a couple days already.
Basically, I have multiple green sheets (my source sheets) and one main sheet (master sheet), the problem I'm working on has to do with looping through these green sheets in order to pull certain information from them and put it on certain columns in my master sheet.
Here's the layout of one of these green sheets for better understanding:
https://imgur.com/cayZXUA
I'm sorry for the links, cant add images yet
You can see that these green sheets consist of multiple boxes which can differ in size from sheet to sheet. Some of the values I need to retrieve are fixed in the same cell address for all green sheets so I have no problem getting them to the master sheet. But there are some cases like this:
https://imgur.com/nPYyLbM
Assumption box contains information that I need to lookup and pull it to Main sheet. In essence, this box can take up vertically any space so that address for values of payroll, tax and miscellaneous expenditures changes.
I came up with the idea of giving these boxes in all green sheets name "Assumptions" like seen in the image above. So the questions is how do I lookup 3rd column of this named box and pull it to main sheet?
Here's Main sheet structure:
https://imgur.com/CWMpGvH
My code so far:
Sub CombiningSheets()
Dim p_value, cst_value, m_value As Long
Dim p, cst, m As String
p = "payroll"
cst = "consolidated social tax"
m = "miscellaneous expenditures"
With ThisWorkbook.Sheets("Main")
For Each wsheet In ThisWorkbook.Sheets
If wsheet.Name <> "Main" Then
Set nextEntry = .Cells(.Rows.Count, "G").End(xlUp).Offset(1, 0)
Set nextEntry_FTE_quantity = .Cells(.Rows.Count, "K").End(xlUp).Offset(1, 0)
Set nextEntry_nonrecurring_expenses = .Cells(.Rows.Count, "S").End(xlUp).Offset(1, 0)
Set nextEntry_initiative_type = .Cells(.Rows.Count, "Q").End(xlUp).Offset(1, 0)
Set nextEntry_initiative_description = .Cells(.Rows.Count, "E").End(xlUp).Offset(1, 0)
Set nextEntry_economic_benefit = .Cells(.Rows.Count, "AA").End(xlUp).Offset(1, 0)
Set nextEntry_payroll = .Cells(.Rows.Count, "AI").End(xlUp).Offset(1, 0)
Set nextEntry_consolidated_social_tax = .Cells(.Rows.Count, "AJ").End(xlUp).Offset(1, 0)
Set nextEntry_miscellaneous_expenditures = .Cells(.Rows.Count, "AK").End(xlUp).Offset(1, 0)
If IsError(Application.Match(wsheet.Name, .Range("G:G"), 0)) Then
nextEntry.Value = wsheet.Name
nextEntry_initiative_description.Value = wsheet.Range("K6").Value
nextEntry_FTE_quantity.Value = wsheet.Range("BH16").Value
nextEntry_initiative_type.Value = wsheet.Range("K8").Value
nextEntry_nonrecurring_expenses.Value = wsheet.Range("BH17").Value
nextEntry_economic_benefit.Value = wsheet.Range("BH15").Value
End If
End If
Debug.Print wsheet.Name
Next wsheet
End With
End Sub
From your questions it seems that you have defined named ranges. As I'm aware of your question How to copy sheets with certain tab color from one workbook to another? I do believe that you don't have named ranges on your individual sheets.
Below you find some code if you have named ranges (Sub List_NamedRange_Loop).If you don't have named ranges you can create these named ranges on the individual sheets first (Sub Create_NamedRange).
At the end of this post you find a screenshot of the result I got.
Sub List_NamedRange_Loop()
Dim NamedRange As Name
Dim ws As Worksheet
Dim PrDebug As Boolean
Dim iCt As Integer
PrDebug = False ' => Output to Worksheet "Main"
'PrDebug = True ' => Output to Immediate Window (Ctrl-G in VBE)
'List on sheet "main"
If Not (PrDebug) Then
On Error Resume Next
Debug.Print ActiveWorkbook.Name
Sheets("main").Activate
If ActiveSheet.Name <> "main" Then
Worksheets.Add
ActiveSheet.Name = "main"
End If
On Error GoTo 0
Range("A1:D1000").ClearContents
Range("A1").Value = "Sheet Name"
Range("B1").Value = "Named Range"
Range("C1").Value = "RefersTo"
Range("D1").Value = "Value (Direct Reference)"
Range("E1").Value = "Value (Named Reference)"
End If
'We expect all named ranges to be local = defined on the indivdual sheets
'so no need for the below 'workbook loop'
'Loop through each named range in workbook
' For Each namedrange In ActiveWorkbook.Names
' Debug.Print namedrange.Name, namedrange.RefersTo
' Next namedrange
'Loop through each named range scoped to a specific worksheet
iCt = 0
For Each ws In Worksheets
iCt = iCt + 1
If ws.Names.Count > 0 Then
If PrDebug Then
Debug.Print
Debug.Print ws.Name
Else
End If
For Each NamedRange In ws.Names 'Worksheets("Sheet1").Names
If PrDebug Then
Debug.Print ws.Name, NamedRange.Name, NamedRange.RefersTo
Else
iCt = iCt + 1
Range("A1").Offset(iCt, 0).Value = ws.Name
' Range("B1").Offset(iCt, 0).Value = Replace(NamedRange.Name, ws.Name & "!", "")
If InStr(1, NamedRange.Name, "'") Then
Range("B1").Offset(iCt, 0).Value = Replace(NamedRange.Name, "'" & ws.Name & "'!", "")
Else
Range("B1").Offset(iCt, 0).Value = Replace(NamedRange.Name, ws.Name & "!", "")
End If
Range("C1").Offset(iCt, 0).Value = "'" & NamedRange.RefersTo
Range("D1").Offset(iCt, 0).Value = NamedRange.RefersTo
Range("E1").Offset(iCt, 0).Formula = "=" & NamedRange.Name
Range("E1").Offset(iCt, 0).Calculate
End If
Next NamedRange
Else
' iCt = iCt + 1
' Range("A1").Offset(iCt, 0).Value = ws.Name
' Range("B1").Offset(iCt, 0).Value = "NO NAMES DEFINED!"
End If
Next ws
End Sub
If you don't have named ranges you might create them with the code similar to the following:
Sub Create_NamedRange()
Dim ws As Worksheet
Dim foundRange As Range
For Each ws In Worksheets
If ws.Name <> "main" Then
Debug.Print ws.Name
Set foundRange = ws.Cells.Find(What:="payroll", After:=ActiveCell, LookIn:=xlValues, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
True, SearchFormat:=False)
If Not (foundRange Is Nothing) Then
Debug.Print "Found: "; ws.Name
'offset between AR and BH: 16 columns (https://imgur.com/nPYyLbM)
ws.Names.Add Name:="payroll", RefersTo:=foundRange.Offset(0, 16)
ws.Names.Add Name:="consolidated_social_tax", RefersTo:=foundRange.Offset(1, 16)
ws.Names.Add Name:="miscellaneous_expenditures", RefersTo:=foundRange.Offset(2, 16)
End If
End If
Next ws
End Sub
I would use Range.Find to locate the cells by keywords and return the values adjacent to them.
Sub TestFind()
Dim colOffset As Long
Dim wsheet As Worksheet
colOffset = Columns("BH").Column - Columns("AR").Column - 2 'Two Extra Cells in Merged Range Adjustment
For Each wsheet In ThisWorkbook.Worksheets
If wsheet.Name <> "Main" Then
Debug.Print FindValueRelativeToSearch(wsheet.Columns("AR"), "payroll", 0, colOffset)
Debug.Print FindValueRelativeToSearch(wsheet.Columns("AR"), "social tax", 0, colOffset)
Debug.Print FindValueRelativeToSearch(wsheet.Columns("AR:AT"), "miscellaneous expenditures", 0, colOffset)
End If
Next
End Sub
Function FindValueRelativeToSearch(SearchRange As Range, search As String, rowOffset As Long, colOffset As Long) As Variant
Dim cell As Range
Application.FindFormat.MergeCells = True
With SearchRange
Set cell = .Find(What:=search, After:=.Cells(1, 1), _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=True)
End With
cell.Offset(rowOffset, colOffset).Activate
If cell Is Nothing Then
Debug.Print "Search not found: FindValueRelativeToSearch()", SearchRange.Address(0, 0, xlA1, True), search
Else
FindValueRelativeToSearch = cell.Offset(rowOffset, colOffset).Value
End If
End Function

Extract matched data from a table to another worksheet in Excel VBA

I've got a sample table in Sheet1 as below:
Location Model Part #
BF03 200W 40536573
BF04 200W 40536573
CV01 120W 40536585
CV02 135W 20085112
CV03 900W 20349280
CV04 135W 20085112
As a reference data of BF03 is in cell B6.
What I need it to do is:
A) When user typed part number (ex: 40536573) in Sheet3 say cell A1, only the matched location will be picked up
B) The picked up "location" value will be tabulated in Sheet2 starting from cell A6.
The output will look something like this:
Location Model Part #
BF03 200W 40536573
BF04 200W 40536573
To make matter more complicated, I would then need to have the "Location" data to be concatenated into a string and store it in Sheet 2 Cell A2.
I'm guessing we need to do a For Loop count rows but I couldn't get any reference on how to write it properly.
Below are what my error "OVERFLOW" code looks like
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim FindMatch As String
Dim Rng As Range
Dim counter As Integer
counter = ActiveWorkbook.Worksheets("Sheet2").Range("A6", Worksheets("Sheet2").Range("A6").End(xlDown)).Rows.Count
For i = 6 To counter
'Get the value from other sheet set as FindMatch
FindMatch = Sheets("Sheet3").Cell("A1").Value
'Find each row if matches the desired FindMatch
If Trim(FindMatch) <> "" Then
With Sheets("Sheet2").Range("D" & i).Rows.Count
Set Rng = .Find(What:=FindMatch, _
after:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
If Not Rng Is Nothing Then
'copy the values required to the cell
Cells(i, 2) = Sheets("Sheet2").Cells(Rng.Row, 2)
Else
MsgBox "Nothing found"
End If
End With
End If
Next i
End Sub
Instead of using the .find method, I managed to use a simple for loop. Sometimes you need to think simple i guess :) I have also added a small function to clear previously used fields. If you check and give feedback if you face any problem, we can try to fix it.
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim ws3 As Worksheet
Dim S_Var As String
Dim copyRange As Range
Dim ws1_lastrow As Long
Dim ws2_lastrow As Long
Dim searchresult As Range
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
Set ws3 = Sheets("Sheet3")
S_Var = ws3.Range("A1").Value
ws1_lastrow = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Row
Set copyRange = ws1.Range("A1:C" & ws1_lastrow)
'Clear Data
ws2.Range("A2").Value = ""
If Range("A7").Value <> "" Then
ws2.Range("A7:C" & ws2.Range("A" & ws1.Rows.Count).End(xlUp).Row).Value = ""
End If
'Searchin through the sheet1 column1
For i = 2 To ws1_lastrow
If ws1.Range("C" & i) = S_Var Then
ws2_lastrow = ws2.Range("A" & ws2.Rows.Count).End(xlUp).Row
ws1.Range("A" & i & ":C" & i).Copy Destination:=ws2.Range("A" & ws2_lastrow + 1)
End If
Next
'Adding location to sheet2 A2 as string
ws2_lastrow = ws2.Range("A" & ws1.Rows.Count).End(xlUp).Row
For i = 7 To ws2_lastrow 'starting from 7, where location starts
If ws2.Range("A2").Value = "" Then
ws2.Range("A2").Value = ws2.Range("A" & i).Value
Else
ws2.Range("A2").Value = ws2.Range("A2").Value & "," & ws2.Range("A" & i).Value
End If
Next

Resources