Lookup unique ID and insert date into next column - excel

I Have a table that is set out with these headers:
Task ID | Description | Date completed | Time completed
Let say that the table is set out so that Task ID is in cell A3, Description B3, Date Completed C3, and Time Completed D3. In cell A1 I will input the Task ID to be looked up.
What I would like to happen is that when the macro is run, the Task ID entered into cell A1 is found in the table and then the date and time (at the time of running the Macro) are entered into the corresponding cells in columns C and D.
Thanks!

It sounds like you just need a bunch of VLOOKUPS. In cell A1 enter your task ID. In cell A2 enter a VLOOKUP for the description (Assuming you have 100 Ids)
=VLOOKUP($A$1,$A$4:$D$100,2,FALSE)
and in A3 for the Date etc
=VLOOKUP($A$1,$A$4:$D$100,3,FALSE)

The following two procedures represent one way to do what you are interested in. The first uses the FIND function to locate the task ID in your table that matches the contents of cell A1; the second runs the first procedure whenever you make an entry in A1.
Date and time logging code
You will need to paste this code into a standard VBA module in the workbook. A standard code module can be inserted by selecting Visual Basic from the Developer tab of the ribbon, and then choosing Insert, Module on the main menu of the VBA code editor.
Note that the procedure assumes that the task table is in Sheet1 of the workbook. If it is in another sheet, you will need to change the name "Sheet1" in the code to the correct name.
Sub LogTaskCompletion()
Dim lastRow As Long
Dim foundCell As Range
With ThisWorkbook.Sheets("Sheet1") '<-- change sheet name here
If Not .Range("A1").Value = "" Then
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
'do the search
Set foundCell = .Range("A2:A" & lastRow).Find(What:=.Range("A1").Value, _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows)
If Not foundCell Is Nothing Then
'a match! post the date and time for the task
With foundCell
.Offset(0, 2).Value = Date
.Offset(0, 2).NumberFormat = "mm-dd-yyyy"
.Offset(0, 3).Value = TimeValue(Now())
.Offset(0, 3).NumberFormat = "hh:mm am/pm"
End With
Else
'no match!
MsgBox "Cannot find task " & .Range("A1").Value
End If
.Range("A1").ClearContents
End If
End With
End Sub
Macro trigger code
This procedure will run the preceding macro whenever an entry is made in A1.
It needs to be installed as code private to the worksheet the task table is in. The easiest way to do this is to right-click on the worksheet's tab, select View Code, and then paste the code into the editor pane that pops up.
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("A1")) Is Nothing Then
Exit Sub
End If
Application.EnableEvents = False
LogTaskCompletion
Application.EnableEvents = True
End Sub
After installing the code, save the file as an macro-enabled ("xlsm") workbook.

It can be achieved with combination of Worksheet_Change and Vlookup. Kindly put this code in sheet code section.
Once the value is entered in A1 the macro is triggered and if the values is found in the table it gets the corresponding values (description) using Vlookup. Also it enters the current date & time.
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
Application.EnableEvents = False
If Not Intersect(Target, Range("A1")) Is Nothing Then
Dim lastRow As Long, tblRng As Range
lastRow = Range("A" & Rows.Count).End(xlUp).Row
If lastRow <= 3 Then lastRow = 3
Set tblRng = Range("A3:D" & lastRow)
dt = Application.VLookup(Target, tblRng, 1, 0)
If Not IsError(dt) Then
With Target
.Offset(0, 1).Value = Application.VLookup(Target, tblRng, 2, 0)
.Offset(0, 2).Value = Date
.Offset(0, 2).NumberFormat = "mm/dd/yyyy"
' if you want date from tbl use Application.VLookup(Target, tblRng, 3, 0)
.Offset(0, 3).Value = TimeValue(Now())
.Offset(0, 3).NumberFormat = "hh:mm am/pm"
' if you want date from tbl use Application.VLookup(Target, tblRng, 4, 0)
End With
Else
With Target
.Offset(0, 1).Value = vbNullString
.Offset(0, 2).Value = vbNullString
.Offset(0, 3).Value = vbNullString
End With
End If
End If
Application.EnableEvents = True
End Sub

Related

Copy values as they're entered into a column & paste to another worksheet - where am I going wrong?

