忽略或避免 UDF 中的循环引用?
Ignore, or avoid circular reference in UDF?
我正在尝试做一个计划表。我有一个 table,我想成为这样的东西:
ID
Parent ID
Start Date
Duration
End Date
1
01/01/2021
10
11/01/2021
2
1
06/05/2021
2
08/05/2021
3
2
08/05/2021
1
09/05/2021
4
3
09/05/2021
5
14/05/2021
5
2,3,4
14/05/2021
4
18/05/2021
开始日期将基于父 ID 与任务 ID 的匹配,因此任务 2 在任务 1 之后,任务 2 在任务 3 之后等等。我还希望能够针对可能发生的多个任务进行测试同时,因此任务 5 可以在任务 2、3 或 4 之后开始,最后结束。
我为计算开始日期写了这个 UDF。
Option Explicit
Function LastPredecessor(PreList As String, TaskList As Range, TaskDueDate As Range)
Dim ID
Dim Dates
Dim nPres, i As Integer
On Error Resume Next
Pres = Split(PreList, ",")
nPres = UBound(Pres)
ReDim Dates(0 To nPres, 0)
For i = 0 To nPres
Dates(i, 0) = IDX_Match(CInt(Pres(i)), TaskList, TaskDueDate)
Next
LastPredecessor = WorksheetFunction.Max(Dates)
End Function
Function IDX_Match(LookupVal, MatchRange As Range, LookupRange As Range, Optional MatchType As Integer = 0)
IDX_Match = WorksheetFunction.Index(LookupRange.Value2, WorksheetFunction.Match(LookupVal, MatchRange.Value2, MatchType))
End Function
函数在table的开始日期被调用,像这样
=LastPredecessor([@Parent ID],[ID],[结束日期])
如果结束日期与开始日期无关,则效果很好,但一旦我尝试更新结束日期,并添加开始日期 + 持续时间作为结束日期的计算,它就会生成循环错误。
我确定我做错了一些非常简单的错误,但如果知道我需要做些什么来解决这个问题,我会很高兴。
编辑:
感谢@Toddleson,以下是稍作修改的版本
Function LastPredecessor(PreList As String, EndDates As Range, IDColumn As Range) As Date
Dim Preds() As String, PredDates() As Long
Preds = Split(PreList, ",")
ReDim PredDates(UBound(Preds))
For i = LBound(Preds) To UBound(Preds)
PredDates(i) = IDColumn(WorksheetFunction.Match(CInt(Preds(i)), IDColumn, 0)).Offset(0, EndDates.Column - IDColumn.Column).Value2
Next i
LastPredecessor = Application.WorksheetFunction.Max(PredDates)
End Function
好的,我重写了函数。它应该完全按照你向我描述的那样做。
Function LastPredecessorV2(PreList As String, EndDates As Range, IDColumn As Range) As Date
Dim Preds() As String, PredDates() As Long
Preds = Split(Replace(PreList, " ", ""), ",")
ReDim PredDates(UBound(Preds))
For i = LBound(Preds) To UBound(Preds)
PredDates(i) = IDColumn.Find( _
What:=CInt(Preds(i)), _
LookAt:=xlWhole _
).Offset(0, EndDates.Column - IDColumn.Column).Value2 'Corrected
Next i
LastPredecessorV2 = CDate(Application.WorksheetFunction.Max(PredDates))
End Function
下面是参数输入的样子。这些范围可以是整个列,它仍然有效。
所有结束日期都使用公式(开始日期 + 以天为单位的持续时间)。第一个任务开始日期是该列中唯一的独立值,所有其他都使用公式。
编辑:
我应该提一下,您可以在范围之间插入列,该功能仍然有效。
我正在尝试做一个计划表。我有一个 table,我想成为这样的东西:
ID | Parent ID | Start Date | Duration | End Date |
---|---|---|---|---|
1 | 01/01/2021 | 10 | 11/01/2021 | |
2 | 1 | 06/05/2021 | 2 | 08/05/2021 |
3 | 2 | 08/05/2021 | 1 | 09/05/2021 |
4 | 3 | 09/05/2021 | 5 | 14/05/2021 |
5 | 2,3,4 | 14/05/2021 | 4 | 18/05/2021 |
开始日期将基于父 ID 与任务 ID 的匹配,因此任务 2 在任务 1 之后,任务 2 在任务 3 之后等等。我还希望能够针对可能发生的多个任务进行测试同时,因此任务 5 可以在任务 2、3 或 4 之后开始,最后结束。
我为计算开始日期写了这个 UDF。
Option Explicit
Function LastPredecessor(PreList As String, TaskList As Range, TaskDueDate As Range)
Dim ID
Dim Dates
Dim nPres, i As Integer
On Error Resume Next
Pres = Split(PreList, ",")
nPres = UBound(Pres)
ReDim Dates(0 To nPres, 0)
For i = 0 To nPres
Dates(i, 0) = IDX_Match(CInt(Pres(i)), TaskList, TaskDueDate)
Next
LastPredecessor = WorksheetFunction.Max(Dates)
End Function
Function IDX_Match(LookupVal, MatchRange As Range, LookupRange As Range, Optional MatchType As Integer = 0)
IDX_Match = WorksheetFunction.Index(LookupRange.Value2, WorksheetFunction.Match(LookupVal, MatchRange.Value2, MatchType))
End Function
函数在table的开始日期被调用,像这样
=LastPredecessor([@Parent ID],[ID],[结束日期])
如果结束日期与开始日期无关,则效果很好,但一旦我尝试更新结束日期,并添加开始日期 + 持续时间作为结束日期的计算,它就会生成循环错误。
我确定我做错了一些非常简单的错误,但如果知道我需要做些什么来解决这个问题,我会很高兴。
编辑:
感谢@Toddleson,以下是稍作修改的版本
Function LastPredecessor(PreList As String, EndDates As Range, IDColumn As Range) As Date
Dim Preds() As String, PredDates() As Long
Preds = Split(PreList, ",")
ReDim PredDates(UBound(Preds))
For i = LBound(Preds) To UBound(Preds)
PredDates(i) = IDColumn(WorksheetFunction.Match(CInt(Preds(i)), IDColumn, 0)).Offset(0, EndDates.Column - IDColumn.Column).Value2
Next i
LastPredecessor = Application.WorksheetFunction.Max(PredDates)
End Function
好的,我重写了函数。它应该完全按照你向我描述的那样做。
Function LastPredecessorV2(PreList As String, EndDates As Range, IDColumn As Range) As Date
Dim Preds() As String, PredDates() As Long
Preds = Split(Replace(PreList, " ", ""), ",")
ReDim PredDates(UBound(Preds))
For i = LBound(Preds) To UBound(Preds)
PredDates(i) = IDColumn.Find( _
What:=CInt(Preds(i)), _
LookAt:=xlWhole _
).Offset(0, EndDates.Column - IDColumn.Column).Value2 'Corrected
Next i
LastPredecessorV2 = CDate(Application.WorksheetFunction.Max(PredDates))
End Function
下面是参数输入的样子。这些范围可以是整个列,它仍然有效。
所有结束日期都使用公式(开始日期 + 以天为单位的持续时间)。第一个任务开始日期是该列中唯一的独立值,所有其他都使用公式。
编辑: 我应该提一下,您可以在范围之间插入列,该功能仍然有效。