MS Access:使用 VBA 进行 SQL 插入的日期格式
Posted
技术标签:
【中文标题】MS Access:使用 VBA 进行 SQL 插入的日期格式【英文标题】:MS Access: Date format for SQL Insert using VBA 【发布时间】:2016-02-18 00:08:46 【问题描述】:这可能是一个非常简单的问题,但到目前为止,我很难理解我在网上找到的信息。当我尝试从 VBA 中运行 SQl 时,我的 strSQl 出现类型不匹配。
我有一个包含 4 列的表 [tbl_DatabaseUpdateLog]
UpdateID(自动编号)
开始(日期/时间)
结束(日期/时间)
持续时间(日期/时间)
我必须定期从公司数据库中提取信息以进行较小的分析项目,并且我想记录运行这些查询的频率和时间。每次启动更新时,都会运行以下内容:
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
我尝试在日期前后使用#'s 并使用 Now() 而不是 Time(),但我觉得我缺少一个基本概念来帮助我解决问题。如果有帮助,我只需要时间和持续时间(而不是日期本身)。
【问题讨论】:
我建议你应该尝试使用参数进行插入。这更安全,并且忽略了格式。因此,您可以更轻松地插入日期和时间。否则,您必须处理令人头疼的格式... MS Access 不是 mysql 或 SQL-Server。请不要使用不恰当的标签。 我很抱歉。我在学习这些东西时有点陷入困境,而且我对差异有点模糊,因为我只熟悉基本知识。感谢您的修复。 【参考方案1】:当我尝试从我的 VBA 中运行 SQl 时,它给了我一个类型不匹配 在我的 strSQl 上
检查这两个语句...
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
只能保存日期/时间值。 "INSERT INTO ...whatever" 等字符串不是日期/时间值。因此,当您尝试将此类字符串存储到 strSQl
时,Access 会抱怨数据类型不兼容:“类型不匹配”。
由于您打算 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
的这种方法,日期格式 甚至都不是问题。由于StartUpdate
、EndUpdate
和LengthUpdate
都是有效的日期/时间值,您可以简单地将它们提供给参数,而无需担心格式和#
分隔符。
【讨论】:
我不敢相信我错过了将 strSQl 作为日期的小错误。那个小修复导致代码做我想要的,但我也尝试了你的代码,这样我将来可以学习一些更好的编码习惯。但是当我尝试它时,它给了我运行时错误 3061,“参数太少。预期为 3。” 它不要求任何东西,但它向我显示了带有 [Start]、[End] 和 [Duration] 参数的简化表我还注意到您的代码列出了 .Parameters("p2 ") 两次。我假设第二个是“p3” 我更正了第三行.Parameters
并将 VALUES
列表中的参数名称括起来。这些变化对你有用吗?
是的,现在可以了!我已经把“p2”改成了“p3”,所以肯定是VALUES
中的参数需要更新了。请问为什么这很重要?
我实际上并不相信括号很重要 --- 在我注意到我最初有两次“p2”之前,我添加了它们(就像出于绝望一样)。但是括号应该不会受伤,所以我离开了它们。【参考方案2】:
我看到您正在使用 INSERT INTO SELECT FROM (literal)
,而直接的 INSERT INTO (columns) VALUES (values)
会更简单。您还可以在单个 INSERT
语句中包含多个 VALUES
子语句,这很简洁。
我还看到您正在存储非规范化数据,很明显 Duration
可以从 End - Start
派生,因此您可能希望删除该列。
另外,请避免使用匈牙利表示法,在这种情况下,请在表名称前加上 tbl_
前缀。现在已经不是 1980 年代了。不要这样做。
使用字符串连接的简短而简单的回答:
(永远不要这样做)
SQL 服务器
如果您使用的是 SQL Server,则需要将日期括在单引号中,并且需要转换为明确的日期格式字符串,例如 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 Server 使用命名参数,例如 @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 个可选参数:Type
、Direction
和 Size
,可以从值中推断出来,因此可以通过输入 , , ,
来省略它们。
【讨论】:
如果提供 VBA 示例而不是 VB.NET 示例,您的“更好的答案:使用参数”部分会更好。 @GordThompson 我已修改我的答案以在 VBA 语法中使用 ADO。 如果您修改它以保持正确的 SQL 语法,它甚至会很有用。以下是 Format 函数的参考:Format Function (Visual Basic for Applications) Access/Jet 的 'hh:mm:ss tt' 中的 'tt' 是什么? 'tt' 没有记录在 VBA 文档 AFAICS 中,它不适用于 Access 2016 中的 'tt'。它在没有 'tt' 的情况下也能工作。【参考方案3】:更直接的方法是使用原生 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
【讨论】:
【参考方案4】:只计算时间,在 VBA 中你可以使用这个表达式:
CDate(Now - Date())
将结果括在 # 中,因为结果仍然是 Date 类型,即使只存储时间信息。
您可以使用 DateDiff 函数来计算持续时间,您需要选择合适的单位。例如:
DateDiff(DateInterval.Second, EndUpdate, StartUpdate)
结果是一个长整数,因此您不需要将结果包含在 SQL 中。
建议您对 SQL 进行参数化,但不是必需的。
【讨论】:
为什么建议使用CDate(Now - Date())
而不是Time()
?要么给你一个日期/时间值,以 Dec 30 1899 作为日期部分:Debug.Print Format(CDate(Now - Date()), "mmm d yyyy hh:nn:ss"), Format(Time, "mmm d yyyy hh:nn:ss")
TBH 这个问题不是很清楚,但我试图通过展示一种通用方法来回答“我只需要时间和持续时间(而不是日期本身)”部分从日期表达式中删除日期信息。正如您指出的那样,两者都给出了相同的答案。我希望 OP 在这里了解如何操作日期是 VB以上是关于MS Access:使用 VBA 进行 SQL 插入的日期格式的主要内容,如果未能解决你的问题,请参考以下文章
编辑器中的 ms-access VBA 长 sql 查询字符串行拆分(内联双引号)
使用 VBA (MS Access) 中的 bigint 字段更新 SQL 表
使用 Excel VBA 查询 MS Access,SQL BETWEEN 日期查询
使用 VBA 或 PowerShell 将所有 MS Access SQL 查询导出到文本文件