vAs the title suggests, I'm trying to copy and paste values to keep as a log as these values will be deleted shortly after they've been entered.
Long story short, a user will scan a barcode and a unique string of characters that correspond to the scanned barcode will be automatically entered into whichever cell is selected (usually A2). These strings are parent barcodes, so immediately after one has been scanned into A2 the user will start scanning their related children barcodes into B2, B3 and so on depending on how many children there are (always a completely random number).
Here's what I have so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Dim intRow As Integer
Dim intCount As Integer
Set ws = Worksheets("log")
intRow = ws.Range("A1").CurrentRegion.Rows.Count + 1
'Check if WandID exist in log.
If Target.Address = "$A$2" Then
intCount = Application.WorksheetFunction.CountIf(ws.Range("D:D"), Target.Value)
If intCount <> 0 Then
Target.Interior.Color = RGB(255, 0, 0)
MsgBox "this wandID has already been used, please try a different barcode"
Range("A2").ClearContents
End
Else
Target.Interior.Color = xlNone
ws.Cells(intRow, "D") = Target.Parent.Range("A2")
ws.Cells(intRow, "E") = Target
End If
End If
End Sub
On the destination worksheet (named 'log') I've set up a simple table to organise the copied / scanned data and added some dummy data as a first entry - seeing as this workbook will be used regularly I wanted this process to keep adding scanned codes beneath the previous (dummy parent code in D2, dummy child codes in E2:E9), so ideally when I enter a new parent code into A2 of the source sheet, it should be copied to D10 on the destination sheet, and any corresponding child codes added to B2 etc. of the source sheet should be copied to E10 etc. of the destination sheet. Instead what's happening is the parent code will be added to D10:E10.
I have a feeling the line
"ws.Cells(intRow, "E") = Target"
is the problem, but not sure of what to change it to.
Any help or advice would be hugely appreciated!
I believe the code below will help you achieve your objective, it checks for the Next Free Row on Column D and that's where the Parent ID will be entered, similarly it will check the Child IDs in Column B and find the Next available row on Column E to paste the list into, the main changes are the use of Application.EnableEvents and the copy of data from Column B to Column E:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet: Set ws = Worksheets("log")
Dim NextRow As Long, ChildRow As Long, ChildNextRow As Long
NextRow = ws.Cells(ws.Rows.Count, "D").End(xlUp).Offset(1, 0).Row
'get the Next Free row in Column D
ChildRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
'get the Last Row with data on Column B
ChildNextRow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Offset(1, 0).Row
'get the Next Free Row on Column E
'Check if WandID exist in log (Column D).
If Target.Address = "$A$2" Then
Application.EnableEvents = False
'Turn Events off, so it doesn't fire the Change Event while we write to it
intCount = Application.WorksheetFunction.CountIf(ws.Range("D:D"), Target.Value)
'check if Parent ID has been used previously by check Column D
If intCount <> 0 Then
Target.Interior.Color = RGB(255, 0, 0)
MsgBox "This wandID has already been used, please try a different barcode", vbInformation, "Duplicate Entry"
ws.Range("A2").ClearContents
Else
Target.Interior.Color = xlNone
ws.Cells(NextRow, "D") = ws.Range("A2")
ws.Range("B2:B" & ChildRow).Copy Destination:=ws.Range("E" & ChildNextRow)
End If
Application.EnableEvents = True
End If
End Sub

Automatically enter date & time as cell is updated/changed

