VBA for find, match and move data - vba

I am trying to find an automated solution for the following daily task.
I have a master workbook with 13 sheets.
Names are Jan-Dec (all 12 months) and Data.
Every sheet has 2 sets of 3 columns: Item Code (A1), Year (B1), Price (C1) and Item Code (E1), Year (F1), Price (G1).
Every day I have over 1000 new entries in "Data" sheet and then have to find matching item code (in Column A) in other 12 sheets, columns A-C, cut and move new matching data to E-G and highlight the new entries.
I tried the following vba code:
Sub TestNewCode()
Application.ScreenUpdating = False
Dim varMainRange As Range
Dim varSubRange As Range
Set varMainRange = Range(Worksheets("Jul").Range("A2:C65536"), _
Worksheets("Jul").Range("A65536").End(xlUp))
For Each MainCell In varMainRange
Set varSubRange = Range(Worksheets("Data").Range("A2"), _
Worksheets("Data").Range("A65536").End(xlUp))
For Each SubCell In varSubRange
If MainCell.Value = SubCell.Value Then
Worksheets("Data").Range("A2:C2").Copy _
Worksheets("Jul").Range("E2:G2")
Exit For
End If
Next SubCell
Next MainCell
Application.ScreenUpdating = True
End Sub
As you can see this code can move only one cell.
I'll appreciate if someone can show a solution to this matter.

I didn't fully test this code, in part because I doubt that you really want to post the data to any of the 12 monthly sheets. Instead, I suspect that the data must be posted to one particular of the monthly sheets. However, that isn't what you said, and therefore my code will look in all sheets and stop looking after it finds a match. This is something you may find easy to adjust. Otherwise I can help you do it.
However, what this code needs now is thorough testing. :-)
Sub TestNewCode()
' 16 Sep 2017
Const Tabs As String = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
Dim WsData As Worksheet
Dim Ws As Worksheet ' any of the monthly sheets
Dim WsName() As String
Dim Rend As Long, Rl As Long ' last row in WsData / Ws
Dim R As Long, Rm As Long ' row counter WsData / Ws
Dim Entry As Variant ' one Data entry
Set WsData = Worksheets("Data")
WsName = Split(Tabs, " ")
Application.ScreenUpdating = False
With WsData
Rend = .Cells(.Rows.Count, "A").End(xlUp).Row
For R = 2 To Rend
Entry = .Range(.Cells(R, 1), .Cells(R, 3)).Value ' A:C
Rm = FindMatch(Entry, Ws, WsName)
If Rm Then ' rm = 0 if not found
With Ws.Cells(Rm, 5).Resize(1, UBound(Entry, 2))
.Value = Entry
.Interior.Color = vbYellow
End With
End If
Next R
End With
Application.ScreenUpdating = True
End Sub
Private Function FindMatch(Entry As Variant, _
Ws As Worksheet, _
WsName() As String) As Long
' return zero if no match was found
Dim Rng As Range ' search range
Dim Fnd As Range
Dim Rl As Long
Dim i As Long
For i = 0 To UBound(WsName)
On Error Resume Next
Set Ws = Worksheets(WsName(i))
If Err Then
MsgBox "Worksheet " & WsName(i) & " doesn 't exist.", _
vbInformation, "Missing worksheet"
Else
With Ws
Rl = .Cells(.Rows.Count, 1).End(xlUp).Row
Set Rng = .Range(.Cells(2, 1), .Cells(Rl, 3))
Set Fnd = Rng.Find(What:=Entry(1, 1), _
After:=Rng.Cells(Rng.Cells.Count), _
LookIn:=xlValues, _
Lookat:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
MatchCase:=False, _
MatchByte:=False)
If Not Fnd Is Nothing Then
FindMatch = Fnd.Row
Exit For
End If
End With
End If
Next i
If Fnd Is Nothing Then
MsgBox "Code " & Entry(1, 1) & " wasn't found.", _
vbInformation, "Missing Code"
End If
End Function

