Word VBA ADO与Excel文件的连接,单元格包含超过255个字符

时间:2014-04-22 11:02:05

标签: vba word-vba

我目前使用以下ADODB连接字符串从Excel工作簿中检索数据(oConnection已声明为新的ADODB.Connection,oRecordSet已声明为新的ADODB.RecordSet):

With oConnection
   .Provider = "Microsoft.ACE.OLEDB.12.0"
   .ConnectionString = "Data Source=C:\Myfile.xlsx;Mode=Read;Extended Properties=""Excel 12.0;HDR=Yes;"""
   .Open
   Set oRecordSet = .Execute(mySqlStatement)
End With

我将记录集添加到数组中,一切似乎都正常。但是,如果Excel工作表中的单元格包含超过255个字符,则文本将被截断/ 255以上的字符将被截断。

我用于连接Excel文件的整个功能如下:

Public Function RecordSet2Matrix(mSqlStatement As String) As Variant
    Dim oSettingsFolder  As String
    Dim oSettingsFile    As String
    Dim oConnection      As New ADODB.Connection
    Dim oRecordSet       As New ADODB.Recordset
    Dim oRecordArray     As Variant
    Dim oTempArray       As Variant
    Dim x                As Long
    Dim y                As Long
    Dim xUpper           As Long
    Dim yUpper           As Long

    'Error handling
    On Error GoTo errHandler

    'Get location and settings file
    oSettingsFolder = GetFolder(xFolderEnum.FolderOther)
    oSettingsFile = xSettingsFile
    oTempArray = Array()

    'Check if settings file exists
    If Len(Dir(oSettingsFolder & oSettingsFile)) = 0 Then
        RecordSet2Matrix = oTempArray
        Exit Function
    End If

    'Create connection to settings file
    With oConnection
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .ConnectionString = "Data Source=" & oSettingsFolder & oSettingsFile & _
                            ";Mode=Read;Extended Properties=""Excel 12.0;HDR=Yes;"""
        .Open
        Set oRecordSet = .Execute(mSqlStatement)
    End With

    'Read the settings file and add data to an array
    If oRecordSet.EOF Then
        oTempArray = Array()
    Else
        oRecordArray = oRecordSet.GetRows

        xUpper = UBound(oRecordArray, 2)
        yUpper = UBound(oRecordArray, 1)

        'Resize array to fit all records
        ReDim oTempArray(xUpper, yUpper)
        For x = 0 To xUpper
            For y = 0 To yUpper
                oTempArray(x, y) = oRecordArray(y, x)
            Next y
        Next x
    End If

    'Close connection to file
    If CBool(oRecordSet.State And adStateOpen) Then
        oRecordSet.Close
    End If

    'Return record set
    RecordSet2Matrix = oTempArray

errHandler:
    If Err.Number <> 0 Then
        ShowErrorMessage Err.Number, Err.Description, "modADO.RecordSet2Matrix"
        Set oRecordSet = Nothing
        RecordSet2Matrix = oTempArray
    End If

cleanUp:
    Set oRecordSet = Nothing
    Set oTempArray = Nothing
End Function

然后我运行实际的SELECT语句来从Excel获取数据:

Public Function GetFirmDetails(mFirmName As String) As xIniDataRecord
    Dim oSqlStatement  As String
    Dim oDataArray     As Variant
    Dim oReturnRec     As xIniDataRecord

    'Error handling
    On Error GoTo errHandler

    'SQL query for retrieving office details
    oSqlStatement = "SELECT [FirmDisplayName], [FirmPrintName], [FirmInfoA]" & _
                    "FROM   [Firms$] " & _
                    "WHERE  [FirmDisplayName] = '" & mFirmName & "';"

    'Return query to array
    oDataArray = RecordSet2Matrix(oSqlStatement)

    'Exit function if array is empty
    If UBound(oDataArray) < 0 Then
        GetFirmDetails = oReturnRec
        Exit Function
    End If

    'Return array data to return record
    With oReturnRec
        .FirmDisplayName = oDataArray(0, 0)
        .FirmName = oDataArray(0, 1)
        .FirmInfoA = oDataArray(0, 2)
    End With

    'Return data record
    GetFirmDetails = oReturnRec

errHandler:
    If Err.Number <> 0 Then
        ShowErrorMessage Err.Number, Err.Description, "modADO.GetFirmDetails"
        GetFirmDetails = oReturnRec
    End If

cleanUp:
    Set oDataArray = Nothing
End Function

我一直在研究与我类似的其他问题,但并没有真正找到解决方案。

有人知道如何避免255个字符的限制吗?

NB!我正在运行Excel 2007。

1 个答案:

答案 0 :(得分:2)

从这里的测试中,我相信你遇到了here所描述的(众所周知的)问题(虽然它谈到了ODBC,但OLEDB中的问题却大致相同)。问题是OLE提供程序想要为工作表中的每个列分配特定的数据类型。然后,它将列中没有该格式的任何单元格转换为指定的格式。

默认情况下,它使用每列的前8行来确定格式。对于仅包含字符串的列,如果列中的前8个单元格包含&lt; 255(或&lt; = 255,无法记住)字符的字符串,则提供程序将使用&gt;截断任何单元格。或&gt; = 255。如果前8个单元中的一个单元格> 255,则提供程序不会截断任何行。

这个问题当然是它看起来完全是任意的 - 有一天你有一个工作表,前8行有一个255个字符的单元格,一切正常。然后修改该数据,系统出错。

修改此行为实际上并非完全不重要。你可以设置&#34; TypeGuessRows&#34;注册表中的值要更高,或将其设置为0,在这种情况下理论上它将检查所有行。

但这会影响使用Jet / ACE提供程序从Excel获取数据的所有其他内容。将值设置为0可能意味着检查需要很长时间,并且据我所知,检查仅应用于前16K(或可能是32K或64K)行,即使在最近版本的Excel中行数也是如此理论上可以更高。

为避免修改其他所有内容的行为,您可以在注册表的私有区域中创建自己的一组Jet / ACE参数,并指向连接字符串中的那些参数。

更简单的替代方法可能是接受在数据开头总是有一个虚拟行,在需要它们的列中长度超过255个字符。就个人而言,这可能就是我要采取的路线。

否则,只要在您的情况下将TypeGuessRows设置为0并且允许您修改注册表是有意义的,那么这可能是您的选择。例如,如果你把值放在这里(你可能还需要修改一些名为&#34; ImportMixedTypes&#34;:

HKEY_LOCAL_MACHINE\SOFTWARE\sample\v1.0\Engines\Excel\TypeGuessRows
HKEY_LOCAL_MACHINE\SOFTWARE\sample\v1.0\Engines\Excel\ImportMixedTypes

然后你需要在你的连接字符串中使用它:

Jet OLE DB:Registry Path="SOFTWARE\sample\v1.0"

您可以导入的一组合适的注册表项如下所示:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\sample]
[HKEY_LOCAL_MACHINE\SOFTWARE\sample\v1.0]
[HKEY_LOCAL_MACHINE\SOFTWARE\sample\v1.0\Engines]

[HKEY_LOCAL_MACHINE\SOFTWARE\sample\v1.0\Engines\Excel]
"ImportMixedTypes"="Text"
"TypeGuessRows"=dword:00000000

您可以使用该方法,但设置

"TypeGuessRows"=dword:00000001

对于您有一个虚拟行的情况,只是为了确保将所有类型分配为该行中指定的类型。但我认为在大多数情况下仅添加行可能就足够了。