Background:
I want the macro to automatically record the time and date on the empty cell on right IF the "cell of interest" changes values through a formula.
e.g. IF cell("k3") changes values, THEN register DATE & TIME when it changed on cell ("L3");
IF cell("L3") IS NOT empty, THEN register the TIME & DATE in cell("M3"), and so forth until it finds an empty cell.
So far, I have not been able to prompt the macro whenever the "cell of interest" changes values.
PS: the latter is an IF formula that outputs 2 possible strings: "OK" and "ISSUE RISK WARNING"
I have tried the following code:
Private sub Register_timestamp(ByVal Target As Range)
'This sub registers the date and hour at which the cells in column K:K changed values.
Dim WorkRng As Range
Dim Rng As Range
Dim xOffsetColumn As Integer
Set WorkRng = Intersect(Application.ActiveSheet.Range("K:K"))
xOffsetColumn = 1
If WorkRng Is Nothing Then
Application.EnableEvents = False
For Each Rng In WorkRng
If Not VBA.IsEmpty(Rng.Value) Then
Rng.Offset(0, xOffsetColumn).Value = Now
Rng.Offset(0, xOffsetColumn).NumberFormat = "dd-mm-yyyy, hh:mm:ss"
Else
xOffsetColumn = xOffsetColumn + 1
End If
Next
Application.EnableEvents = True
End If
End sub
Expected output:
If I were to manually change the cell that is subject to the "cell of interest"'s IF Function - and triggers it -, the date and time at which the "cell of interest" changed, e.g.: 14/05/2019 21:44:21
Here's how you'd implement my suggestions. Make sure this code is on the correct worksheet's code module.
Private Sub Worksheet_Calculate()
Dim rMonitored As Range
Dim MonitoredCell As Range
Dim vSelected As Variant
Dim aNewValues As Variant
Dim ixFormulaCell As Long
On Error Resume Next
Set rMonitored = Me.Columns("K").SpecialCells(xlCellTypeFormulas)
On Error GoTo 0
If rMonitored Is Nothing Then Exit Sub 'No formula cells in column K
Application.EnableEvents = False 'Disable events to prevent infinite calc loop
Set vSelected = Selection 'Remember current selection (it may not be a range)
'Prepare the array that will store the new values, the cells those values are in, and whether or not there was a change
ReDim aNewValues(1 To rMonitored.Cells.Count, 1 To 3)
'Column1 = new value
'Column2 = cell address
'Column3 = did value change?
'Get the new value for each formula in column K
ixFormulaCell = 0
For Each MonitoredCell In rMonitored.Cells 'The formula cells may not be in a contiguous range
ixFormulaCell = ixFormulaCell + 1
aNewValues(ixFormulaCell, 1) = MonitoredCell.Value 'Store the new value
Set aNewValues(ixFormulaCell, 2) = MonitoredCell 'Store the cell address
Next MonitoredCell
Application.Undo 'This will undo the most recent change, which allows us to compare the new vs old to check for formula updates
ixFormulaCell = 0
For Each MonitoredCell In rMonitored.Cells
ixFormulaCell = ixFormulaCell + 1
'Check if the formula result is different
If MonitoredCell.Value <> aNewValues(ixFormulaCell, 1) Then
'Formula result found to be different, record that
'We can't put the timestamp in now because we still have to redo the most recent change
aNewValues(ixFormulaCell, 3) = True
End If
Next MonitoredCell
Application.Undo 'Redo the most recent change to put worksheet back in the new state
'Now that we've completed our comparison and have re-done the most recent change, check what did change and put in a timestamp in the next empty cell in same row
For ixFormulaCell = LBound(aNewValues, 1) To UBound(aNewValues, 1)
'Check for formula result change
If aNewValues(ixFormulaCell, 3) Then
'Formula result change found, get next empty cell in same row
With Me.Cells(aNewValues(ixFormulaCell, 2).Row, Me.Columns.Count).End(xlToLeft).Offset(, 1)
'Next empty cell found, put in the current datetime stamp and format it
.Value = Now
.NumberFormat = "dd-mm-yyyy, hh:mm:ss"
End With
End If
Next ixFormulaCell
vSelected.Select 'Re-select the remembered selection so that this operation is invisible to users
Application.EnableEvents = True 'Re-enable events so that the next calculation can be monitored for formula changes in cells of interest
End Sub

If user inputs text in cell then return user name and date in another cell

Help, In shared sheet, If user adds text in cell, then click button to return user name and date in another cell.
Example, cell B3 = Complete, then cell C3 returns John Smith 14/04/19
Many thanks!
No need for VBA. Try:
=IF(B6="Complete", "User Name " & TEXT(NOW(),"dd/mm/yyyy"),"")
Results:
Some more information might be helpful. I'm going to assume that the layout of the sheet is as follows. You'll need some way of specifying who the current user is, and in this example I have used cell A2.
If the layout isn't as shown, you will need to edit the code accordingly.
Sub date_user()
Dim lastrow As Long
Dim rng As Range, cell As Range
With Application.ActiveSheet
Name = .Range("A2").Value
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set rng = .Range("B3:B" & lastrow)
End With
For Each cell In rng
If cell.Offset(0, 1).Value = 0 Then
If Len(cell.Value) > 0 Then
cell.Offset(0, 1).Value = Name & " " & Format(Now(), "MMM-DD-YYYY")
End If
End If
Next
End Sub