Related

Dynamically insert rows

I want to ask couple of Qs.
1.
Code below dynamically add new rows before the cell that contain "7000"
Code works but it is not very efficient. It slows down where I used For Next loop to insert new rows. Is there better way to insert rows dynamically before cell that contain "7000".
Sub PLFinalReport()
Dim XCount As Integer
Dim YCount As Integer
Dim i As Integer
JobsPivot.Activate
XCount = JobsPivot.Range("H3", Range("H3").End(xlDown)).Count
PLJob.Activate
Range("G6", Range("G6").End(xlDown)).Find("7000").Select
YCount = Range(ActiveCell, ActiveCell.End(xlUp)).Count - 2
For i = 1 To (XCount - YCount)
ActiveCell.EntireRow.Insert
Next i
JobsPivot.Activate
JobsPivot.Range("H3", Range("H3").End(xlDown).End(xlToRight)).Copy
PLJob.Range("G6").PasteSpecial
End Sub
Also I want to copy the forumulas from cell B444 to F44 and paste them all the way down to the last row containing formulas. Same way as we do in the excel with fill handle.
Thanks
Please try this code.
Sub PLFinalReport()
' 13 Feb 2018
Dim SourceRange As Range
Dim TargetRange As Range
Dim R As Long
Dim C As Long
With Application
.ScreenUpdating = False
.Calculation = xlCalculationManual
End With
Set SourceRange = JobsPivot.Range("H3")
With SourceRange
C = .End(xlToRight).Column - .Column + 1
Set SourceRange = .Resize((.End(xlDown).Row - .Row + 1), C)
End With
C = 7 ' Column G
With PLJob
R = MatchRow("7000", .Cells(6, C)) ' = G6
If R Then
Set TargetRange = Range(.Cells(R, C), .Cells((R + SourceRange.Rows.Count - 1), C))
TargetRange.Rows.EntireRow.Insert
SourceRange.Copy .Cells(R, "H") ' column H
Else
' "7000" wasn't found
End If
End With
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
End With
End Sub
Private Function MatchRow(ByVal Crit As Variant, _
ByVal StartCell As Range) As Long
' 13 Feb 2018
Dim Rng As Range
Dim Rl As Long
Dim Fnd As Range
With StartCell.Worksheet
Rl = .Cells(.Rows.Count, 1).End(xlUp).Row ' find last used row
Set Rng = Range(.Cells(StartCell.Row, StartCell.Column), _
.Cells(Rl, StartCell.Column))
End With
With Rng
Set Fnd = .Find(What:=Crit, _
After:=.Cells(.Cells.Count), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False)
End With
On Error Resume Next
MatchRow = Fnd.Row
End Function
I was more careful with the Find function because there are many reasons why the item might not be found causing an "unexplained" crash. One of the reasons is that Excel remembers most of the settings of your last use of Find. If your code doesn't make clear which settings to use you may not always get the same result with the same code. Consider the setting of the LookAt property in this regard.
I didn't look into your second question because - in essence - it is another question.
you can do that in one statement like:
Range("G6", Range("G6").End(xlDown)).Find("7000").Resize(XCount - YCount).EntireRow.Insert
as for your second question you can use something like follows (explanations in comments, so you can adjust it to your needs):
With PLJob 'reference PLJob
With .Range("B2", .Cells(.Rows.Count, 1).End(xlUp)) 'reference its columns A and B cells from row 2 down to column A last not empty one
.Formula = .Resize(1).Formula 'copy/paste formulas
End With
End With

Copy Partial Row Identified by ID

