【问题标题】:MS-Access Table Updates to NULL values when calling a Public Function in Update Query在更新查询中调用公共函数时 MS-Access 表更新为 NULL 值
【发布时间】:2016-05-09 04:36:35
【问题描述】:

对于初学者,我不是专业人士,但我有几年的 SSMS 和 MS-Access 数据库经验。

目的:在调用公共函数时通过更新查询更新MS-Access表中的字段

问题:在执行 MS-Access 查询时,该字段似乎更新为 NULL 值(这是通过首先使用文本字符串“testing”更新此字段来识别的;然后在执行查询后,现在导致 NULL 值它用来说“测试”的地方)。如果该字段已经为 NULL,然后我执行查询,则该值仍然为 NULL。执行查询后从 VBA 查看即时窗口时有结果。

更新字段中的一些预期结果:

0 年 0 个月 0 周 4 天 3 小时 11 分 8 秒

0 年 0 个月 -1 周 11 天 21 小时 3 分 29 秒

0 年 0 个月 -1 周 8 天 20 小时 51 分 42 秒

0 年 0 个月 -1 周 12 天 19 小时 43 分 17 秒

0 年 0 个月 0 周 0 天 0 小时 1 分 3 秒

0 年 0 个月 0 周 0 天 2 小时 30 分 55 秒

0 年 0 个月 0 周 0 天 2 小时 44 分 52 秒

0 年 0 个月 1 周 0 天 1 小时 18 分 23 秒

0 年 0 个月 0 周 9 天 19 小时 48 分 33 秒

0 年 0 个月 -1 周 11 天 21 小时 6 分 49 秒

正在使用来自公共函数的代码:

Public Function ElapsedTimeString(Interval As String, Date1 As Variant, Date2 As Variant, Optional ShowZero As Boolean = False) As Variant
'You must specify how you want the difference between two date/times to be calculated
'This is done by providing which string from ymwdhns (for years, months, weeks, days, hours, minutes and seconds)
'you want calculated.

'For example:
'Print Diff2Dates("y", #6/1/1998#, #6/26/2002#)
'4 years
'Print Diff2Dates("ymd", #6/1/1998#, #6/26/2002#)
'4 years 25 days
'Print Diff2Dates("ymd", #6/1/1998#, #6/26/2002#, True)
'4 years 0 months 25 days
'Print Diff2Dates("ymwd", #6/1/1998#, #6/26/2002#, True)
'4 years 0 months 3 weeks 4 days
'Print Diff2Dates("d", #6/1/1998#, #6/26/2002#)
'1486 days
'Print Diff2Dates("h", #1/25/2002 1:23:01 AM#, #1/26/2002 8:10:34 PM#)
'42 hours
'Print Diff2Dates("hns", #1/25/2002 1:23:01 AM#, #1/26/2002 8:10:34 PM#)
'42 hours 47 minutes 33 seconds
'Print Diff2Dates("dhns", #1/25/2002 1:23:01 AM#, #1/26/2002 8:10:34 PM#)
'1 day 18 hours 47 minutes 33 seconds
'Print Diff2Dates("ymd", #12/31/1999#, #1/1/2000#)
'1 Day
'Print Diff2Dates("ymd", #1/1/2000#, #12/31/1999#)
'-1 day
'Print Diff2Dates("ymd", #1/1/2000#, #1/2/2000#)
'1 Day
 'Description:   This function calculates the number of years,
'               months, days, hours, minutes and seconds between
'               two dates, as elapsed time.

'Inputs:    Interval:   Intervals to be displayed (a string)
'           Date1:      The lower date (see below)
'           Date2:      The higher date (see below)
'           ShowZero:   Boolean to select showing zero elements

