VBA&;SQL-从数据库中删除日期范围
我试图在Access数据库上创建一个选项,删除两个日期之间的所有记录 我在下面的代码似乎并不一致。例如,如果我的数据库具有日期01/01/18至01/30/18,并且我指定的范围正好是01/01/18至01/30/18,则它将工作并删除所有数据 但如果我指定任何其他日期范围(如01/01-01/15),它将失败,并且不会删除任何记录 [交易日期]为短文本格式,而不是日期,但所有条目均为MM/DD/YY。我宁愿保持这种方式,除非这是一个问题,没有其他选择 请让我知道我做错了什么或可以做得更好。先谢谢你VBA&;SQL-从数据库中删除日期范围,sql,vba,date,ms-access,between,Sql,Vba,Date,Ms Access,Between,我试图在Access数据库上创建一个选项,删除两个日期之间的所有记录 我在下面的代码似乎并不一致。例如,如果我的数据库具有日期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
为了在Jet SQL中表示日期值,您需要用
#
将其包围起来,这样您的SQL就可以这样结束:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN #01/01/18# AND #01/30/18#
PARAMETERS [prmDateFrom] DateTime, [prmDateTo] DateTime;
DELETE *
FROM AR_Consolidated
WHERE [Trade Date] Between [prmDateFrom] And [prmDateTo];
请注意,一般来说,将字符串与用户输入结合起来生成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\u 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上的和页面。我将采用不同的方法,使用参数而不是字符串连接 查询的SQL如下所示:
DELETE FROM AR_Consolidated WHERE [Trade Date] BETWEEN #01/01/18# AND #01/30/18#
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
Sub Something()
Dim trFrmDat As字符串
Dim trToDat作为字符串
trFrmDat=InputBox(“交易日期从[MM/DD/YY]删除:”)
trToDat=InputBox(“交易日期被删除到[MM/DD/YY]:”)
如果Len(trFrmDat)8或Len(trToDat)8,则
MsgBox(“尚未输入正确的日期或答案。进程已中止。”)
出口接头
如果结束
将qdf设置为DAO.QueryDef
不算长
设置qdf=CurrentDb().QueryDefs(“QueryName”)
使用qdf
.Parameters(“[PRMDATEFORM]”)。值=CDate(trFrmDat)
.Parameters(“[prmDateTo]”)。值=CDate(trToDat)
.执行dbFailOnError
计数=.RecordsAffected
以
MsgBox“”和计数记录已从AR_Consolidated中删除
端接头
但是,您需要增强输入验证,因为包含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。谢谢。我会在心里做一些编辑,一旦我开始工作就会更新。我会用两个日期控件和一个按钮创建一个简单的表单。如果将控件的格式设置为日期,则不允许使用任何其他值。谢谢。从未考虑过SQL注入。将尝试这两个建议,如果有效,将进行更新。@Chris需要xkcd引用:。永远不要将日期存储为文本。此外,避免在字段名中使用空格。