【问题标题】:VBA&SQL - delete date range from databaseVBA&SQL - 从数据库中删除日期范围
【发布时间】:2018-11-15 01:20:42
【问题描述】:

我正在尝试在我的 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

编辑:

我最终使用了以下建议之一,但日期的格式仍然存在问题,因此我承认我无法将实际字段保留为短文本。我刚刚注入了一条变更线,一切正常。

    DoCmd.RunSQL "ALTER TABLE AR_Consolidated ALTER COLUMN [Trade Date] Datetime"

【问题讨论】:

  • 永远不要将日期存储为文本。此外,请避免在字段名称中添加空格。

标签: sql vba date ms-access between


【解决方案1】:

为了在 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 AccessCOM / Automation 页面。

【讨论】:

  • 谢谢。从未考虑过 SQL 注入。将尝试这两个建议,如果可行,将进行更新。
  • @Chris 必需的 xkcd 参考:Exploits of a mom.
【解决方案2】:

我会采用不同的方法并使用参数而不是字符串连接。

查询的 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 个字符的普通字符串会导致运行时错误。

【讨论】:

  • 谢谢。将考虑到这一点进行一些编辑,一旦我开始工作就会更新。
  • 我会创建一个带有两个日期控件和一个按钮的简单表单。如果您将控件的格式设置为日期,它将不允许任何其他值。
【解决方案3】:

您可以验证输入,然后格式化值:

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 类似。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    • 2021-01-10
    • 2020-08-16
    • 2015-03-15
    • 1970-01-01
    相关资源
    最近更新 更多