'Outputs:   On error: Null
'           On no error: Variant containing the number of years,
'               months, days, hours, minutes & seconds between
'               the two dates, depending on the display interval
'               selected.
'           If Date1 is greater than Date2, the result will
'               be a negative value.
'           The function compensates for the lack of any intervals
'               not listed. For example, if Interval lists "m", but
'               not "y", the function adds the value of the year
'               component to the month component.
'           If ShowZero is True, and an output element is zero, it
'               is displayed. However, if ShowZero is False or
'               omitted, no zero-value elements are displayed.
'               For example, with ShowZero = False, Interval = "ym",
'               elements = 0 & 1 respectively, the output string
'               will be "1 month" - not "0 years 1 month".


On Error GoTo Err_Diff2Dates

Dim booCalcYears As Boolean
Dim booCalcMonths As Boolean
Dim booCalcDays As Boolean
Dim booCalcHours As Boolean
Dim booCalcMinutes As Boolean
Dim booCalcSeconds As Boolean
Dim booCalcWeeks As Boolean
Dim booSwapped As Boolean
Dim dtTemp As Date
Dim intCounter As Integer
Dim lngDiffYears As Long
Dim lngDiffMonths As Long
Dim lngDiffDays As Long
Dim lngDiffHours As Long
Dim lngDiffMinutes As Long
Dim lngDiffSeconds As Long
Dim lngDiffWeeks As Long
Dim varTemp As Variant
Dim Diff2Dates As Variant
Const INTERVALS As String = "ymwdhns"

'Check that Interval contains only valid characters
   Interval = LCase$(Interval)
   For intCounter = 1 To Len(Interval)
      If InStr(1, INTERVALS, Mid$(Interval, intCounter, 1)) = 0 Then
         Exit Function
      End If
   Next intCounter

'Check that valid dates have been entered
   If IsNull(Date1) Then Exit Function
   If IsNull(Date2) Then Exit Function
   If Not (IsDate(Date1)) Then Exit Function
   If Not (IsDate(Date2)) Then Exit Function

'If necessary, swap the dates, to ensure that
'Date1 is lower than Date2
'   If Date1 > Date2 Then
'      dtTemp = Date1
'      Date1 = Date2
'      Date2 = dtTemp
'      booSwapped = True
'   End If

   Diff2Dates = Null
   varTemp = Null

'What intervals are supplied
   booCalcYears = (InStr(1, Interval, "y") > 0)
   booCalcMonths = (InStr(1, Interval, "m") > 0)
   booCalcDays = (InStr(1, Interval, "d") > 0)
   booCalcHours = (InStr(1, Interval, "h") > 0)
   booCalcMinutes = (InStr(1, Interval, "n") > 0)
   booCalcSeconds = (InStr(1, Interval, "s") > 0)
   booCalcWeeks = (InStr(1, Interval, "w") > 0)