I have two Excel sheets in a workbook that I am wanting to copy data between and I can't figure it out. I am trying to adapt the code from a prior answer here but I can't get it to function how I want.
In short the two sheets are "Active" and "Term" for if an employee is active with the company or not. I am trying to get a pop-up when I run the macro to request entry of the employee ID. Once entered I want to find that unique ID in column A and then select a portion of the cells (cells A to G) in that row (of the unique value) then cut and paste it in the next empty row in the "term" sheet. Once that is done I want to delete the entire row from the active sheet.
I've used the match function nested within an index function to reference the unique value and return data from the sheets and others but I can't figure out if those will somehow help and how to implement them. What I am asking may not be possible. I can record a macro but the values are static and would only work that one exact time. Thank you in advance.
Sub EmployeeTermination()
Dim x As Long
Dim iCol As Integer
Dim MaxRowList As Long
Dim S As String
Dim fVal As String
Dim fRange As Range
Set wssource = Worksheets("Active")
Set wstarget = Worksheets("Term")
iCol = 1
MaxRowList = wssource.Cells(Rows.Count, iCol).End(xlUp).Row
For x = MaxRowList To 1 Step -1
S = wssource.Cells()
If S = "Yes" Or S = "yes" Then
fVal = InputBox(Enter employee ID:)
Set fRange = wstarget.Columns("A:A").Find(What:=fVal, LookIn:=xlFormulas, LookAt _
:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:= _
False, SearchFormat:=False)
If fRange Is Nothing Then
AfterLastTarget = wstarget.Cells(Rows.Count, 1).End(xlUp).Row + 1
wssource.Rows(x).Copy
wstarget.Rows(AfterLastTarget).PasteSpecial Paste:=xlPasteValuesAndNumberFormats
End If
End If
Next
Application.ScreenUpdating = True
End Sub
I know this basically rewrote your code, but I added a few checks to ensure you want to delete your employee. I made the assumption that the employee's name is in column B, so if not you can change this line:
If MsgBox("Are you sure you want to terminate " & wsActive.Cells(rngEmployee.Row, _
2) & "?", vbYesNo) Then
by replacing the 2 in the second row with whatever column number you would like. (or you can simply delete this check altogether).
I also added minimal error handling.
Option Explicit
Const Err_EmpNotFound = 1000
Public Function NextRow(ByVal ws As Worksheet, Optional ByVal col As Variant = 1) As Long
With ws
NextRow = .Cells(.Rows.Count, col).End(xlUp).Row + 1
End With
End Function
Sub EmployeeTermination()
'On Error GoTo ErrHandler
Dim wsActive As Worksheet, wsTerm As Worksheet
Set wsActive = ThisWorkbook.Worksheets("Active")
Set wsTerm = ThisWorkbook.Worksheets("Term")
'Locate the employee
Dim rngEmployee As Range, sEmployeeID As String, empDataArr As Variant
sEmployeeID = Application.InputBox("Enter Employee ID")
Set rngEmployee = wsActive.Range("A:A").Find(sEmployeeID, Lookat:=xlWhole)
If rngEmployee Is Nothing Then
Err.Raise vbObjectError + Err_EmpNotFound, Description:="Employee Not Found"
End If
'Prompt before termination (assume's employee's name is column 2 (col B)
If MsgBox("Are you sure you want to terminate " & wsActive.Cells(rngEmployee.Row, _
2) & "?", vbYesNo) = vbNo Then
Exit Sub
End If
empDataArr = rngEmployee.Columns("A:G").Value
'Delete the data
rngEmployee.EntireRow.Delete
'Add employee to termination sheet (and date column "H")
With wsTerm.Rows(NextRow(wsTerm))
.Columns("A:G") = empDataArr
.Columns("H") = Date
End With
'Notify user of completion
MsgBox "Employee was successfully terminated!"
Exit Sub
ErrHandler:
Dim errBox As Long
Select Case Err.Number - vbObjectError
Case Err_EmpNotFound
errBox = MsgBox(Err.Description, vbRetryCancel)
If errBox = vbRetry Then
Err.Clear
EmployeeTermination
End
End If
Case Else
MsgBox Err.Description, Title:=Err.Number
End Select
End Sub

