VBA&SQL - 从数据库中删除日期范围
VBA&SQL - delete date range from database
我正在尝试在我的 Access 数据库上创建一个选项,用于删除 2 个日期之间的所有记录。
我下面的代码似乎无法始终如一地工作。例如,如果我的数据库的日期是 01/01/18 到 01/30/18,而我指定的范围恰好是 01/01/18 到 01/30/18,那么它会工作并删除所有数据。
但如果我指定任何其他日期范围(如 01/01 - 01/15),它将失败并且不会删除任何记录。
[交易日期]是短文本格式而不是日期,但所有条目都在MM/DD/YY中。宁愿保持这种方式,除非这是问题所在并且没有其他选择。
请让我知道我做错了什么或者可以做得更好。先感谢您。
Dim trFrmDat As String
Dim trToDat As String
Dim dbsDelete As DAO.Database
Dim qdfToDelete As DAO.QueryDef
Dim countString As String
Dim count As Long
Set dbsDelete = CurrentDb
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If Len(trFrmDat) <> 8 Or Len(trToDat) <> 8 Then
MsgBox ("The correct date or answer has not been entered. Process Aborted.")
Exit Sub
Else
countString = "SELECT COUNT(PK_ID) FROM AR_Consolidated WHERE [Trade Date] BETWEEN " & trFrmDat & " AND " & trToDat & ""
count = dbsDelete.OpenRecordset(countString).Fields(0).Value
Set qdfToDelete = dbsDelete.CreateQueryDef("", "DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN " & trFrmDat & " AND " & trToDat & "")
qdfToDelete.Execute dbFailOnError
MsgBox ("" & count & " records have been deleted from AR_Consolidated")
End If
编辑:
我最终使用了以下建议之一,但日期格式仍然存在问题,因此我承认我无法将实际字段保留为短文本。我刚刚注入了一条更改线,一切正常。
DoCmd.RunSQL "ALTER TABLE AR_Consolidated ALTER COLUMN [Trade Date] Datetime"
为了在 Jet SQL 中表示日期值,您需要用 #
将其括起来,这样您的 SQL 就会像这样结束:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN #01/01/18# AND #01/30/18#
请注意,一般来说,将字符串与用户输入结合起来制作 SQL 语句不是一个好主意。除了与您类似的问题——在 SQL 语句中正确表示日期或其他文字——您还可能遭受 SQL 注入,恶意用户插入额外的 SQL 语句或子句导致您的代码失败或做一些不需要的事情。例如,用户可以将以下字符串作为第二个参数传入:
01/01/18 OR 1 = 1
和生成的 SQL 语句:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN 01/01/18 AND 01/01/18 OR 1 = 1
会删除AR_Consolidated
中的所有记录。
避免这两个 类 问题的正确方法是使用参数化查询。
Dim sql As String
sql = _
"PARAMETERS FromDate DATETIME, TillDate DATETIME; " & _
"DELETE FROM AR_Consolidated " & _
"WHERE [Trade Date] BETWEEN FromDate AND TillDate"
Dim qdfToDelete As DAO.QueryDef
Set qdfToDelete = dbsToDelete.CreateQueryDef("", sql)
qdfToDelete.Parameters("FromDate") = trFromDate
qdfToDelete.Parameters("TillDate") = trToDate
'You may have to convert the string values to dates first
qdfToDelete.Execute dbFailOnError
有关在针对 Jet / ACE 编程时如何避免 SQL 注入的全面说明,请参阅 bobby-tables.com 上的 Microsoft Access and COM / Automation 页。
我会采用不同的方法并使用参数而不是字符串连接。
查询的 SQL 将是这样的:
PARAMETERS [prmDateFrom] DateTime, [prmDateTo] DateTime;
DELETE *
FROM AR_Consolidated
WHERE [Trade Date] Between [prmDateFrom] And [prmDateTo];
然后在 VBA 中调用我的查询:
Sub Something()
Dim trFrmDat As String
Dim trToDat As String
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If Len(trFrmDat) <> 8 Or Len(trToDat) <> 8 Then
MsgBox ("The correct date or answer has not been entered. Process Aborted.")
Exit Sub
End If
Dim qdf As DAO.QueryDef
Dim count As Long
Set qdf = CurrentDb().QueryDefs("QueryName")
With qdf
.Parameters("[prmDateFrom]").Value = CDate(trFrmDat)
.Parameters("[prmDateTo]").Value = CDate(trToDat)
.Execute dbFailOnError
count = .RecordsAffected
End With
MsgBox " " & count & " records have been deleted from AR_Consolidated"
End Sub
但是,您需要加强输入验证,因为无法将 8 个字符转换为日期的普通字符串会导致运行时错误。
您可以验证输入然后格式化值:
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If IsDate(trFrmDat) And IsDate(trToDat) Then
trFrmDat = Format(CDate(trFrmDat), "yyyy\/mm\/dd")
trToDat = Format(CDate(trToDat), "yyyy\/mm\/dd")
countString = "SELECT COUNT(PK_ID) FROM AR_Consolidated WHERE [Trade Date] BETWEEN #" & trFrmDat & "# AND #" & trToDat & "#"
End If
与删除类似 SQL。
我正在尝试在我的 Access 数据库上创建一个选项,用于删除 2 个日期之间的所有记录。
我下面的代码似乎无法始终如一地工作。例如,如果我的数据库的日期是 01/01/18 到 01/30/18,而我指定的范围恰好是 01/01/18 到 01/30/18,那么它会工作并删除所有数据。
但如果我指定任何其他日期范围(如 01/01 - 01/15),它将失败并且不会删除任何记录。
[交易日期]是短文本格式而不是日期,但所有条目都在MM/DD/YY中。宁愿保持这种方式,除非这是问题所在并且没有其他选择。
请让我知道我做错了什么或者可以做得更好。先感谢您。
Dim trFrmDat As String
Dim trToDat As String
Dim dbsDelete As DAO.Database
Dim qdfToDelete As DAO.QueryDef
Dim countString As String
Dim count As Long
Set dbsDelete = CurrentDb
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If Len(trFrmDat) <> 8 Or Len(trToDat) <> 8 Then
MsgBox ("The correct date or answer has not been entered. Process Aborted.")
Exit Sub
Else
countString = "SELECT COUNT(PK_ID) FROM AR_Consolidated WHERE [Trade Date] BETWEEN " & trFrmDat & " AND " & trToDat & ""
count = dbsDelete.OpenRecordset(countString).Fields(0).Value
Set qdfToDelete = dbsDelete.CreateQueryDef("", "DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN " & trFrmDat & " AND " & trToDat & "")
qdfToDelete.Execute dbFailOnError
MsgBox ("" & count & " records have been deleted from AR_Consolidated")
End If
编辑:
我最终使用了以下建议之一,但日期格式仍然存在问题,因此我承认我无法将实际字段保留为短文本。我刚刚注入了一条更改线,一切正常。
DoCmd.RunSQL "ALTER TABLE AR_Consolidated ALTER COLUMN [Trade Date] Datetime"
为了在 Jet SQL 中表示日期值,您需要用 #
将其括起来,这样您的 SQL 就会像这样结束:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN #01/01/18# AND #01/30/18#
请注意,一般来说,将字符串与用户输入结合起来制作 SQL 语句不是一个好主意。除了与您类似的问题——在 SQL 语句中正确表示日期或其他文字——您还可能遭受 SQL 注入,恶意用户插入额外的 SQL 语句或子句导致您的代码失败或做一些不需要的事情。例如,用户可以将以下字符串作为第二个参数传入:
01/01/18 OR 1 = 1
和生成的 SQL 语句:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN 01/01/18 AND 01/01/18 OR 1 = 1
会删除AR_Consolidated
中的所有记录。
避免这两个 类 问题的正确方法是使用参数化查询。
Dim sql As String
sql = _
"PARAMETERS FromDate DATETIME, TillDate DATETIME; " & _
"DELETE FROM AR_Consolidated " & _
"WHERE [Trade Date] BETWEEN FromDate AND TillDate"
Dim qdfToDelete As DAO.QueryDef
Set qdfToDelete = dbsToDelete.CreateQueryDef("", sql)
qdfToDelete.Parameters("FromDate") = trFromDate
qdfToDelete.Parameters("TillDate") = trToDate
'You may have to convert the string values to dates first
qdfToDelete.Execute dbFailOnError
有关在针对 Jet / ACE 编程时如何避免 SQL 注入的全面说明,请参阅 bobby-tables.com 上的 Microsoft Access and COM / Automation 页。
我会采用不同的方法并使用参数而不是字符串连接。
查询的 SQL 将是这样的:
PARAMETERS [prmDateFrom] DateTime, [prmDateTo] DateTime;
DELETE *
FROM AR_Consolidated
WHERE [Trade Date] Between [prmDateFrom] And [prmDateTo];
然后在 VBA 中调用我的查询:
Sub Something()
Dim trFrmDat As String
Dim trToDat As String
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If Len(trFrmDat) <> 8 Or Len(trToDat) <> 8 Then
MsgBox ("The correct date or answer has not been entered. Process Aborted.")
Exit Sub
End If
Dim qdf As DAO.QueryDef
Dim count As Long
Set qdf = CurrentDb().QueryDefs("QueryName")
With qdf
.Parameters("[prmDateFrom]").Value = CDate(trFrmDat)
.Parameters("[prmDateTo]").Value = CDate(trToDat)
.Execute dbFailOnError
count = .RecordsAffected
End With
MsgBox " " & count & " records have been deleted from AR_Consolidated"
End Sub
但是,您需要加强输入验证,因为无法将 8 个字符转换为日期的普通字符串会导致运行时错误。
您可以验证输入然后格式化值:
trFrmDat = InputBox("Trade Date To Be Deleted From [MM/DD/YY]:")
trToDat = InputBox("Trade Date To Be Deleted To [MM/DD/YY]:")
If IsDate(trFrmDat) And IsDate(trToDat) Then
trFrmDat = Format(CDate(trFrmDat), "yyyy\/mm\/dd")
trToDat = Format(CDate(trToDat), "yyyy\/mm\/dd")
countString = "SELECT COUNT(PK_ID) FROM AR_Consolidated WHERE [Trade Date] BETWEEN #" & trFrmDat & "# AND #" & trToDat & "#"
End If
与删除类似 SQL。