'Get the cumulative differences
   If booCalcYears Then
      lngDiffYears = Abs(DateDiff("yyyy", Date1, Date2)) - _
              IIf(Format$(Date1, "mmddhhnnss") <= Format$(Date2, "mmddhhnnss"), 0, 1)
      Date1 = DateAdd("yyyy", lngDiffYears, Date1)
   End If

   If booCalcMonths Then
      lngDiffMonths = Abs(DateDiff("m", Date1, Date2)) - _
              IIf(Format$(Date1, "ddhhnnss") <= Format$(Date2, "ddhhnnss"), 0, 1)
      Date1 = DateAdd("m", lngDiffMonths, Date1)
   End If

   If booCalcWeeks Then
      lngDiffWeeks = Abs(DateDiff("w", Date1, Date2)) - _
              IIf(Format$(Date1, "hhnnss") <= Format$(Date2, "hhnnss"), 0, 1)
      Date1 = DateAdd("ww", lngDiffWeeks, Date1)
   End If

   If booCalcDays Then
      lngDiffDays = Abs(DateDiff("d", Date1, Date2)) - _
              IIf(Format$(Date1, "hhnnss") <= Format$(Date2, "hhnnss"), 0, 1)
      Date1 = DateAdd("d", lngDiffDays, Date1)
   End If

   If booCalcHours Then
      lngDiffHours = Abs(DateDiff("h", Date1, Date2)) - _
              IIf(Format$(Date1, "nnss") <= Format$(Date2, "nnss"), 0, 1)
      Date1 = DateAdd("h", lngDiffHours, Date1)
   End If

   If booCalcMinutes Then
      lngDiffMinutes = Abs(DateDiff("n", Date1, Date2)) - _
              IIf(Format$(Date1, "ss") <= Format$(Date2, "ss"), 0, 1)
      Date1 = DateAdd("n", lngDiffMinutes, Date1)
   End If

   If booCalcSeconds Then
      lngDiffSeconds = Abs(DateDiff("s", Date1, Date2))
      Date1 = DateAdd("s", lngDiffSeconds, Date1)
   End If

   If booCalcYears And (lngDiffYears > 0 Or ShowZero) Then
      varTemp = lngDiffYears & IIf(lngDiffYears <> 1, " years", " year")
   End If

   If booCalcMonths And (lngDiffMonths > 0 Or ShowZero) Then
      If booCalcMonths Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffMonths & IIf(lngDiffMonths <> 1, " months", " month")
      End If
   End If

   If booCalcWeeks And (lngDiffWeeks > 0 Or ShowZero) Then
      If booCalcWeeks Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffWeeks & IIf(lngDiffWeeks <> 1, " weeks", " week")
      End If
   End If

   If booCalcDays And (lngDiffDays > 0 Or ShowZero) Then
      If booCalcDays Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffDays & IIf(lngDiffDays <> 1, " days", " day")
      End If
   End If

   If booCalcHours And (lngDiffHours > 0 Or ShowZero) Then
      If booCalcHours Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffHours & IIf(lngDiffHours <> 1, " hours", " hour")
      End If
   End If

   If booCalcMinutes And (lngDiffMinutes > 0 Or ShowZero) Then
      If booCalcMinutes Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffMinutes & IIf(lngDiffMinutes <> 1, " minutes", " minute")
      End If
   End If

   If booCalcSeconds And (lngDiffSeconds > 0 Or ShowZero) Then
      If booCalcSeconds Then
         varTemp = varTemp & IIf(IsNull(varTemp), Null, " ") & _
                   lngDiffSeconds & IIf(lngDiffSeconds <> 1, " seconds", " second")
      End If
   End If

'   If booSwapped Then
'      varTemp = "-" & varTemp
'   End If

   Diff2Dates = Trim$(varTemp)
Debug.Print varTemp

End_Diff2Dates:
   Exit Function

Err_Diff2Dates:
   Resume End_Diff2Dates

End Function

来自 MS-Access 更新查询的粘糊糊:

'****************** 代码开始 *****************

UPDATE SupplyToMakeFinal SET SupplyToMakeFinal.TimeToMakeDaysHoursMinutesSeconds = ElapsedTimeString("ymwdhns",[SupplyLatestEndDate],[MakeLatestEndDate],True);

'****************** 代码结束 *******************

我尝试过数据类型 Text 和 Memo,它们的结果相同。

对于此事的任何帮助将不胜感激,因为我花费了无数小时研究和尝试所有我能想到的都无济于事。

如果我的帖子没有包含您提供帮助所需的所有内容,我深表歉意;如果您需要我的其他任何东西,请告诉我。

【问题讨论】:

  • 确保Option Explicit 位于包含您的函数的模块顶部。 (我认为你有一个命名问题,但在我的手机上遵循代码有点困难)。

标签: vba ms-access


【解决方案1】:

您不能这样计算月份,因为一个月可以有 28 到 31 天,年份也不能有 365 或 366 天。这就是您看到负数的原因。

所以使用下面这样的函数来计算月份。由此您可以计算年数(= Int(months / 12))。将月份添加到开始日期,您可以计算从该日期到结束日期的天数。几周只有 7 天。

