VBA 中 DateAdd 的 MS Access 问题插入日期格式不一致的语句
MS Access Problem with DateAdd in VBA Insert statement with inconsistent date format
我对如何在我的数据库中存储日期有疑问。
我需要创建一个临时 TableC,其中将为 TableA 上的每条记录插入 X 条记录。其中 X 是周数。结果 table 将在 UNION 语句中与其他几个查询一起使用。
问题在于 DateAdd 如何为每条新记录创建日期。日期最初以 dd/mm/yyyy 格式存储。但是生成的 DateAdd("ww", i, rst![Date]) 有时会以 mm/dd/yyyy 格式存储,从而在 30K 结果行中造成严重破坏。
写了一个 VB Sub 来创建 table,下面是一个关于实际存储方式与预期存储方式的示例。
Sub AddItems()
Dim db as DAO.Database
Dim rst as DAO.Recordset
Dim Sql1, Sql2 as String
Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];"
Set db = CurrentDb
Set rst = db.OpenRecordset(Sql1)
rst.movefirst
While NOT rst.EOF
If rst![Weeks] > 0 Then
For i = 1 to rst![Weeks]
Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMOUNT]) VALUES ("
Sql2 = Sql2 & rst![ID] & ", " & rst![CUSTOMER]
Sql2 = Sql2 & "#" & Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy") & "#"
Sql2 = Sql2 & ", " & rst![AMOUNT]
Sql2 = Sql2 & ")"
Debug.Print Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy")
db.Execute(Sql2)
Next i
End If
rst.movenext
Wend
End Sub
结果 TABLE 样本
+------------+------------+------------+
|星期 |关于 Table |在调试 |预期数据已插入
+------------+------------+------------+
| 1 | 12/02/2019 | 2019 年 2 月 12 日 |应该是 2/12/2019
| |作为 2 月 12 日 |正确 |
+------------+------------+------------+
| 2 | 2019 年 12 月 9 日 | 2019 年 9 月 12 日 |应该是 2019 年 12 月 9 日
| |作为 9 月 12 日 |正确 |
+------------+------------+------------+
| 3 | 16/12/2019 | 16/12/2019 |应该是 2019 年 12 月 16 日
| |正确 |正确 |
+------------+------------+------------+
立即 Window 上打印的结果是正确的,但实际 table 上的信息不正确。我的样本数据从 02/12/2019 开始(2/12/2019 已通过 TableA 中 table 视图中的日期选择器确认)
调试 window 显示要存储的正确信息,但 table 上的信息不正确,尽管 TableC 中的字段 [DATE] 的格式为 "Short Date" 并使用 IsDate 验证规则。
如果没有这两个 Format 语句,结果将与预期的结果大相径庭。然而,生成的 DATE 字段并不一致。
有没有办法根据系统设置一致地生成日期并存储它们?
如果数据类型为日期,则日期值不会以某种格式存储。一种格式仅供显示或在 SQL 中连接时使用。所以尝试:
Sub AddItems()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim Sql1 As String
Dim Sql2 As String
Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];"
Set db = CurrentDb
Set rst = db.OpenRecordset(Sql1)
rst.MoveFirst
While Not rst.EOF
If rst![Weeks] > 0 Then
For i = 1 to rst![Weeks]
Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMOUNT]) VALUES ("
Sql2 = Sql2 & rst![ID] & ", '" & rst![CUSTOMER] & "', "
Sql2 = Sql2 & "#" & Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy") & "#, "
Sql2 = Sql2 & Str(rst![AMOUNT])
Sql2 = Sql2 & ")"
Debug.Print Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy")
db.Execute(Sql2)
Next i
End If
rst.MoveNext
Wend
End Sub
也就是说,为 TableC 打开第二个记录集然后使用 AddNew 和 Update 追加会更简单、更快周的记录。
如果您的“日期”存储为 文本,除了手动编辑以使其格式一致之外,没有办法解决您的问题。
先说几点:
- 根本没有声明变量
i
,您应该在模块的 header 中使用 Option Explicit
以使 VBE 能够警告您。
Date
是保留字,所以我改名为YourDate
.
- 变量
sql1
被隐式定义为类型变体。
- 您对变量
sql1
的 SQL 的定义在句法上不正确。我更正了它,希望这是你的意思。
- 我希望您的 table 字段
YourDate
是日期类型而不是字符串类型。如果它是字符串,那么您需要先在代码中将其转换为日期,或者在 table. 中更好
- 如果您隐含地想使用它来清除您所做的事情,请始终明确使用 属性
Value
,并且不要意外分配 object。
- 在 SQL 注入的情况下,连接 SQL 字符串是不安全的。面向 object 的方法不是,它是类型安全的。
这应该会如您所愿:
Option Compare Database
Option Explicit
Sub AddItems()
Dim sql1 As String
sql1 = "SELECT a.*, b.YourDate, b.Weeks, b.Rate FROM TableA as a LEFT JOIN TableB as b On a.GroupId = b.Id ORDER BY b.YourDate, a.Id"
Dim db As DAO.Database
Set db = CurrentDb
Dim rst As DAO.Recordset
Set rst = db.OpenRecordset(sql1)
rst.MoveFirst
While Not rst.EOF
If rst("Weeks").Value > 0 Then
Dim i As Long
For i = 1 To rst("Weeks").Value
With CurrentDb().CreateQueryDef(vbNullString, _
"INSERT INTO TableC ([ID], [CUSTOMER], [YourDATE], [AMOUNT]) " & _
"VALUES (@ParID, @ParCustomer, @ParDate, @ParAmount)")
.Parameters("@ParID").Value = rst("ID").Value
.Parameters("@ParCustomer").Value = rst("CUSTOMER").Value
.Parameters("@ParDate").Value = DateAdd("ww", (i - 1), rst("YourDate").Value)
.Parameters("@ParAmount").Value = rst("AMOUNT").Value
.Execute dbFailOnError
End With
Next i
End If
rst.MoveNext
Wend
rst.Close
End Sub
我对如何在我的数据库中存储日期有疑问。
我需要创建一个临时 TableC,其中将为 TableA 上的每条记录插入 X 条记录。其中 X 是周数。结果 table 将在 UNION 语句中与其他几个查询一起使用。
问题在于 DateAdd 如何为每条新记录创建日期。日期最初以 dd/mm/yyyy 格式存储。但是生成的 DateAdd("ww", i, rst![Date]) 有时会以 mm/dd/yyyy 格式存储,从而在 30K 结果行中造成严重破坏。
写了一个 VB Sub 来创建 table,下面是一个关于实际存储方式与预期存储方式的示例。
Sub AddItems() Dim db as DAO.Database Dim rst as DAO.Recordset Dim Sql1, Sql2 as String Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];" Set db = CurrentDb Set rst = db.OpenRecordset(Sql1) rst.movefirst While NOT rst.EOF If rst![Weeks] > 0 Then For i = 1 to rst![Weeks] Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMOUNT]) VALUES (" Sql2 = Sql2 & rst![ID] & ", " & rst![CUSTOMER] Sql2 = Sql2 & "#" & Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy") & "#" Sql2 = Sql2 & ", " & rst![AMOUNT] Sql2 = Sql2 & ")" Debug.Print Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy") db.Execute(Sql2) Next i End If rst.movenext Wend End Sub
结果 TABLE 样本 +------------+------------+------------+ |星期 |关于 Table |在调试 |预期数据已插入 +------------+------------+------------+ | 1 | 12/02/2019 | 2019 年 2 月 12 日 |应该是 2/12/2019 | |作为 2 月 12 日 |正确 | +------------+------------+------------+ | 2 | 2019 年 12 月 9 日 | 2019 年 9 月 12 日 |应该是 2019 年 12 月 9 日 | |作为 9 月 12 日 |正确 | +------------+------------+------------+ | 3 | 16/12/2019 | 16/12/2019 |应该是 2019 年 12 月 16 日 | |正确 |正确 | +------------+------------+------------+
立即 Window 上打印的结果是正确的,但实际 table 上的信息不正确。我的样本数据从 02/12/2019 开始(2/12/2019 已通过 TableA 中 table 视图中的日期选择器确认)
调试 window 显示要存储的正确信息,但 table 上的信息不正确,尽管 TableC 中的字段 [DATE] 的格式为 "Short Date" 并使用 IsDate 验证规则。
如果没有这两个 Format 语句,结果将与预期的结果大相径庭。然而,生成的 DATE 字段并不一致。
有没有办法根据系统设置一致地生成日期并存储它们?
如果数据类型为日期,则日期值不会以某种格式存储。一种格式仅供显示或在 SQL 中连接时使用。所以尝试:
Sub AddItems()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim Sql1 As String
Dim Sql2 As String
Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];"
Set db = CurrentDb
Set rst = db.OpenRecordset(Sql1)
rst.MoveFirst
While Not rst.EOF
If rst![Weeks] > 0 Then
For i = 1 to rst![Weeks]
Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMOUNT]) VALUES ("
Sql2 = Sql2 & rst![ID] & ", '" & rst![CUSTOMER] & "', "
Sql2 = Sql2 & "#" & Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy") & "#, "
Sql2 = Sql2 & Str(rst![AMOUNT])
Sql2 = Sql2 & ")"
Debug.Print Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy")
db.Execute(Sql2)
Next i
End If
rst.MoveNext
Wend
End Sub
也就是说,为 TableC 打开第二个记录集然后使用 AddNew 和 Update 追加会更简单、更快周的记录。
如果您的“日期”存储为 文本,除了手动编辑以使其格式一致之外,没有办法解决您的问题。
先说几点:
- 根本没有声明变量
i
,您应该在模块的 header 中使用Option Explicit
以使 VBE 能够警告您。 Date
是保留字,所以我改名为YourDate
.- 变量
sql1
被隐式定义为类型变体。 - 您对变量
sql1
的 SQL 的定义在句法上不正确。我更正了它,希望这是你的意思。 - 我希望您的 table 字段
YourDate
是日期类型而不是字符串类型。如果它是字符串,那么您需要先在代码中将其转换为日期,或者在 table. 中更好
- 如果您隐含地想使用它来清除您所做的事情,请始终明确使用 属性
Value
,并且不要意外分配 object。 - 在 SQL 注入的情况下,连接 SQL 字符串是不安全的。面向 object 的方法不是,它是类型安全的。
这应该会如您所愿:
Option Compare Database
Option Explicit
Sub AddItems()
Dim sql1 As String
sql1 = "SELECT a.*, b.YourDate, b.Weeks, b.Rate FROM TableA as a LEFT JOIN TableB as b On a.GroupId = b.Id ORDER BY b.YourDate, a.Id"
Dim db As DAO.Database
Set db = CurrentDb
Dim rst As DAO.Recordset
Set rst = db.OpenRecordset(sql1)
rst.MoveFirst
While Not rst.EOF
If rst("Weeks").Value > 0 Then
Dim i As Long
For i = 1 To rst("Weeks").Value
With CurrentDb().CreateQueryDef(vbNullString, _
"INSERT INTO TableC ([ID], [CUSTOMER], [YourDATE], [AMOUNT]) " & _
"VALUES (@ParID, @ParCustomer, @ParDate, @ParAmount)")
.Parameters("@ParID").Value = rst("ID").Value
.Parameters("@ParCustomer").Value = rst("CUSTOMER").Value
.Parameters("@ParDate").Value = DateAdd("ww", (i - 1), rst("YourDate").Value)
.Parameters("@ParAmount").Value = rst("AMOUNT").Value
.Execute dbFailOnError
End With
Next i
End If
rst.MoveNext
Wend
rst.Close
End Sub