【问题标题】:Can't seem to get rid of pesky syntax errors似乎无法摆脱讨厌的语法错误
【发布时间】:2018-12-14 06:39:37
【问题描述】:

所以我对 SQL 编码有点陌生,我的公司有一个预先存在的采购订单系统,运行一个 .xlsx 启用宏的工作表。

我不断收到“靠近“,”的语法不正确,当我在这里或那里更改随机逗号时,我得到不同的错误。当它抛出错误并且我热调试时,它会突出显示@ 987654321@线

那么在每个受过良好训练的人眼中,有什么特别突出的吗? 谢谢!

Dim Report As Worksheet
Set Report = Excel.ActiveSheet
SQL = "insert into Purchases.dbo.POs values(" & Range("H12").Value & "," & Range("H30").Value & Excel.WorksheetFunction.Sum(Report.Range("F16:F29")) & "," & Range("A34").Value & _
"','" & Range("F7").Value & "','" & Range("C12").Value & "','" & Range("A38").Value & "',0,'" & Code & "')"
'MsgBox SQL
Set RS = Conn.Execute(SQL)

【问题讨论】:

  • 你能打印出SQL语句是什么吗?您可以在调试器中检查变量或在即时窗口中打印它
  • 我会将长 SQL 字符串分解为辅助变量,然后您可以在调试时更清楚地看到它们。 excel单元格中的值是否有逗号,例如单元格H12?还是空白?
  • 你能包含'MsgBox SQL'的输出吗?另外,您使用的是什么 DBMS(MySQL、SQL Server 等)?
  • 您包含的任何字段中是否有字符串?如果是,您将必须传递字符串文字。 (N'... ' 代表 NVARCHAR 和 '... ' 代表 VARCHAR)如果存在包含撇号的字符串,则必须将其加倍以对其进行转义。
  • 您可能需要一个左撇号来表示您从 A34 获得的值,因为您有一个结束撇号。

标签: sql excel vba syntax-error


【解决方案1】:

如您所见,在一条指令中塞入尽可能多的操作会使代码更难阅读和调试。

也就是说,我有 95% 的把握这 Range("H30").Value & Excel.WorksheetFunction.Sum(Report.Range("F16:F29")) 不是你想要做的。

分解:

Dim value1 As Double
value1 = ActiveSheet.Range("H12").Value

Dim value2 As String
value2 = "'" & ActiveSheet.Range("H30").Value & "'"

Dim value3 As Double
value3 = Excel.WorksheetFunction.Sum(Report.Range("F16:F29"))

Dim value4 As Double
value4 = ActiveSheet.Range("A34").Value

Dim value5 As String
value5 = "'" & ActiveSheet.Range("F7").Value & "'"

Dim value6 As String
value6 = "'" & ActiveSheet.Range("C12").Value & "'"

Dim value7 As String
value7 = "'" & ActiveSheet.Range("A38").Value & "'"

Dim value8 As Long
value8 = 0

Dim value9 As String
value9 = "'" & Code & "'"

现在您可以单独验证每个值。都好?现在将它们连接起来:

Dim values As Variant
values = Join(Array(value1, value2, value3, value4, value5, value6, value7, value8, value9), ",")

Dim sql As String
sql = "insert into Purchases.dbo.POs values(" & values & ")"

SQL 字符串看起来正确吗?

Debug.Print sql
Stop 'hit Ctrl+G to bring up the *immediate pane* and view the output

如果您获取该输出并在 SSMS 中运行它,插入是否有效?是的?那么你就可以开始了!

conn.Execute sql

现在,假设ActiveSheet.Range("H30").Value 包含一个恶意字符串;像这样直接从连接中执行它会使insert 语句失败,SQL Server 将愉快地执行被不小心连接到查询中的可执行 SQL 语句:this comes to mind,查找“SQL 注入”以获取更多信息。

研究如何为每个值使用ADODB.CommandADODB.Parameter,并立即避免此安全漏洞。当值包含 ' 单引号时,它还可以防止您的代码生成无效的 SQL 语句 - 作为奖励,您不再需要关心带有单引号的周围字符串,服务器将处理它。

【讨论】:

  • 我不知道您不需要字段列表。顺便说一句,大写 SQL 关键字会更好:)
  • @TinMan 如果值的数量(及其类型)与表结构匹配,则可以省略字段名称(可以省略 PK/identity 列,假设 identity insert 已关闭)。另外... SCREAMCASE 让我的眼睛流血 ;-)
  • 我猜你不可能对所有事情都是正确的......至少是正确的情况!......大声笑
  • @TinMan 嗯,void DoSomething()\n{\t/*code*/\n} 也战胜了void DoSomething() {\n\t/*code*/\n} ;-)
  • Awww..RegEx 让我的眼睛流血了!!我将把它添加到我的武器库中:How to get rid of Syntax Errors Fast.
【解决方案2】:

StringBuilders 有一个 AppendFormat 函数,可以轻松创建 SQL 语句。

StringBuilder.AppendFormat Method

将通过处理包含零个或多个格式项的复合格式字符串返回的字符串附加到此实例。每个格式项都替换为相应对象参数的字符串表示形式。

注意:VBA 使用 StringBuilder.AppendFormat_4 处理格式字符串和值数组。

StringBuilder.AppendFormat_4 Format, Array()
Const Code = 10
Dim sb As Object
Dim SQL As String
Dim Report As Worksheet
Set Report = Excel.ActiveSheet

Set sb = CreateObject("System.Text.StringBuilder")
SQL = "INSERT INTO Purchases.DBO.Pos VALUES({0},'{1}',{2},'{3}','{4}','{5}','{6}',0,'{7}')"
sb.AppendFormat_4 SQL, Array(Range("H12").Value, _
                           Range("H30").Value, _
                           Excel.WorksheetFunction.Sum(Range("F16:F29")), _
                           Range("A34").Value, _
                           Range("F7").Value, _
                           Range("C12").Value, _
                           Range("A38").Value, _
                           Code)

SQL = sb.ToString

国际海事组织。大写 SQL 关键字使 SQL 语句更易于阅读。我还将在声明中添加一个字段列表。

INSERT INTO Purchases.DBO.Pos(FirstName,LastName) VALUES('Tin','Man')

【讨论】:

  • 糟透了 AppendFormat 方法不采用 params 最终参数;如果是这样,那么Array(...) 调用将是多余的。 +1 以更简洁的方式(认为重载支持是......嗯)将值连接到 SQL 字符串中,但是应该注意,将值连接到任何可执行的 SQL 语句中是错误和危险的;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-18
  • 2018-01-14
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
相关资源
最近更新 更多