VBA to Copy and Paste Based on Two Criterias

It's is possible to create a macro that do a mathematical sum?
I don't know how to explain. But I already saw another answers but I could not make work for me.
Here is what I trying to do:
I have this Worksheet
iTEM 1 [1]: https://i.stack.imgur.com/v7vXF.jpg
And I to put values as the image below. Make a search and make a mathematical sum in the "available" according with the group.
ITEM 2 [2]: https://i.stack.imgur.com/wQnxu.png
Here would be the result:
ITEM 3 [3]: https://i.stack.imgur.com/ify7J.png
To answer your question, tongue in cheek, Excel is very good at doing mathematical sums, and with the help of VBA it gains versatility. To prove the point, the code below doesn't only act upon your selection in the 'Update' sheet, it takes all the items in the 'Update' sheet and posts them to the 'Database' sheet. Click twice and it's done twice over. There is no break.
Option Explicit
Enum Nup ' Sheet Update
NupFirstDataRow = 2
NupName = 1 ' 1 = column A
NupGroup = 5
NupQty = 7
End Enum
Enum Ndt ' Sheet Data
NdtFirstDataRow = 2
NdtName = 1 ' 1 = column A
NdtGroup = 3
NdtQty ' = 4
NdtOffset = 3 ' NdtGroup + NdtOffset = Group2 column
End Enum
Sub UpdateQuantity()
' 09 Jan 2018
Dim WsUpdate As Worksheet ' Sheet where data are entered
Dim WsData As Worksheet ' Sheet where data are updated
Dim Rng As Range
Dim SearchRng As Range
Dim Itm As String ' an item's name
Dim Qty As Long ' Update quantity (designed for integers)
Dim Rt As Long ' target row in WsData
Dim Rl As Long ' last row in WsUpdate
Dim ClmOffset As Long ' helper
Dim R As Long ' row counter in WsUpdate
Dim Ct As Ndt ' column in WsData
Set WsUpdate = Worksheets("Update")
Set WsData = Worksheets("Database")
With WsData
Rl = .Cells(.Rows.Count, NupName).End(xlUp).Row
Set Rng = Range(.Cells(NdtFirstDataRow, NdtName), .Cells(Rl, NdtQty + NdtOffset))
End With
Application.ScreenUpdating = False
With WsUpdate
Rl = .Cells(.Rows.Count, NupName).End(xlUp).Row
For R = NupFirstDataRow To Rl
Itm = .Cells(R, NupName).Value
Set SearchRng = Range(Rng.Columns(NdtName), Rng.Columns(NdtName))
If CellAddress(Itm, SearchRng, Rt) Then
Itm = .Cells(R, NupGroup).Value
With WsData
Set SearchRng = Range(.Cells(R, NdtGroup), .Cells(R, NdtGroup + NdtOffset))
End With
If CellAddress(Itm, SearchRng, Ct) Then
Qty = Val(.Cells(R, NupQty).Value)
With WsData.Cells(Rt, Ct + 1)
Qty = Val(.Value) + Qty
.Value = Qty
End With
End If
End If
Next R
End With
Application.ScreenUpdating = True
End Sub
Private Function CellAddress(ByVal Itm As String, _
SearchRange As Range, _
Rc As Long) As Boolean
' 09 Jan 2018
' Rc is a return variable (either column or row = 0 if not found)
Dim ClmRng As Range
Dim Fnd As Range
Dim i As Long
With SearchRange
Set Fnd = .Find(What:=Itm, After:=.Cells(.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False)
If Fnd Is Nothing Then
Rc = 0
MsgBox "Item """ & Itm & """ wasn't found.", _
vbInformation, "Update failed"
Else
Rc = IIf(.Rows.Count > 1, Fnd.Row, Fnd.Column)
CellAddress = True
End If
End With
End Function
The enumerations at the top of the code control which columns and rows are used. You can modify these numbers. Observe that the quantity columns in the Database must be adjacent to the Group columns. The only other place in the code you may have to change concerns the names of the two worksheets. The code must be in a standard code module in the same workbook.

VBA - Find all matches across multiple sheets

I am working on a macro that will search an entire workbook for various codes. These codes are all six digit numbers. Codes I wish to search for are input in column A of a sheet called "Master". If a code found on another sheet matches one in Master it's sheet name and cell will be pasted in column B next to it's match in Master. When successful the end result looks like this.
The code posted below works in certain cases, but fails quite often. Occasionally a run-time error will appear, or an error message with "400" and nothing else. When these errors occur the macro fills a row with matches for a blank value at the end of all the listed codes. This is obviously not an intended function.
I am at a loss regarding the above error. I have wondered if limiting the search range would help stability. All codes on other sheets are only found in column A, so searching for matches in all columns as is done currently is quite wasteful. Speed is secondary to stability however, I first want to eliminate all points of failure.
Sub MasterFill()
Dim rngCell As Range
Dim rngCellLoc As Range
Dim ws As Worksheet
Dim lngLstRow As Long
Dim lngLstCol As Long
Dim strSearch As String
Sheets("Master").Select
lngLstRowLoc = Sheets("Master").UsedRange.Rows.Count
Application.ScreenUpdating = False
For Each rngCellLoc In Range("A1:A" & lngLstRowLoc)
i = 1
For Each ws In Worksheets
If ws.Name = "Master" Then GoTo SkipMe
lngLstRow = ws.UsedRange.Rows.Count
lngLstCol = ws.UsedRange.Columns.Count
ws.Select
For Each rngCell In Range(Cells(2, 1), Cells(lngLstRow, lngLstCol))
If InStr(rngCell.Value, rngCellLoc) > 0 Then
If rngCellLoc.Offset(0, i).Value = "" Then
rngCellLoc.Offset(0, i).Value = ws.Name & " " & rngCell.Address
i = i + 1
End If
End If
Next
SkipMe:
Next ws
Next
Application.ScreenUpdating = True
Worksheets("Master").Activate
MsgBox "All done!"
End Sub
See if this doesn't expedite matters while correcting the logic.
Sub MasterFill()
Dim addr As String, fndCell As Range
Dim rngCellLoc As Range
Dim ws As Worksheet
Application.ScreenUpdating = False
With Worksheets("Master")
For Each rngCellLoc In .Range(.Cells(1, "A"), .Cells(.Rows.Count, "A").End(xlUp))
For Each ws In Worksheets
If LCase(ws.Name) <> "master" Then
With ws.Columns("A")
Set fndCell = .Find(what:=rngCellLoc.Value2, After:=.Cells(1), _
LookIn:=xlFormulas, LookAt:=xlPart, _
MatchCase:=False, SearchFormat:=False)
If Not fndCell Is Nothing Then
addr = fndCell.Address(0, 0)
Do
With rngCellLoc
.Cells(1, .Parent.Columns.Count).End(xlToLeft).Offset(0, 1) = _
Join(Array(ws.Name, fndCell.Address(0, 0)), Chr(32))
End With
Set fndCell = .FindNext(After:=fndCell)
Loop While addr <> fndCell.Address(0, 0)
End If
End With
End If
Next ws
Next
.Activate
End With
Application.ScreenUpdating = True
MsgBox "All done!"
End Sub
I've used LookAt:=xlPart in keeping with your use of InStr for criteria logic; if you are only interested in whole cell values change this to LookAt:=xlWhole.
I've restricted the search range to column A in each worksheet.
Previous results are not cleared before adding new results.
Your own error was due to the behavior where a zero length string (blank or vbNullString) is found within any other string when determined by Instr.

Excel VBA Gathering Names from a Schedule of People Working Today

Even though I thought this would be a common question, I have searched and can't seem to find an answer.
I have a work schedule and I'd like to search the today's date and return all the names of those who are scheduled to work today. I built a code that works but it takes a long time to complete and is not 100% effective every time its run. I am sure there must be a better and faster way to do this but I have not yet been able to find one. I have it broken apart into two different codes. The first one finds the column where today's date is located and the second one gathers the names and places them onto the next sheet.
Here's the First Sub:
Sub GetDateRow_()
'//////Finds the row that has today's date and returns the value of that row to cell C34\\\\\\
Dim SearchMe As Integer
SearchMe = Sheets("Sheet1").Range("C33")
Set FindMe = Sheets("Sheet1").Range("C5:AD5").Find(What:=SearchMe, LookIn:=xlValues, LookAt:= _
xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, SearchFormat:=False)
Sheets("Sheet1").Range("C34").Value = Cells(1, FindMe.Column)
End Sub
And the Second Sub:
Sub CopyScheduledToList()
'//////Searches Today's day Column from the schedule given by GetDateRow Sub & assimbles \\\\\\\
'////// the names of those who are scheduled to work today to a list on Page 2 \\\\\\\
Dim Ccount As Integer
Dim lngLoop As Long
Dim RowCount As Integer
Dim dShift As String
Dim cShift As String
Ccount = 1
dShift = "A63"
cShift = "TLA"
RowCount = Sheets("Sheet1").Range("C34").Value
lngLoop = 1
For lngLoop = 1 To Rows.count
If Cells(lngLoop, RowCount).Value = cShift Then Worksheets("Sheet2").Cells(1, 4).Value = Worksheets("Sheet1").Cells(lngLoop, 1).Value
'////// Get's the Team Leader and places name into column D on Page 2
If Cells(lngLoop, RowCount).Value = dShift Then Worksheets("Sheet2").Cells(Ccount, 1).Value = Worksheets("Sheet1").Cells(lngLoop, 1).Value
If Worksheets("Sheet2").Range("A" & Ccount).Value <> "" Then Ccount = Ccount + 1
'////// Places the name from the working list onto page 2 and adds a count so the next value found
'////// will go to the next empty row on Sheet 2
Next lngLoop
End Sub
Again, your help is greatly appreciated!
Your excessively long run times will be due to looping over 1048576 cells in your For lngLoop = 1 To Rows.count loop. That can be improved by just processing as far as the last cell that contains data in the applicable column.
The problem of it not always working correctly is almost certainly due to the fact that you have some Cells references which aren't qualified with the sheet that you want to use, and therefore they refer to the ActiveSheet.
Sub GetDateRow_()
'//////Finds the row that has today's date and returns the value of that row to cell C34\\\\\\
Dim SearchMe As Date
Dim FindMe As Range
With Worksheets("Sheet1")
SearchMe = .Range("C33").Value
Set FindMe = .Range("C5:AD5").Find(What:=SearchMe, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If FindMe Is Nothing Then
MsgBox "Date not found!"
Else
'I think this line
'.Range("C34").Value = .Cells(1, FindMe.Column).Value
'should be
.Range("C34").Value = FindMe.Column
'so that it saves the column number you want
End If
End With
End Sub
Sub CopyScheduledToList()
'//////Searches Today's day Column from the schedule given by GetDateRow Sub & assembles \\\\\\\
'////// the names of those who are scheduled to work today to a list on Page 2 \\\\\\\
Dim Ccount As Integer
Dim lngLoop As Long
Dim TodaysCol As Long
Dim dShift As String
Dim cShift As String
Dim lastRow As Long
Dim wsSrc As Worksheet
Dim wsDst As Worksheet
Ccount = 1
dShift = "A63"
cShift = "TLA"
Set wsSrc = Worksheets("Sheet1")
Set wsDst = Worksheets("Sheet2")
TodaysCol = wsSrc.Range("C34").Value
'Find last used row in today's column
lastRow = wsSrc.Cells(wsSrc.Rows.Count, TodaysCol).End(xlUp).Row
For lngLoop = 1 To lastRow
If wsSrc.Cells(lngLoop, TodaysCol).Value = cShift Then
wsDst.Cells(1, "D").Value = wsSrc.Cells(lngLoop, "A").Value
End If
'////// Get's the Team Leader and places name into column D on Page 2
If wsSrc.Cells(lngLoop, TodaysCol).Value = dShift Then
If wsSrc.Cells(lngLoop, "A").Value <> "" Then
wsDst.Cells(Ccount, "A").Value = wsSrc.Cells(lngLoop, "A").Value
Ccount = Ccount + 1
End If
End If
'////// Places the name from the working list onto page 2 and adds a count so the next value found
'////// will go to the next empty row on Sheet 2
Next lngLoop
End Sub
Your first sub is, in fact, a function (or should be) which returns a value which can be assigned to a variable in your second sub. The following code realises that concept. It is different in other respects too, but I think you will like it. Please try.
Option Explicit
Sub CopyScheduledToList()
'//////Searches Today's day Column from the schedule given by GetDateRow Sub & assambles \\\\\\\
'////// the names of those who are scheduled to work today to a list on Page 2 \\\\\\\
' it is best practise, not to have any hard-coded addresses in the code.
' Therefore it is good to place all parameters separate from and before the code:
Const SearchRow As Long = 5
Const dShift As String = "A63"
Const cShift As String = "TLA"
Dim WsMain As Worksheet ' better to set your own variable
Dim WsOutput As Worksheet ' even if it will be "ActiveSheet"
Dim TgtColumn As Long
Dim Rlast As Long ' last data row in WsMain
Dim Rcount As Long ' output row counter
Dim R As Long
Set WsMain = ActiveSheet ' might be Sheets("Sheet1")
Set WsOutput = Worksheets("Sheet2") ' or, simply, Sheet1
TgtColumn = DateColumn(WsMain, SearchRow)
If TgtColumn < 1 Then Exit Sub
Rcount = 1
With WsMain
Rlast = .Cells(.Rows.Count, TgtColumn).End(xlUp).Row
For R = 1 To Rlast
Select Case .Cells(R, TgtColumn).value
Case cShift
'////// Get's the Team Leader and places name into column D on WsOutput
WsOutput.Cells(Rcount, "D").value = .Cells(R, 1).value
Case dShift
WsOutput.Cells(Rcount, "A").value = .Cells(R, 1).value
Case Else
Exit Sub ' define the correct response if neither is found
End Select
If Len(WsOutput.Cells(Rcount, "A").value) Then Rcount = Rcount + 1
'////// Places the name from the working list onto page 2 and adds a count so the next value found
'////// will go to the next empty row on Sheet 2
Next R
End With
End Sub
Private Function DateColumn(Ws As Worksheet, _
ByVal SearchRow As Long) As Long
' returns the row that has today's date
' return 0 if not found
Dim SearchMe As Variant
Dim TgtDate As String
Dim Fnd As Range
If SearchRow < 1 Then Exit Function
Do
TgtDate = InputBox("Enter the target date", _
"List shift workers", _
Format(Date, "Short Date"))
' you can also set the default like Format(Date + 1, "d/m/yy")
' the sample date format must match your regional settings
If IsDate(TgtDate) Then
SearchMe = CDate(TgtDate)
' SearchMe will have the date in the format set
' in your regional settings
Exit Do
Else
MsgBox "Please enter a valid date" & vbCr & _
"in d-m-yy format", vbExclamation, "Invalid date"
' adjust the required format to your regional settings
End If
Loop While Len(TgtDate) ' enter blank or press Cancel to exit
Set Fnd = Ws.Rows(SearchRow).Find(What:=SearchMe, _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
If Not Fnd Is Nothing Then DateColumn = Fnd.Column
End Function