Here is what I have. When moving data the VLOOKUP was causing errors. So I added code for a Function that does the lookup. It works well. Unless there are thousands of S/Ns it should not bog down calculation too much. I also added a sub that gathers all S/Ns and puts them into a dropdown in cell F3. If there are too many S/Ns for a dropdown let me know and I'll remove that functionality and then you can enter the S/N directly as before. There is also a sub that puts a dropdown with all worksheets except the main worksheet -- and excepting other worksheets specified in the new worksheet called control -- into H7. Finally, there is code to do the move after clicking a button.
There are a few important notes.
As mentioned above, I added a worksheet named Control. It includes a list of worksheets that do not have serial number data and that should be excluded when compiling the list of serial numbers. It also has the list of serial numbers that fill the dropdown for serial numbers in worksheet Main, cell F3.
Regarding the serial numbers, code always starts in cell B1 in the respective data worksheet to locate serial numbers. If that changes you'll have to modify code.
I named the cell containing the serial number dropdown to Input_Serial_Number. Code uses that name to know where to put the dropdown. Similarly, I added name Input_Worksheet_Name for the cell where the "move to" worksheet name is specified using the dropdown.
Oddly, the commands in the code that add the dropdown for serial numbers and for worksheets causes an error intermittently. I cannot figure out why. So code is set to not execute that command -- with a message -- if there IS an error. This is not totally satisfying but the code seems to work as expected 95% of the time. If there is no dropdown for serial numbers or worksheets you can still input them.
I used what is called an Event. In Excel an event is code that is triggered when a specific condition is met. In this case I used the Worksheet_Activate event for worksheet Main. The event puts the dropdown for serial numbers and for worksheets into worksheet Main each time that the worksheet Main is activated (by selecting its tab). That code is located in the code module for Main.
It seems likely that there will be issues. Please contact me if there ARE issues.
Here is the workbook.
VBA Code:
Function FindSNInSheets(psStockNumber As String, Optional piColumn As Long = 0) As String
Dim wsLoop As Worksheet
Dim rFoundCell As Range
Dim iOffset As Long
Dim asSheetsToExclude()
Dim iWorksheetsToExcludeCount As Long
Dim bDoExcludeSheet As Boolean
Dim iWorksheetIndex
iWorksheetsToExcludeCount = 10
ReDim asSheetsToExclude(iWorksheetsToExcludeCount)
ReDim asSheetsToExclude(10)
With Worksheets("Control").Range("WorksheetsToExclude")
asSheetsToExclude(1) = .Cells(1).Value
asSheetsToExclude(2) = .Cells(2).Value
asSheetsToExclude(3) = .Cells(3).Value
asSheetsToExclude(4) = .Cells(4).Value
asSheetsToExclude(5) = .Cells(5).Value
asSheetsToExclude(6) = .Cells(6).Value
asSheetsToExclude(7) = .Cells(7).Value
asSheetsToExclude(8) = .Cells(8).Value
asSheetsToExclude(9) = .Cells(9).Value
asSheetsToExclude(10) = .Cells(10).Value
End With
FindSNInSheets = "?"
For Each wsLoop In ThisWorkbook.Worksheets
bDoExcludeSheet = False
For iWorksheetIndex = 1 To UBound(asSheetsToExclude)
If wsLoop.Name = asSheetsToExclude(iWorksheetIndex) _
Then
bDoExcludeSheet = True
Exit For
End If
Next iWorksheetIndex
If Not bDoExcludeSheet _
Then
With wsLoop.UsedRange
Set rFoundCell = .Find(What:=psStockNumber, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=True)
End With
If Not rFoundCell Is Nothing _
Then
If piColumn = 0 _
Then
FindSNInSheets = wsLoop.Name
Else
If piColumn = rFoundCell.Column _
Then
FindSNInSheets = wsLoop.Name
Exit For
ElseIf piColumn < rFoundCell.Column _
Then
iOffset = rFoundCell.Column - piColumn
Else
iOffset = piColumn - rFoundCell.Column
End If
FindSNInSheets = rFoundCell.Offset(0, iOffset)
End If
Exit For
End If
End If
Next wsLoop
End Function
VBA Code:
Option Explicit
Option Base 1
Sub CreateSerialNumberDropDown()
Dim wsMain As Worksheet
Dim wsLoop As Worksheet
Dim rSerialNumsHeaderCell As Range
Dim rSerialNumsDropDownCell As Range
Dim sSerialNumber As String
Dim avSheetNames() As Variant
Dim iWorksheetsToProcess As Long
Dim iWorksheetsProcessed
Dim rSerialNumbersAnchorCell As Range
Dim iSerialNumbersTotal As Long
Dim iSerialNumberLoopIndex As Long
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wsMain = Worksheets("Main")
Set rSerialNumsDropDownCell = wsMain.Range("Input_Serial_Number")
Call CreateWorksheetsList(avSheetNames())
iWorksheetsToProcess = UBound(avSheetNames)
Set rSerialNumbersAnchorCell = Worksheets("Control").Range("E3")
rSerialNumbersAnchorCell.EntireColumn.Value = ""
rSerialNumbersAnchorCell.Value = "Serial Numbers"
iSerialNumbersTotal = 0
For iWorksheetsProcessed = 1 To iWorksheetsToProcess
Set wsLoop = ThisWorkbook.Worksheets(avSheetNames(iWorksheetsProcessed))
Set rSerialNumsHeaderCell = wsLoop.Range("B1")
iSerialNumberLoopIndex = 0
With rSerialNumsHeaderCell
Do
iSerialNumberLoopIndex = iSerialNumberLoopIndex + 1
iSerialNumbersTotal = iSerialNumbersTotal + 1
rSerialNumbersAnchorCell.Offset(iSerialNumbersTotal).Value = .Offset(iSerialNumberLoopIndex).Value
Loop Until .Offset(iSerialNumberLoopIndex + 1) = ""
End With
Next iWorksheetsProcessed
With ThisWorkbook
.Names("SerialNumbersList").Delete
.Names.Add _
Name:="SerialNumbersList", _
RefersTo:="=Control!" & rSerialNumbersAnchorCell.Offset(1).Resize(iSerialNumbersTotal).Address
End With
On Error GoTo DropDownError
With rSerialNumsDropDownCell.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:="=SerialNumbersList"
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
On Error GoTo 0
With ThisWorkbook.Worksheets("Control")
.Activate
.Sort.SortFields.Clear
.Range("SerialNumbersList").Sort Key1:=.Range("SerialNumbersList").Cells(1), Order1:=xlAscending, Header:=xlNo
.Range("SerialNumbersList").Offset(-1).Cells(1).Activate
End With
wsMain.Activate
Cloesout:
Application.EnableEvents = True
Set wsMain = Nothing
Set wsLoop = Nothing
Set rSerialNumsDropDownCell = Nothing
Set rSerialNumsHeaderCell = Nothing
Exit Sub
DropDownError:
Dim sMsg As String
sMsg = "There was an error adding the serial numbers" _
& Chr(10) _
& "dropdown to worksheet Main. Try deactivating" _
& Chr(10) _
& "then reactivating worksheet Main."
MsgBox sMsg, vbExclamation
End Sub
VBA Code:
Option Explicit
Option Base 1
Sub CreateWorksheetsList(Optional pavLookinSheets As Variant)
Dim wsMain As Worksheet
Dim rDropdownCell As Range
Dim wsLoop As Worksheet
Dim sDropDownEntriesList As String
Dim iWorksheetsCount As Long
Dim asSheetsToExclude()
Dim iWorksheetsToExcludeCount As Long
Dim bDoExcludeSheet As Boolean
Dim iWorksheetIndex As Long
Dim sWorksheetName As String
Set wsMain = ThisWorkbook.Worksheets("Main")
Set rDropdownCell = wsMain.Range("Input_Worksheet_Name")
ReDim asSheetsToExclude(10)
With Worksheets("Control").Range("WorksheetsToExclude")
asSheetsToExclude(1) = .Cells(1).Value
asSheetsToExclude(2) = .Cells(2).Value
asSheetsToExclude(3) = .Cells(3).Value
asSheetsToExclude(4) = .Cells(4).Value
asSheetsToExclude(5) = .Cells(5).Value
asSheetsToExclude(6) = .Cells(6).Value
asSheetsToExclude(7) = .Cells(7).Value
asSheetsToExclude(8) = .Cells(8).Value
asSheetsToExclude(9) = .Cells(9).Value
asSheetsToExclude(10) = .Cells(10).Value
End With
For Each wsLoop In ThisWorkbook.Worksheets
bDoExcludeSheet = False
For iWorksheetIndex = 1 To UBound(asSheetsToExclude)
If wsLoop.Name = asSheetsToExclude(iWorksheetIndex) _
Then
bDoExcludeSheet = True
Exit For
End If
Next iWorksheetIndex
If Not bDoExcludeSheet _
Then
If sDropDownEntriesList <> "" Then sDropDownEntriesList = sDropDownEntriesList & ","
sDropDownEntriesList = sDropDownEntriesList & wsLoop.Name
iWorksheetsCount = iWorksheetsCount + 1
If Not IsMissing(pavLookinSheets) _
Then
ReDim Preserve pavLookinSheets(iWorksheetsCount)
pavLookinSheets(iWorksheetsCount) = wsLoop.Name
End If
End If
Next wsLoop
On Error GoTo DropDownError
With rDropdownCell.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
xlBetween, Formula1:=sDropDownEntriesList
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
On Error GoTo 0
Closeout:
Set wsLoop = Nothing
Set wsMain = Nothing
Set rDropdownCell = Nothing
Exit Sub
DropDownError:
Dim sMsg As String
sMsg = "There was an error adding the worksheets" _
& Chr(10) _
& "dropdown to worksheet Main. Try deactivating" _
& Chr(10) _
& "then reactivating worksheet Main."
MsgBox sMsg, vbExclamation
End Sub
VBA Code:
Option Explicit
Sub MoveSerialNumberData()
Dim wsMain As Worksheet
Dim wsSource As Worksheet
Dim wsTarget As Worksheet
Dim rSerialNumberCell As Range
Dim rWorksheetFromNameCell As Range
Dim rWorksheetToNameCell As Range
Dim rSerialNumberFoundCell As Range
Dim rTargetCell As Range
Dim iMoveFromRowNum As Integer
Dim iMoveToRowNum As Integer
Dim iMoveRowsCount As Integer
Dim sSerialNumberToMove As String
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set wsMain = ThisWorkbook.Worksheets("Main")
With wsMain
Set rSerialNumberCell = .Range("F3")
Set rWorksheetToNameCell = .Range("H7")
Set rWorksheetFromNameCell = .Range("G3")
End With
If rSerialNumberCell.Value = "" _
Then
MsgBox "You must specify a serial number.", vbExclamation
Exit Sub
End If
sSerialNumberToMove = rSerialNumberCell.Value
On Error Resume Next
Set wsSource = ThisWorkbook.Worksheets(rWorksheetFromNameCell.Value)
On Error GoTo 0
If wsSource Is Nothing _
Then
MsgBox "The worksheet named " & rWorksheetToNameCell.Value & " does not exist.", vbExclamation
Exit Sub
End If
On Error Resume Next
Set wsTarget = ThisWorkbook.Worksheets(rWorksheetToNameCell.Value)
On Error GoTo 0
If wsTarget Is Nothing _
Then
MsgBox "The worksheet named " & rWorksheetToNameCell.Value & " does not exist.", vbExclamation
Exit Sub
End If
If wsSource.Name = wsTarget.Name _
Then
MsgBox "The source worksheet and the target worksheet are the same.", vbExclamation
Exit Sub
End If
Set rSerialNumberFoundCell = wsSource.UsedRange.Find(sSerialNumberToMove)
If rSerialNumberFoundCell Is Nothing _
Then
MsgBox "The serial number " & sSerialNumberToMove & Chr(10) _
& "in worksheet named " & wsSource.Name, vbExclamation
Exit Sub
End If
iMoveFromRowNum = rSerialNumberFoundCell.Row
iMoveToRowNum = wsTarget.Range("A" & Rows.Count).End(xlUp).Row + 1
With rSerialNumberFoundCell.EntireRow
.Cut wsTarget.Rows(iMoveToRowNum & ":" & iMoveToRowNum)
End With
wsSource.Rows(iMoveFromRowNum & ":" & iMoveFromRowNum).Delete Shift:=xlUp
Closeout:
With wsTarget
.Activate
.Cells(1).Activate
End With
wsMain.Activate
rSerialNumberCell.Value = ""
Set wsSource = Nothing
Set wsTarget = Nothing
Set rWorksheetToNameCell = Nothing
Set rWorksheetFromNameCell = Nothing
With Application
.EnableEvents = True
.CalculateFull
.EnableEvents = True
End With
End Sub