【问题标题】:Handling a #Num! Error on importing Excel into Access处理#Num!将 Excel 导入 Access 时出错
【发布时间】:2013-05-13 13:54:47
【问题描述】:

我正在使用 ADO (Provider = "Microsoft.Jet.OLEDB.4.0") 将电子表格从 Excel 2003 导入到 Access 2003。但是,我在日期字段中有一些文本条目。正如您所料,这些值以#Num! 的形式出现。

我想做的是将有问题的字段包装在IIf(IsDate(FIELDNAME),FIELDNAME,#1/1/1900#) 之类的东西中。但是,这仍然会导致#Num!。测试IsDate()IsDate(CVar())IsError()IsError(CDat())VBAFunctionThatReturns0GivenAnyValue(FIELDNAME) 也是如此。

任何人都知道我可以使用的包装函数来完成这项工作吗?我或多或少已经束手无策了?

请注意:我对导入的数据没有任何控制权,因此我无法修复电子表格,就像我想的那样。我还想避免导入函数本身的特定黑客行为(例如,改用 TransferSpreadsheet)。目标是使用相同的方法来引入数据,只是忽略不起作用的位。

还应该指出,这里的非日期值被丢弃是合适的。理想情况下,我希望避免以文本形式导入,因为它会进一步导致各种其他错误。

编辑:添加了 2003 年的规定。我还应该指出,安装在环境中的 .Net 框架版本不包括(或似乎不包括)ACE.12.0 提供程序。

编辑 2:根据要求,这是我正在执行的 SQL 的(稍微清理过的)版本。请注意,这不是确切的查询,但在同一个电子表格上运行它会导致相同的问题:

SELECT 
    CStr(Nz([Notes], "")), 
    [ID],
    [Date]
INTO
    [;DATABASE=C:\DatabaseTarget.Mdb].[tblImport]
FROM
    [Excel 8.0;Database=C:\ExcelSheet.xls].[sheet1$]
WHERE
    [ID] IS NOT NULL

可以通过删除INTO 子句并查看[Date] 的值来发现问题。如果它们中的任何一个是#Num!,那么即使对所有Test1-5 在#Num!s 中执行以下结果,也可以说明问题。:

SELECT 
    CStr(Nz([Notes], '')), 
    [ID],
    CStr(Nz([Date],'')) As [Test1],
    IsError([Date]) As [Test2],
    IsDate([Date]) As [Test3],
    IsNull([Date]) As [Test4],
    IIf(True, 1, [Date]) As [Test5],
FROM
    [Excel 8.0;Database=C:\ExcelSheet.xls].[sheet1$]
WHERE
    [ID] IS NOT NULL

【问题讨论】:

    标签: excel ms-access ado ms-access-2003


    【解决方案1】:

    测试IsNull() 看起来应该可以工作。对于 Excel 数据...

    ID  ActivityDescription ActivityDate
    1   activity_1          2013-05-12
    2   activity_2          2013-05-13
    3   activity_3          2013-05-14
    4   activity_4          2013-05-15
    5   activity_5          2013-05-16
    6   activity_6          2013-05-17
    7   activity_7          2013-05-18
    8   activity_8          2013-05-19
    9   activity_9          2013-05-20
    10  activity_10         2013-05-21
    11  activity_11         2013-05-22
    12  activity_12         2013-05-23
    13  activity_13         oops!
    14  activity_14         2013-05-25
    15  activity_15         2013-05-26
    

    ...下面的 Access VBA 代码...

    Sub adoTest()
    Dim con As ADODB.Connection, rst As ADODB.Recordset
    Set con = New ADODB.Connection
    con.Open _
            "Provider=Microsoft.JET.OLEDB.4.0;" & _
            "Data Source=C:\Users\Public\xlsTest.xls;" & _
            "Extended Properties=""Excel 8.0;HDR=YES"";"
    Set rst = New ADODB.Recordset
    rst.Open "SELECT * FROM [Sheet1$]", con
    Do While Not rst.EOF
        Debug.Print _
                Format(rst("ID").Value, "00") & _
                "  " & _
                IIf(IsNull(rst("ActivityDate").Value), "<NULL>", rst("ActivityDate").Value)
        rst.MoveNext
    Loop
    rst.Close
    Set rst = Nothing
    con.Close
    Set con = Nothing
    End Sub
    

    ...产生这个:

    01  2013-05-12
    02  2013-05-13
    03  2013-05-14
    04  2013-05-15
    05  2013-05-16
    06  2013-05-17
    07  2013-05-18
    08  2013-05-19
    09  2013-05-20
    10  2013-05-21
    11  2013-05-22
    12  2013-05-23
    13  <NULL>
    14  2013-05-25
    15  2013-05-26
    

    这表明IsNull() 将“错误”日期值识别为Null 并替换为文本&lt;NULL&gt;

    根据上下文,Nz() 函数也可能有用。

    【讨论】:

    • 在 ACE 下可能工作得很好,但不幸的是,我坚持使用 JET,因为这是 Office 2003。抱歉,应该指定。也就是说,不确定我是否使用 IsNull() 进行测试或直接进入 Nz。这种情况有点奇怪,因为在这些字段中出现的一些文本数据确实得到了正确解释,但有些则没有。
    • @tobriand 我刚刚使用 Jet 测试了代码,得到了完全相同的结果。 (我已经更新了我的答案。)
    • 我会在几分钟内尝试一下,看看它是否能修复它。我是否认为不将数据包装在 IsNull 中也会产生#Num!错误?
    • @tobriand 不,如果我只是尝试 Debug.Print rst("ActivityDate").Value 那个条目是空的,而不是 #Num!。但是,如果我在 Excel 工作表中创建一个 Access 链接表,然后在数据表视图中打开该链接表,我确实会看到 #Num!
    • 我现在尝试了IsNull 方法,结果相同。我认为#Num!与其他错误类型相比,这是一种非常挑剔的错误类型。虽然找到了解决方法!通过 DAO 触发相同的查询并关闭错误,并且它无法引入的任何数据都将替换为 Null,这正是我想要的。
    【解决方案2】:

    #Num!错误似乎是由提供者在遇到大多数可用于查询中的错误处理的错误方法之前引发的。坚持使用 ADO 似乎很容易失败。

    但是,在 DAO 中测试我的查询(没有 INTO 子句只生成一个记录集)确实产生了有效的 sata,所以我认为 DAO 是否可以处理对 OLEDB 记录源的查询可能值得一看。原来可以!

    因此最终代码看起来像

    On Error Resume Next
    cmdFirstTry.Execute '' Includes fields which are pulled through as #Num! errors
    Select Case Err.Number
        Case 0
            On Error Goto ErrorHandler
        Case &H80040E14
            '' Failed in this manner; Try with DAO
            On Error Goto ErrorHandler
            CurrentDb.Execute strSQL
        Case Else
            lngErrNum = Err.Number
            strErrDesc = Err.Description
            On Error Goto ErrorHandler
            Err.Raise lngErrNum, , strErrDesc
    End Select
    

    根据我的需要,这可以完成工作,但我不会在几天内接受作为答案,以防真的有一种优雅的方法。

    【讨论】:

    • 你正在执行的SQL语句是什么?
    • 我添加了上述问题的精简版。 SQL 语句在 DAO 上执行良好,即使没有为 Provider 等指定更多细节。但是,我在 ADODB 上得到了可比较的结果,因此首先是这个问题!
    猜你喜欢
    • 2013-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多