Create a new datestamp every time a certain cell changes?

I have a cell that states the status of a project, and this status will change frequently.
Whenever the status gets changed, I would like a row to state the time the status was changed and the name of the new status.
I have next to no experience with VBA, so any assistance would be greatly appreciated. So far I have this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 And Target.Row = 4 Then
Target.Offset(10, 3) = Format(Now(), "YYYY-MM-DD HH:MM:SS")
End If
End Sub
This code successfully lists the time in cell G7 whenever the status contained in cell D4 changes, but it always repopulates the same cell, I would like each successive status change to list the date stamp in cell G8, then G9, then G10, and so on.
It also doesn't list what the status cell D4 is changed too, ideally I would like that to be listed in F7, then F8, then F9, and so on.
If you are only interested in a Worksheet_Change on cell D4, you can use the Intersect method shown below
To start a running list, you will need to determine that last used cell in Column G and offset accordingly
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("D4")) Is Nothing Then
Dim LR As Long: LR = Range("G" & Rows.Count).End(xlUp).Offset(1).Row
Target.Offset(LR - Target.Row, 3) = Format(Now(), "YYYY-MM-DD HH:MM:SS")
Target.Offset(LR - Target.Row, 4) = Target
End If
End Sub
Please try this.
Private Sub Worksheet_Change(ByVal Target As Range)
Const Tgt As String = "D4" ' monitored cell
Const FirstRecord As Long = 7 ' change as required
Const Fmt As String = "yyyy-mm-dd hh:mm:ss"
Dim Rl As Long ' last used row
If Target.Address = Range(Tgt).Address Then
Application.EnableEvents = False
Rl = Application.WorksheetFunction.Max( _
Cells(Rows.Count, "F").End(xlUp).Row + 1, FirstRecord)
With Cells(Rl, "G")
.Value = Now()
.NumberFormat = Fmt
Target.Copy Destination:=.Offset(0, -1)
End With
Application.EnableEvents = True
End If
End Sub

Macro is not working automatically

I am using a macro to write a datestamp when a column is modified. The idea is that whenever the status changes it gives the running time for that particular status. I have four columns:
A b c d
clearing 24.04.2015 1 empty
**when stauts is changed**
A b c d
wait for start 24.04.2015 2 24.04.2015
formual for c is :
IF(RC[-2]="";"";IF(RC[-2]="clearing";1;2))
Macro;
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 And Target.Value = "clearing"
Then
Cells(Target.Row, 2) = Date
Else
If Target.Column = 3 And Target.Value = 2
Then
Cells(Target.Row, 4) = Date
End If
End If
End Sub
The problem is when C column is, with the help of formula, changed to 2 the macro does not automatically give me the date, but when I insert that manually it's working.
When you put values into the worksheet that is triggering the Worksheet_Change event macro, you should always turn off events or the macro will try to run on top of itself.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns(1)) Is Nothing Then
On Error GoTo Fìn
Application.EnableEvents = False
Dim rng As Range
For Each rng In Intersect(Target, Columns(1))
If LCase(rng.Value) = "clearing" Then
Cells(rng.Row, 2) = Now
Cells(rng.Row, 2).NumberFormat = "dd.mm.yyyy"
'Cells(rng.Row, 3).FormulaR1C1 = "maybe put the formula in here"
ElseIf rng.Offset(0, 2).Value = 2 Then
Cells(rng.Row, 4) = Now
Cells(rng.Row, 4).NumberFormat = "dd.mm.yyyy"
End If
Next rng
End If
Fìn:
Application.EnableEvents = True
End Sub
It sounds like you already have that formula in column C but I left a place where you can put it in once column A gets the clearing value. Another option would be to simply write a 1 into column C and the next time write a 2 in column C. That way you wouldn't have to deal with the formula at all.

Resources