如何仅在 VBA 逗号分隔列表中的字符串(而不是数字)上加上引号?

Posted

技术标签:

【中文标题】如何仅在 VBA 逗号分隔列表中的字符串(而不是数字)上加上引号?【英文标题】:How to put quotes only on strings (not on numbers) in a VBA comma-separated list? 【发布时间】:2018-03-23 21:06:28 【问题描述】:

上下文:我想在 PostgreSQL 数据库中导入 Excel 电子表格中的一些数据。 为此,我在 VBA 中建立了与数据库的连接,现在,我想对每一行执行一个 INSERT SQL 查询,例如

INSERT INTO mytable VALUES ('a','b',32,'d',17.2);

如果我们假设一个 pgSQL 表有 5 列,其中 2 列是数字。

使用数组和 VBA join 函数,我已经想出了如何获取 Excel 表格的给定行并将其转换为列表每个项目都被引用,例如

('a','b','32','d','17.2');

我可以从中轻松编写 SQL 查询。

引用所有项目的缺点是,在插入时,postgreSQL 服务器必须将已作为字符串传递的数值再次转换回数值。我担心这会影响性能,尤其是在需要处理 50000 多行的情况下。


问题:在这种情况下,我想找到一个解决方案,在将 VBA 数组转换为逗号分隔列表时仅在非数值上加上引号 不在列上使用 For 循环,这也会影响性能。

我当前用于将我的水平 Excel 范围转换为此类列表的 VBA 代码是:

myArray = Application.Transpose(Application.Transpose(myRange.Value))
myList = "('" & Join(myArray, "','") & "')"

(在上面的示例中,myArray 将是一个包含值 ("a","b",32,"d",17.2) 的 VBA 数组。

【问题讨论】:

加载数组时,请将' 放在文本的开头和结尾,而不是数字,然后只使用, 作为分隔符。 但是如果我这样做,字符串就不会被引用了,对吗? 请说明你是如何加载数组的。 @ScottCraner 我编辑了我的问题,向您展示如何将我的 Excel 水平范围转换为数组,然后转换为列表。 我要问为什么?,去掉引号对性能没有太大影响,也许可以节省 20% 的网络带宽,但服务器上的磁盘负载将是相同的. 【参考方案1】:

在 Join 之前需要几毫秒来转换数组。

Dim myarray As Variant, mylist As String, i As Long

myarray = Application.Transpose(Application.Transpose(Range("a1:f1").Value2))

For i = LBound(myarray) To UBound(myarray)
    If Not IsNumeric(myarray(i)) Then _
        myarray(i) = Chr(39) & Trim(myarray(i)) & Chr(39)
Next i

mylist = "(" & Join(myarray, Chr(44)) & ")"
Debug.Print mylist

【讨论】:

我不知道您的数值在简化的样本数据之外是什么样子的。更好的格式掩码可能是format(myarray(i), "general;'@'") 我们确定对每一行执行此操作的成本对性能的影响小于在 VBA 中转换为字符串,然后在插入数据库后转换回数字吗? 由于您正在处理内存中的数组,因此这里的计算时间成本是无限小的。我面前没有你的机器来进行时间测试。 那我试试这个方法。 我试过了,还是不行,数字周围还有引号。【参考方案2】:

使用带有缓冲区的循环来构建 SQL。您不会注意到性能上的差异。您还可以更好地控制类型,并且可以在字符串包含引号的情况下转义引号:

Sub Test()
  Dim data()
  data = [ "a",1 ; "b",2 ]
  Debug.Print ToSqlInsert("MyTable (Col1, Col2)", data)
End Sub


Public Function ToSqlInsert(target As String, data()) As String
  Dim sb() As String, n As Long, r As Long, c As Long
  ReDim sb(0 To UBound(data, 1) * UBound(data, 2) * 2)

  sb(n) = "INSERT INTO " & target & " VALUES ("
  n = n + 1

  For r = 1 To UBound(data, 1)
    For c = 1 To UBound(data, 2)
      If c > 1 Then sb(n - 1) = ","

      Select Case VBA.VarType(data(r, c))
        Case vbString:  sb(n) = "'" & Replace$(data(r, c), "'", "''") & "'"
        Case vbDate:    sb(n) = Int((data(r, c) - #1/1/1970#) * 86400) ' to epoche '
        Case vbEmpty:   sb(n) = "NULL"
        Case Else:      sb(n) = data(r, c)
      End Select

      n = n + 2
    Next

    sb(n - 1) = "),("
  Next

  sb(n - 1) = ");"
  ToSqlInsert = Join$(sb, Empty)
End Function

【讨论】:

以上是关于如何仅在 VBA 逗号分隔列表中的字符串(而不是数字)上加上引号?的主要内容,如果未能解决你的问题,请参考以下文章

用 .csv 文件中的 VBA 仅在 3 列中用分号替换逗号

如何将逗号分隔的字符串转换为 Python 中的列表?

如何从 SQL CE 中的表中构建逗号分隔列表?

从无组织的单词列表中组织一个用逗号分隔的单词列表(仅在可能的情况下提供提示)

如何在 SQL 中计算逗号分隔列表中的字符串项

在Solr 7.x中,如何仅使用逗号而不是空格或其他特殊字符进行标记?