Public Function Months( _
  ByVal datDate1 As Date, _
  ByVal datDate2 As Date, _
  Optional ByVal booLinear As Boolean) _
  As Integer

' Returns the difference in full months between datDate1 and datDate2.
'
' Calculates correctly for:
'   negative differences
'   leap years
'   dates of 29. February
'   date/time values with embedded time values
'   negative date/time values (prior to 1899-12-29)
'
' Optionally returns negative counts rounded down to provide a
' linear sequence of month counts.
' For a given datDate1, if datDate2 is decreased stepwise one month from
' returning a positive count to returning a negative count, one or two
' occurrences of count zero will be returned.
' If booLinear is False, the sequence will be:
'   3, 2, 1, 0,  0, -1, -2
' If booLinear is True, the sequence will be:
'   3, 2, 1, 0, -1, -2, -3
'
' If booLinear is False, reversing datDate1 and datDate2 will return
' results of same absolute Value, only the sign will change.
' This behaviour mimics that of Fix().
' If booLinear is True, reversing datDate1 and datDate2 will return
' results where the negative count is offset by -1.
' This behaviour mimics that of Int().

' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of months to dates of Feb. 29.
' when the resulting year is a common year.
'
' 2010-03-30. Cactus Data ApS, CPH.

  Dim intDiff   As Integer
  Dim intSign   As Integer
  Dim intMonths As Integer

  ' Find difference in calendar months.
  intMonths = DateDiff("m", datDate1, datDate2)
  ' For positive resp. negative intervals, check if the second date
  ' falls before, on, or after the crossing date for a 1 month period
  ' while at the same time correcting for February 29. of leap years.
  If DateDiff("d", datDate1, datDate2) > 0 Then
    intSign = Sgn(DateDiff("d", DateAdd("m", intMonths, datDate1), datDate2))
    intDiff = Abs(intSign < 0)
  Else
    intSign = Sgn(DateDiff("d", DateAdd("m", -intMonths, datDate2), datDate1))
    If intSign <> 0 Then
      ' Offset negative count of months to continuous sequence if requested.
      intDiff = Abs(booLinear)
    End If
    intDiff = intDiff - Abs(intSign < 0)
  End If

  ' Return count of months as count of full 1 month periods.
  Months = intMonths - intDiff

End Function

也就是说,以这种方式将月份和日期与一秒的分辨率混合在一起计算仍然没有多大意义。您可以获得的最接近真实计数的是 days-hours-minutes-seconds(-milliseconds)

【讨论】:

  • 感谢您的评论,但代码似乎工作正常...负数是由于 date1 在 date2 之前造成的,因此负数...即Date1 = #11/25/2015 2:08:34 PM# 和 Date2 = #11/25/2015 2:00:48 PM# 导致负值 = -1 年 11 个月 3 周 9 天 23 小时 52分 14 秒。我已经对 19,978 date1 和 date2 评估进行了测试,但没有发现任何问题。请提供您所指问题的示例,因为这可以帮助我理解您所指出的内容。再次感谢!
  • 我指出“0 年 0 个月 -1 周 11 天 21 小时 6 分 49 秒”这样的结果没有意义。
【解决方案2】:

您的函数原则上可以工作,但您似乎重命名了它,但忘记将返回值实际设置为新的函数名称。

你计算

Diff2Dates = Trim$(varTemp)
Debug.Print varTemp
' The End

但是Diff2Dates只是一个局部变量,你的函数是

Public Function ElapsedTimeString

ElapsedTimeString 永远不会被赋值,因此该函数将始终返回 NULL。

要么还原名称更改,要么在末尾添加:

ElapsedTimeString = Diff2Dates 

【讨论】:

  • 安德烈,谢谢,谢谢,谢谢...技术...去图...我不敢相信我错过了这个......它现在按预期工作......再次,感谢您的关注....
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多