如何在 MS Access 报表上使用 VBA 对计算字段求和
How to Sum Calculated Fields with VBA on MS Access Report
我希望有人能在这里为我指出正确的方向,并希望我能解释清楚。我的报告得到了不理想的结果,因为我需要对计算字段求和。员工 ID header 中的员工姓名、周 header 中的标签以及详细信息 header 中的日期和计算小时数均正确显示。但是,Access 以错误的顺序填写信息。
这是它正在做的事情:
正在计算并填写期间最后一周最后一天的小时数 ->
填写期间最后一周的小时数 ->
填写期间的小时数 ->
计算并填写期间前一周的最后一天->
填写期间前一周的小时数 ->
重复到第一周。
然后填写剩余的计算时间。
所以我的结果显示如下:(请注意四舍五入是有意的,这也是我不能在页脚中只做 =Sum([Hours]) 的原因)
Employee Name
Date Hours Reg OT
9/8/15 8:00
9/9/15 8:28
9/10/15 8:00
9/11/15 7:32 <--Inputs this fourth
------------------------------
Week Totals: 7:30 7:30 0:00 <--Inputs this fifth then fills in other dates
Date Hours Reg OT
9/14/15 9:43
9/15/15 8:00
9/16/15 13:14
9/17/15 11:39
9/18/15 5:25 <--Starts here first
------------------------------
Week Totals: 5:30 5:30 0:00 <--Inputs this second
------------------------------
Period Totals: 5:30 5:30 0:00 <--Inputs this third
这是我现在设置报告的方式:
Employee Name (Employee ID Header)
Date Hours Regular Overtime (Week Header)
=[Date] =CalcHours([Hours]) (Details)
=GetWeekTot() =GetWeekReg() =GetWeekOT() (Week Footer)
=GetPeriodTot() =GetPeriodReg() =GetPeriodOT() (Employee ID Footer)
这是我的模块:
Option Compare Database
Option Explicit
Private WeekTot As Double
Private WeekReg As Double
Private WeekOT As Double
Private PeriodTot As Double
Private PeriodReg As Double
Private PeriodOT As Double
Public Function CalcHours(ByVal Hours As Double) As String
'Add the Daily Hours to the Total Weekly Hours
WeekTot = WeekTot + Hours
'Format and Return the Daily Hours
CalcHours = Int(Hours) & ":" & Format((Hours * 60) Mod 60, "00")
End Function
Public Function GetWeekTot() As String
'Round the Total Weekly Hours to the Nearest Quarter Hour
WeekTot = Round(WeekTot * 4, 0) / 4
'Calculate the Regular Weekly Hours and the Overtime Weekly Hours
If WeekTot > 40 Then
WeekReg = 40
WeekOT = WeekTot - 40
Else
WeekReg = WeekTot
WeekOT = 0
End If
'Add the Total Weekly Hours to the Total Period Hours
PeriodTot = PeriodTot + WeekTot
'Format and Return the Total Weekly Hours
GetWeekTot = Int(WeekTot) & ":" & Format(WeekTot * 60 Mod 60, "00")
'Reset the Total Weekly Hours
WeekTot = 0
End Function
Public Function GetWeekReg() As String
'Add the Regular Weekly Hours to the Regular Period Hours
PeriodReg = PeriodReg + WeekReg
'Format and Return the Regular Weekly Hours
GetWeekReg = Int(WeekReg) & ":" & Format(WeekReg * 60 Mod 60, "00")
'Reset the Regular Weekly Hours
WeekReg = 0
End Function
Public Function GetWeekOT() As String
'Add the Overtime Weekly Hours to the Overtime Period Hours
PeriodOT = PeriodOT + WeekOT
'Format and Return the Overtime Weekly Hours
GetWeekOT = Int(WeekOT) & ":" & Format(WeekOT * 60 Mod 60, "00")
'Reset the Overtime Weekly Hours
WeekOT = 0
End Function
Public Function GetPeriodTot() As String
'Format and Return Total Period Hours
GetPeriodTot = Int(PeriodTot) & ":" & Format((PeriodTot * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodTot = 0
End Function
Public Function GetPeriodReg() As String
'Format and Return Total Period Hours
GetPeriodReg = Int(PeriodReg) & ":" & Format((PeriodReg * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodReg = 0
End Function
Public Function GetPeriodOT() As String
'Format and Return Total Period Hours
GetPeriodOT = Int(PeriodOT) & ":" & Format((PeriodOT * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodOT = 0
End Function
如果有人能想出办法让它显示这一点,我将不胜感激:
Employee Name
Date Hours Reg OT
9/8/15 8:00
9/9/15 8:28
9/10/15 8:00
9/11/15 7:32
------------------------------
Week Totals: 32:00 32:00 0:00
Date Hours Reg OT
9/14/15 9:43
9/15/15 8:00
9/16/15 13:14
9/17/15 11:39
9/18/15 5:25
------------------------------
Week Totals: 48:00 40:00 8:00
------------------------------
Period Totals: 80:00 72:00 8:00
既然您透露这些函数是在报表的文本框中调用的,那么可以说您永远无法确定 Access 在初始化报表时以什么顺序调用它们。
我提出另外两种可能性:
1.使用带有额外字段的表达式
在您的报告详细信息行中设置一个真实的每日小时字段,将其命名为例如DAILY_CORRECT_FIELD,将 visible 设置为 false 将其隐藏。插入另一个文本字段,将其命名为例如DAILY_ROUNDED_FIELD,在其中插入舍入到四分之一的表达式。在周的总和字段上,引用 sum(DAILY_CORRECT_FIELD),具有未舍入值的不可见字段。
2。基于代码
如果您想使用 VBA,请不要编写对所有字段求和的模块,尤其是当您无法控制调用函数的顺序时。改为编写一个查询,您可以在其中总结一周并将其设置为报告中的字段。网上有很多教程,我就不多说了。
虽然我非常喜欢使用 VBA,但我还是强烈推荐建议 1,因为它的实现很简单。
我想到了一个解决方案,@asdev,你让我考虑再次使用访问表达式,但这次我添加了一种旁路聚合查询,以按员工和周分组,然后四舍五入总和在那个查询中给我的总数与我在报告的周页脚中得到的总数相同。然后,我使用 DSum 函数按员工 ID 过滤旁路查询,并在我的 Period 页脚中对总计求和,得到正确的总计。
我希望有人能在这里为我指出正确的方向,并希望我能解释清楚。我的报告得到了不理想的结果,因为我需要对计算字段求和。员工 ID header 中的员工姓名、周 header 中的标签以及详细信息 header 中的日期和计算小时数均正确显示。但是,Access 以错误的顺序填写信息。
这是它正在做的事情:
正在计算并填写期间最后一周最后一天的小时数 ->
填写期间最后一周的小时数 ->
填写期间的小时数 ->
计算并填写期间前一周的最后一天->
填写期间前一周的小时数 ->
重复到第一周。
然后填写剩余的计算时间。
所以我的结果显示如下:(请注意四舍五入是有意的,这也是我不能在页脚中只做 =Sum([Hours]) 的原因)
Employee Name
Date Hours Reg OT
9/8/15 8:00
9/9/15 8:28
9/10/15 8:00
9/11/15 7:32 <--Inputs this fourth
------------------------------
Week Totals: 7:30 7:30 0:00 <--Inputs this fifth then fills in other dates
Date Hours Reg OT
9/14/15 9:43
9/15/15 8:00
9/16/15 13:14
9/17/15 11:39
9/18/15 5:25 <--Starts here first
------------------------------
Week Totals: 5:30 5:30 0:00 <--Inputs this second
------------------------------
Period Totals: 5:30 5:30 0:00 <--Inputs this third
这是我现在设置报告的方式:
Employee Name (Employee ID Header)
Date Hours Regular Overtime (Week Header)
=[Date] =CalcHours([Hours]) (Details)
=GetWeekTot() =GetWeekReg() =GetWeekOT() (Week Footer)
=GetPeriodTot() =GetPeriodReg() =GetPeriodOT() (Employee ID Footer)
这是我的模块:
Option Compare Database
Option Explicit
Private WeekTot As Double
Private WeekReg As Double
Private WeekOT As Double
Private PeriodTot As Double
Private PeriodReg As Double
Private PeriodOT As Double
Public Function CalcHours(ByVal Hours As Double) As String
'Add the Daily Hours to the Total Weekly Hours
WeekTot = WeekTot + Hours
'Format and Return the Daily Hours
CalcHours = Int(Hours) & ":" & Format((Hours * 60) Mod 60, "00")
End Function
Public Function GetWeekTot() As String
'Round the Total Weekly Hours to the Nearest Quarter Hour
WeekTot = Round(WeekTot * 4, 0) / 4
'Calculate the Regular Weekly Hours and the Overtime Weekly Hours
If WeekTot > 40 Then
WeekReg = 40
WeekOT = WeekTot - 40
Else
WeekReg = WeekTot
WeekOT = 0
End If
'Add the Total Weekly Hours to the Total Period Hours
PeriodTot = PeriodTot + WeekTot
'Format and Return the Total Weekly Hours
GetWeekTot = Int(WeekTot) & ":" & Format(WeekTot * 60 Mod 60, "00")
'Reset the Total Weekly Hours
WeekTot = 0
End Function
Public Function GetWeekReg() As String
'Add the Regular Weekly Hours to the Regular Period Hours
PeriodReg = PeriodReg + WeekReg
'Format and Return the Regular Weekly Hours
GetWeekReg = Int(WeekReg) & ":" & Format(WeekReg * 60 Mod 60, "00")
'Reset the Regular Weekly Hours
WeekReg = 0
End Function
Public Function GetWeekOT() As String
'Add the Overtime Weekly Hours to the Overtime Period Hours
PeriodOT = PeriodOT + WeekOT
'Format and Return the Overtime Weekly Hours
GetWeekOT = Int(WeekOT) & ":" & Format(WeekOT * 60 Mod 60, "00")
'Reset the Overtime Weekly Hours
WeekOT = 0
End Function
Public Function GetPeriodTot() As String
'Format and Return Total Period Hours
GetPeriodTot = Int(PeriodTot) & ":" & Format((PeriodTot * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodTot = 0
End Function
Public Function GetPeriodReg() As String
'Format and Return Total Period Hours
GetPeriodReg = Int(PeriodReg) & ":" & Format((PeriodReg * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodReg = 0
End Function
Public Function GetPeriodOT() As String
'Format and Return Total Period Hours
GetPeriodOT = Int(PeriodOT) & ":" & Format((PeriodOT * 60) Mod 60, "00")
'Reset the Total Period Hours
PeriodOT = 0
End Function
如果有人能想出办法让它显示这一点,我将不胜感激:
Employee Name
Date Hours Reg OT
9/8/15 8:00
9/9/15 8:28
9/10/15 8:00
9/11/15 7:32
------------------------------
Week Totals: 32:00 32:00 0:00
Date Hours Reg OT
9/14/15 9:43
9/15/15 8:00
9/16/15 13:14
9/17/15 11:39
9/18/15 5:25
------------------------------
Week Totals: 48:00 40:00 8:00
------------------------------
Period Totals: 80:00 72:00 8:00
既然您透露这些函数是在报表的文本框中调用的,那么可以说您永远无法确定 Access 在初始化报表时以什么顺序调用它们。
我提出另外两种可能性:
1.使用带有额外字段的表达式
在您的报告详细信息行中设置一个真实的每日小时字段,将其命名为例如DAILY_CORRECT_FIELD,将 visible 设置为 false 将其隐藏。插入另一个文本字段,将其命名为例如DAILY_ROUNDED_FIELD,在其中插入舍入到四分之一的表达式。在周的总和字段上,引用 sum(DAILY_CORRECT_FIELD),具有未舍入值的不可见字段。
2。基于代码
如果您想使用 VBA,请不要编写对所有字段求和的模块,尤其是当您无法控制调用函数的顺序时。改为编写一个查询,您可以在其中总结一周并将其设置为报告中的字段。网上有很多教程,我就不多说了。
虽然我非常喜欢使用 VBA,但我还是强烈推荐建议 1,因为它的实现很简单。
我想到了一个解决方案,@asdev,你让我考虑再次使用访问表达式,但这次我添加了一种旁路聚合查询,以按员工和周分组,然后四舍五入总和在那个查询中给我的总数与我在报告的周页脚中得到的总数相同。然后,我使用 DSum 函数按员工 ID 过滤旁路查询,并在我的 Period 页脚中对总计求和,得到正确的总计。