Reputation: 962
How can I make a formula such that when update a value in Completed
for a particular value of ID
, it automatically gets filled in all cells of Completed
for that particular ID
? And, when I remove the value from one cell in Completed
, it automatically gets removed from all cells in Completed
that correspond to that value in ID
.
For eg. in the data below, I'd like the three blank cells automatically filled with 4
, 6
and 5
respectively.
Role ID Completed
A 1 3
A 2 4
A 5 3
A 8 6
B 2
B 8
B 10 5
C 10
C 15 2
Upvotes: 1
Views: 2251
Reputation: 54807
What does it do?
Target Column
is changed to a new value, the value in
the same row of Source Column
is being looked up in the same Source Column
.
With each found value, the value in this (found) row in
Target Column
is changed to the mentioned new value.Usage
1. Sheet Module
The following code is to be copied into a sheet module e.g. Sheet1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
updateColumn Me, Target, "B", "C", 2
End Sub
"B"
and "C"
you can use the numbers 2
and 3
.SourceColumn
, TargetColumn
and FirstRow
.Me
and Target
stay the same.2. Standard Module
The following code is to be copied into a standard module e.g. Module1
Option Explicit
Sub updateColumn(Sheet As Worksheet, _
TargetCell As Range, _
ByVal SourceColumn As Variant, _
ByVal TargetColumn As Variant, _
Optional ByVal FirstRow As Long = 4)
If TargetCell.Cells.CountLarge > 1 Then GoTo MoreThanOneCell
Dim rng As Range: Set rng = Sheet.Columns(TargetColumn)
If Intersect(TargetCell, rng) Is Nothing Then GoTo NotInTargetColumn
Set rng = rng.Find("*", , xlValues, , , xlPrevious)
If rng Is Nothing Then GoTo EmptyTargetColumn
If rng.Row < FirstRow Then GoTo FirstRowBelowLastRow
Dim LastRow As Long: LastRow = rng.Row
Set rng = Sheet.Columns(SourceColumn).Find("*", , xlValues, , , xlPrevious)
If Not rng Is Nothing Then
If rng.Row > LastRow Then LastRow = rng.Row
Else ' Empty Source Column. Don't care.
End If
If FirstRow = LastRow Then GoTo OnlyOneCell
Set rng = Sheet.Range(Sheet.Cells(FirstRow, TargetColumn), _
Sheet.Cells(LastRow, TargetColumn))
If Intersect(TargetCell, rng) Is Nothing Then GoTo NotInTargetRange
Dim ColOff As Long: ColOff = Sheet.Columns(SourceColumn).Column - rng.Column
Dim Target As Variant: Target = rng.Value
Dim Source As Variant: Source = rng.Offset(, ColOff).Value
Dim i As Long, tVal As Variant, sVal As Variant
tVal = TargetCell.Value
sVal = TargetCell.Offset(, ColOff).Value
Debug.Print TargetCell.Address, tVal, _
TargetCell.Offset(, ColOff).Address, sVal
On Error GoTo CleanExit
For i = 1 To UBound(Source)
If Source(i, 1) = sVal Then
Target(i, 1) = tVal
End If
Next i
'Application.EnableEvents = False
rng.Value = Target
CleanExit:
' Application.EnableEvents = True
LastExit:
Exit Sub
MoreThanOneCell:
'Debug.Print "More than one cell."
GoTo LastExit
NotInTargetColumn:
'Debug.Print "Not in Target Column."
GoTo LastExit
EmptyTargetColumn:
'Debug.Print "Empty Target Column."
GoTo LastExit
FirstRowBelowLastRow:
'Debug.Print "First row below last row."
GoTo LastExit
OnlyOneCell:
'Debug.Print "Only one cell."
GoTo LastExit
NotInTargetRange:
'Debug.Print "Not in Target Range."
GoTo LastExit
End Sub
You can uncomment the Debug.Print
lines to monitor the behavior of the Change event
in the Immediate window
(CTRL + G) in VBE
(Alt+F11).
Upvotes: 1
Reputation: 5902
Here is one approach.
Your setup is in column A, B & C
Prepare a LOOKUP table in column E & F as shown below.
ID Completed
1 3
2 4
5 3
8 6
10 5
15 2
Then in column C (cell C2), you can use a simple formula like below and copy down as much needed.
=IFERROR(VLOOKUP(B2,$E:$F,2,0),"")
So, as soon as you update status in column E & F, it will get updated in the formula column.
Upvotes: 1