MS Access:SQL 的日期格式使用 VBA 插入

MS Access: Date format for SQL Insert using VBA

这可能是一个非常简单的问题,但到目前为止,我很难理解我在网上找到的信息。当我尝试从我的 VBA 中 运行 SQl 时,它给我的 strSQl.

类型不匹配

我有一个 table [tbl_DatabaseUpdateLog] 有 4 列

UpdateID (Autonumber)

Start (Date/Time)

End (Date/Time)

Duration (Date/Time)

我必须定期从公司数据库中提取信息以用于较小的分析项目,并且我想记录 运行 这些查询所需的频率和时间。每次开始更新时,它 运行 如下:

Dim StartUpdate, EndUpdate, LengthUpdate, strSQl As Date
StartUpdate = Time()
    
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem

EndUpdate = Time()
LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "HH:MM:SS") & ")"

    DoCmd.SetWarnings (0)
    strSQl = "INSERT INTO tbl_DatabaseUpdateLog ( Start, [End], Duration ) " & _
            "SELECT '" & StartUpdate & "' AS Started, '" & EndUpdate & "' AS Ended, '" & LengthUpdate & "' AS Lasted"
    DoCmd.RunSQL strSQl
    DoCmd.SetWarnings (-1)
    
DoCmd.Close acForm, Me.Name

我试过在日期前后使用#,并使用 Now() 而不是 Time(),但我觉得我缺少一个基本概念来帮助我解决问题。如果有帮助,我只需要一天中的时间和持续时间(与其说是日期本身)。

我看到您在使用 INSERT INTO SELECT FROM (literal),而直接的 INSERT INTO (columns) VALUES (values) 会更简单。您还可以在单​​个 INSERT 语句中包含多个 VALUES 子语句,这很简洁。

我还看到您正在存储非规范化数据,很明显 Duration 可以从 End - Start 派生,因此您可能想要删除该列。

另外,避免使用匈牙利语表示法,在这种情况下,table 的名字前面加上 tbl_。现在已经不是 1980 年代了。别这样。

使用字符串连接的糟糕而简单的答案:

(永远不要这样做)

SQL 服务器

如果您使用 SQL 服务器,您需要将日期用单引号括起来,并且需要转换为明确的日期格式字符串,例如 yyyy-MM-dd HH:mm:ss.

strSQL = "INSERT INTO neverDoThis VALUES ( '" & Format( startUpdate, "yyyy-MM-dd HH:mm:ss" & "' )"

访问/喷射

如果您使用的是 Access 或 Jet,则需要将日期包含在哈希字符“#”中并使用 'MM/dd/yyyy hh:mm:ss tt' 格式(愚蠢的美国人...)。

strSQL = "INSERT INTO neverDoThis VALUES ( #" & Format( startUpdate, "MM/dd/yyyy hh:mm:ss tt" & "# )"

这里是 Format 函数的参考:https://msdn.microsoft.com/en-us/library/office/gg251755.aspx?f=255&MSPPError=-2147217396

更好的答案:使用参数

(改为这样做)

SQL 服务器

SQL 服务器使用命名参数,如 @foo:

cmd.CommandText = "INSERT INTO databaseUpdateLog ( [Start], [End], [Duration] ) VALUES ( @start, @end, @duration )"
cmd.Parameters.Append cmd.CreateParameter( "@start", , , startUpdate )
cmd.Parameters.Append cmd.CreateParameter( "@end", , , endUpdate )
cmd.Parameters.Append cmd.CreateParameter( "@duration", , , lengthUpdate )

访问/喷射

Access 使用按添加顺序访问的匿名占位符,使用 `?':

cmd.CommandText = "INSERT INTO databaseUpdateLog ( [Start], [End], [Duration] ) VALUES ( ?, ?, ? )"
cmd.Parameters.Append cmd.CreateParameter( "?", , , startUpdate )
cmd.Parameters.Append cmd.CreateParameter( "?", , , endUpdate )
cmd.Parameters.Append cmd.CreateParameter( "?", , , lengthUpdate )

VBA中的Append方法是Sub所以调用它不使用括号。
CreateParameter 方法在中间有 3 个可选参数:TypeDirectionSize 可以从值中推断出来,因此将它们省略 , , ,.

要计算一天中的时间 ,在 VBA 中,您可以使用此表达式:

CDate(Now - Date())

将结果括在 # 中,因为结果仍然是 Date 类型,即使只存储了时间信息。

您可以使用DateDiff函数来计算持续时间,您需要选择合适的单位。例如:

DateDiff(DateInterval.Second, EndUpdate, StartUpdate)

结果是一个长整数,因此您无需将结果包含在 SQL 中。

顺便说一句,建议对 SQL 进行参数化,但不是必需的。

When I try to run SQl from within my VBA, it gives me a type mismatch on my strSQl

检查这 2 个语句...

Dim StartUpdate, EndUpdate, LengthUpdate, strSQl As Date
strSQl = "INSERT INTO tbl_DatabaseUpdateLog ( Start, [End], Duration ) " & _
    "SELECT '" & StartUpdate & "' AS Started, '" & EndUpdate & "' AS Ended, '" & LengthUpdate & "' AS Lasted"

当您声明 strSQl As Date 时,这意味着 strSQl 只能包含 Date/Time 值。 "INSERT INTO ... whatever" 等字符串不是 Date/Time 值。因此,当您尝试将这样的字符串存储到 strSQl 时,Access 会抱怨数据类型不兼容:"Type mismatch".

由于您打算 strSQl 保存 SQL 语句的文本,因此以这种方式声明它(而不是 As Date):Dim strSQl As String

该更改应该可以让您克服错误。为了您更大的目标,使用带有 DAO 的参数查询。

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim StartUpdate As Date, EndUpdate As Date, LengthUpdate As Date
Dim strSQl As String

StartUpdate = Time()
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem
EndUpdate = Time()

LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "HH:MM:SS") & ")"

strSQl = "INSERT INTO tbl_DatabaseUpdateLog ([Start], [End], Duration) " & _
    "VALUES ([p1], [p2], [p3]);"
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSQl)
With qdf
    .Parameters("p1").Value = StartUpdate
    .Parameters("p2").Value = EndUpdate
    .Parameters("p3").Value = LengthUpdate
End With
qdf.Execute dbFailOnError
DoCmd.Close acForm, Me.Name

请注意,对于 INSERT,使用这种方法,日期 格式 甚至都不是问题。由于 StartUpdateEndUpdateLengthUpdate 都是有效的 Date/Time 值,您可以简单地将它们提供给参数,而无需担心格式和 # 分隔符。

更直接的方法是使用原生 DAO:

Dim rs As DAO.Recordset
Dim StartUpdate As Date
Dim EndUpdate As Date
Dim LengthUpdate As Date

StartUpdate = Time    
Call UpdateAll 'This calls the collection of queries and is irrelevant for my problem.    
EndUpdate = Time
LengthUpdate = EndUpdate - StartUpdate
Forms!frm_Timer.Caption = "Update Completed at " & EndUpdate & " (" & Format(LengthUpdate, "h:mm:ss") & ")"

Set rs = CurrentDb.OpenRecordset("Select Top 1 * From tbl_DatabaseUpdateLog")
rs.AddNew
    rs!Start.Value = StartUpdate
    rs!End.Value = EndUpdate
    rs!Duration.Value = LengthUpdate
rs.Update
rs.Close    
Set rs = Nothing

DoCmd.Close acForm, Me.Name