【问题标题】:Cannot update the fields using ADODB from VBA无法使用 VBA 中的 ADODB 更新字段
【发布时间】:2018-06-16 17:04:01
【问题描述】:

我的目标是能够从已关闭的工作簿中读取和写入单元格值。我使用 ADODB 来获取所需的信息。 文件是由公司网站生成的,所以在使用实际文件之前我无法更改内容。该文件为 Excel 格式。单元格中没有公式,只有值。 我想从工作表中获取日期、字符串、整数,但遇到了一些限制。

我编写了示例代码来向您展示发生了什么:

Dim rsConn As ADODB.Connection
Dim rsData As ADODB.Recordset
Dim strFileName As String
Dim strFieldNames As String
Dim intValue As Integer

strFileName = "C:\Tests\Sample.xlsx" ' Fullpath to a workbook
'strFieldNames = "CInt([Proj_Year]) as [Proj_Year]"
'strFieldNames = "[Proj_Year]"
strFieldNames = "*"

Set rsConn = New ADODB.Connection
With rsConn
    .ConnectionString = "Data Source=" & strFileName & "; Extended Properties=""Excel 12.0; HDR=YES; "";"
    .Provider = "Microsoft.ACE.OLEDB.12.0"
    .Open
End With

Set rsData = New ADODB.Recordset
With rsData
    .Source = "SELECT " & strFieldNames & " FROM A2:AE500;" ' Sheetname not required
    .ActiveConnection = rsConn
    '.CursorType = adOpenKeyset     ' Tried this - didn't work
    '.CursorType = adOpenDynamic     ' Tried this - didn't work
    .CursorType = adOpenStatic
    .LockType = adLockOptimistic
    .Open
End With

With rsData
    .MoveFirst
    Do While Not .EOF
        ' Getting the value
        intValue = .Fields(0).Value

        ' Make some crazy modifications of the value
        intValue = intValue + 10

        ' Updating
        .Fields(0).Value = intValue   ' this is place where crash happens

        ' Move to the next record
        .MoveNext
    Loop
End With

rsData.Close
Set rsData = Nothing
rsConn.Close
Set rsConn = Nothing

这是示例工作簿的屏幕截图:

我尝试了几种方法:

  1. strFieldNames = "*" 我得到工作表中存在的所有列。但是驱动程序试图猜测字段类型,我不喜欢它,因为它的猜测是错误的。例如,单元格 I3 应该是字符串,但实际上它是 adDouble。所以阅读可能没问题,但我不能写回字符串。 我尝试使用IMEX=1,但没有帮助,尝试了MAXSCANROWS=1Readonly=0,但也没有运气。我不想触摸 Windows 注册表来修改猜测行。

  2. strFieldNames = "[Proj_Year]" 我只收到一列,但我遇到了与 1 中相同的限制。

  3. strFieldNames = "CInt([Proj_Year]) as [Proj_Year]" 我收到所需类型的所需列。但是当我运行我收到的代码时:

无法更新字段

输入代码:.Fields(0).Value = intValue

在上面的代码中,我一次读取和写入一条记录。我尝试使用 GetRows 读取所有数据(30 列,3000 行),然后将数据数组解析到我自己的类中。读取所有数据后,我会修改此数据并将其一次写回工作表中的一条记录。

我需要做什么才能让这段代码正常工作?

【问题讨论】:

  • SELECT " & strFieldNames & " FROM A2:AE500;?不应该是strSQL = "SELECT * from [sheet1$](stackoverflow.com/questions/24193112/…) 之类的吗? From 之后应该是工作表名称而不是范围(在任何给定工作表上),即使文件中只有一张工作表。此外,工作表名称后应跟$ 并用方括号括起来。 support.microsoft.com/en-us/help/278973/…
  • 添加工作表名称没有任何区别。
  • 我怀疑 ACE 驱动程序在 Excel 中使用静态游标更改记录集时存在问题。你可能想试试adOpenKeyset。就个人而言,我会使用第二个命令对象来发出 UPDATE 请求。
  • 如果我使用 adOpenKeysetstrFieldNames = "CInt([Proj_Year]) as [Proj_Year]" 程序将像以前一样运行。 UPDATE 呢?可以举几个例子吗?
  • 你需要 adOpenDynamic、adLockOptimistic

标签: excel vba field adodb


【解决方案1】:

我通常只使用Connection 对象的Execute 方法。

我的Before数据集(这是位于FilePath变量的文件中的数据):

Field1  Field2
   1    a
   2    b
   3    c
   4    d
   5    e

我的之后数据集:

Field1  Field2
   1    b
   2    b
   3    c
   4    d
   5    e

这是对我有用的代码。

Const FilePath As String = "C:\Users\MyComputerName\Desktop\Book1.xlsx"
Const ConnStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & FilePath & _
                          ";Extended Properties='Excel 12.0 Xml;HDR=YES';"

Public Sub testUpdate()
    Dim conn As ADODB.Connection: Set conn = New ADODB.Connection

    With conn
        .connectionstring = ConnStr
        .Open
        .Execute "Update [Sheet1$] set Field2='b' where Field1=1"
    End With

    If conn.State = adopenstate Then conn.Close: Set conn = Nothing
End Sub

其他一些观察结果

  • 这个strFileName = "C:\Tests\Sample.xlxs" 似乎不是一个有效的文件名。所以这可能会让你很伤心。
  • 数据集的第一行不包含标题,因此以工作表名称[Sheet1$] 为例,我相信默认为F1,F2,F3 代表字段名称(F1 = Field1)。如果您想要两全其美,请使用 Sheet AND Range 限定范围,如下所示:[Sheet1$A1:B10]。请参阅here 了解更多详情。

【讨论】:

  • 那我想知道更多关于:.Execute "Update [Sheet1$] set Field2='b' where Field1=1"的例子。
  • 如果我要修改以下单元格怎么办:B6="Open"、C12=123、E9=345、I17=Null 等。如果我有 300 行要修改怎么办。那个怎么样?关于观察。我写了一个假文件名,因为它只是一个例子。当我将第二行用作带有标题的行时,我不知道您为什么要说第一行。而且 sheetname 不是必需的,我在上面被问到同样的问题。
  • Xlxs 不是有效的文件扩展名是我的观点,如果有问题,请提及这一点。您正在编写更新记录的 SQL 语句,而不是更新范围对象中的单元格。您将更新所需的记录,通常通过在 where 子句中指定条件。查看 ADO 文档以获取有关 SO 的更多信息。
  • 据我所知,无法使用.Execute "Update ..."更新所有记录中的所有字段
  • 当然可以。只是不要在 where 子句中指定任何条件。如果全部适用,它将更新所有记录。
猜你喜欢
  • 1970-01-01
  • 2013-12-30
  • 2014-01-26
  • 2022-12-15
  • 2014-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多