【问题标题】:Input error when I am using vba to execute SQL使用vba执行SQL时输入错误
【发布时间】:2020-12-09 19:23:05
【问题描述】:

我的 RunSQL 语句似乎遇到了问题,我不断收到以下错误

查询输入必须至少包含一个表或查询

我确定这是一个简单的错误,但我现在没有看到。

Private Sub Command13_Click()
    Dim SQL_Text As String
    Dim reccount As Long
    Dim dbs As Database
    Dim rs As DAO.Recordset

    'Assign count of PO's
    Set dbs = OpenDatabase("Y:\Databases\Bulk database\Fabric_Data.mdb")
    Set rs = dbs.OpenRecordset("SELECT * FROM PO;")
    rs.MoveLast
    reccount = rs.RecordCount
    rs.Close

    'IF PO count is greater than 0 the table is Drop and PO's are recounted in prep to be inserted
    If recount <> 0 Then
        DoCmd.RunSQL ("DROP [PO_#];")
        DoCmd.RunSQL ("SELECT [P0_#] INTO PO FROM Fabric_Release;")
    Else
        DoCmd.RunSQL ("SELECT [PO_#] INTO PO FROM Fabric_Release;")
    End If

    Set rs = Nothing

    'Insert new PO data
    SQL_Text = "INSERT INTO Fabric_Release ([PO_#], Supplier, [Fabric Name], [Fabric_#], Order_Qty, ETD) VALUES ('" & Me![PO_#] & "', '" & Me.Supplier & "', '" & Me![Fabric Name] & "', '" & Me![Fabric_#] & "', '" & Me.Order_Qty & "', '" & Me.ETD & "')" & " " & _
               "WHERE '" & Me![PO_#] & "' NOT IN (SELECT [PO_#] FROM PO);"
    MsgBox (SQL_Text)
    DoCmd.RunSQL (SQL_Text)
End Sub

【问题讨论】:

  • 4 个RunSQL 语句中的哪一个导致了错误?
  • 最后一句话
  • 如果字段是数字类型,不要使用撇号分隔符。如果字段是日期/时间,请使用 # 分隔符。 WHERE 子句在这种情况下没有价值。查看stackoverflow.com/questions/6199417/upserting-in-ms-access 建议不要在命名约定中使用标点符号/特殊字符。最好是 PO_Num。
  • 您在最后一条语句中的 SQL 中有错误,因此无法正确解析。您可以通过不连接 SQL 而是使用参数化查询来避免这种情况。这样做还可以防止 SQL 注入导致数据丢失或损坏。
  • 也不建议在命名中使用空格。为什么要保存面料名称和面料编号?

标签: sql vba ms-access


【解决方案1】:

正如@KenWhite 所评论的,使用 SQL 参数化的最佳实践(除了 MS Access 和 VBA 之外的概念,但适用于所有数据库和连接到它们的所有编程语言使用 SQL)。这样做,您可以避免将 VBA 变量连接到带有引号的 SQL 字符串的混乱甚至危险的需要。

具体来说,MS Access 支持在 DAO 中使用 SQL 中的PARAMETERS 子句进行参数化,该子句可以通过QueryDefs.Parameters 与应用层值绑定。因此,请使用以下内容调整您上次的 RunSQL 呼叫:

...
Dim qdef As QueryDef

' DEFINE PREPARED SQL (NO VBA DATA) WITH DEFINED COLUMN TYPES
SQL_Text = "PARAMETERS [prmPO] AS TEXT, [prmSupplier] AS TEXT, [prmFabricName] AS TEXT," _ 
           & "         [prmFabricNum] AS INTEGER, [prmOrderQty] AS LONG, [prmETD] AS DATE; " _
           & "INSERT INTO Fabric_Release ([PO_#], Supplier, [Fabric Name], [Fabric_#], Order_Qty, ETD)" _
           & " VALUES ([prmPO], [prmSupplier], [prmFabricName], [prmFabricNum], [prmOrderQty], [prmETD])"

' INITIALIZE QUERYDEF
Set qdef = CurrentDb.CreateQueryDef("", SQL_Text)
' Set qdef = CurrentDb.QueryDefs("mySavedParamQuery")  ' FOR SAVED QUERY WITH ABOVE SQL

' BIND PARAMETERS
qdef![prmPO] =  Me![PO_#]                   ' ASSUMED TO BE A TEXT
qdef![prmSupplier] = Me.Supplier            ' ASSUMED TO BE A TEXT 
qdef![prmFabricName] = Me![Fabric Name]     ' ASSUMED TO BE A TEXT
qdef![prmFabricNum] = Me![Fabric_#]         ' ASSUMED TO BE A NUMBER 
qdef![prmOrderQty] = Me.Order_Qty           ' ASSUMED TO BE A NUMBER
qdef![prmETD] = Me.ETD                      ' ASSUMED TO BE A DATE/TIME VALUE

' EXECUTE ACTION QUERY
qdef.Execute

' UNINTIALIZE QUERYDEF
Set qdef = Nothing

更好的是,您可以使用保存的 SQL 查询,该查询通过 DoCmd.OpenQuery 调用指向表单控件,该调用可以直接从打开的表单控件中读取:

SQL (调整表单名称并在下方另存为 MS Access 查询)

INSERT INTO Fabric_Release ([PO_#], Supplier, [Fabric Name], [Fabric_#], Order_Qty, ETD)
VALUES (Forms!myForm![prmPO], Forms!myForm![prmSupplier], Forms!myForm![prmFabricName], 
        Forms!myForm![prmFabricNum], Forms!myForm![prmOrderQty], Forms!myForm![prmETD])

VBA

Private Sub Command13_Click()
   ' AVOID DROP/MAKE TABLE QUERIES FOR DELETE/INSERT
   DoCmd.RunSQL "DELETE FROM [PO]"
   DoCmd.RunSQL "INSERT INTO [PO] ([PO_#]) SELECT [PO_#] FROM Fabric_Release"

   DoCmd.OpenQuery "mySavedQuery"                 ' NO NEED TO CLOSE ACTION QUERIES
 End Sub

【讨论】:

  • 谢谢。这应该会帮助我度过难关。
  • 很高兴听到。如果解决方案有帮助,请不要忘记 StackOverflow 的说法 thanks
猜你喜欢
  • 2022-12-18
  • 1970-01-01
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-10
相关资源
最近更新 更多